Пример #1
0
/* Slightly specialized version of buffer_write designed to maximize
 * chances of the driver consolidating successive writes into a single
 * upload.
 *
 * dirty_size may be slightly greater than size to cope with
 * alignment.  We don't want to leave holes between succesively mapped
 * regions as that may prevent the driver from consolidating uploads.
 * 
 * Note that the 'data' pointer has probably come from the application
 * and we cannot read even a byte past its end without risking
 * segfaults, or at least complaints from valgrind..
 */
static INLINE enum pipe_error
my_buffer_write(struct pipe_context *pipe,
                struct pipe_resource *buf,
                unsigned offset, unsigned size, unsigned dirty_size,
                const void *data)
{
   struct pipe_transfer *transfer = NULL;
   uint8_t *map;
   
   assert(offset < buf->width0);
   assert(offset + size <= buf->width0);
   assert(dirty_size >= size);
   assert(size);

   map = pipe_buffer_map_range(pipe, buf, offset, dirty_size,
                               PIPE_TRANSFER_WRITE |
                               PIPE_TRANSFER_FLUSH_EXPLICIT |
                               PIPE_TRANSFER_DISCARD |
                               PIPE_TRANSFER_UNSYNCHRONIZED,
			       &transfer);
   if (map == NULL) 
      return PIPE_ERROR_OUT_OF_MEMORY;

   memcpy(map + offset, data, size);
   pipe_buffer_flush_mapped_range(pipe, transfer, offset, dirty_size);
   pipe_buffer_unmap(pipe, buf, transfer);

   return PIPE_OK;
}
Пример #2
0
static INLINE enum pipe_error
my_buffer_write(struct pipe_screen *screen,
                struct pipe_buffer *buf,
                unsigned offset, unsigned size, unsigned dirty_size,
                const void *data)
{
    uint8_t *map;

    assert(offset < buf->size);
    assert(offset + size <= buf->size);
    assert(dirty_size >= size);
    assert(size);

    map = pipe_buffer_map_range(screen, buf, offset, size,
    PIPE_BUFFER_USAGE_CPU_WRITE |
    PIPE_BUFFER_USAGE_FLUSH_EXPLICIT |
    PIPE_BUFFER_USAGE_DISCARD |
    PIPE_BUFFER_USAGE_UNSYNCHRONIZED);
    if (map == NULL)
        return PIPE_ERROR_OUT_OF_MEMORY;

    memcpy(map + offset, data, size);
    pipe_buffer_flush_mapped_range(screen, buf, offset, dirty_size);
    pipe_buffer_unmap(screen, buf);

    return PIPE_OK;
}
Пример #3
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 r600_resource_global* buffer =
		(struct r600_resource_global*)resource;

	COMPUTE_DBG(rctx->screen, "* r600_compute_global_transfer_map()\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);
	COMPUTE_DBG(rctx->screen, "Buffer id = %u offset = "
		"%u (box.x)\n", buffer->chunk->id, box->x);


	compute_memory_finalize_pending(pool, ctx_);

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

	///TODO: do it better, mapping is not possible if the pool is too big
	return pipe_buffer_map_range(ctx_, (struct pipe_resource*)buffer->chunk->pool->bo,
			box->x + (buffer->chunk->start_in_dw * 4),
			box->width, usage, ptransfer);
}
Пример #4
0
static void
fill_grid_size(struct pipe_context *context,
               const struct pipe_grid_info *info,
               uint32_t grid_size[3])
{
   struct pipe_transfer *transfer;
   uint32_t *params;
   if (!info->indirect) {
      grid_size[0] = info->grid[0];
      grid_size[1] = info->grid[1];
      grid_size[2] = info->grid[2];
      return;
   }
   params = pipe_buffer_map_range(context, info->indirect,
                                  info->indirect_offset,
                                  3 * sizeof(uint32_t),
                                  PIPE_TRANSFER_READ,
                                  &transfer);

   if (!transfer)
      return;

   grid_size[0] = params[0];
   grid_size[1] = params[1];
   grid_size[2] = params[2];
   pipe_buffer_unmap(context, transfer);
}
Пример #5
0
/**
 * Called via glMapBufferRange().
 */
static void *
st_bufferobj_map_range(struct gl_context *ctx,
                       GLintptr offset, GLsizeiptr length, GLbitfield access,
                       struct gl_buffer_object *obj)
{
   struct pipe_context *pipe = st_context(ctx)->pipe;
   struct st_buffer_object *st_obj = st_buffer_object(obj);
   enum pipe_transfer_usage flags = 0x0;

   if (access & GL_MAP_WRITE_BIT)
      flags |= PIPE_TRANSFER_WRITE;

   if (access & GL_MAP_READ_BIT)
      flags |= PIPE_TRANSFER_READ;

   if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
      flags |= PIPE_TRANSFER_FLUSH_EXPLICIT;

   if (access & GL_MAP_INVALIDATE_BUFFER_BIT) {
      flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
   }
   else if (access & GL_MAP_INVALIDATE_RANGE_BIT) {
      if (offset == 0 && length == obj->Size)
         flags |= PIPE_TRANSFER_DISCARD_WHOLE_RESOURCE;
      else
         flags |= PIPE_TRANSFER_DISCARD_RANGE;
   }
   
   if (access & GL_MAP_UNSYNCHRONIZED_BIT)
      flags |= PIPE_TRANSFER_UNSYNCHRONIZED;

   /* ... other flags ...
    */

   if (access & MESA_MAP_NOWAIT_BIT)
      flags |= PIPE_TRANSFER_DONTBLOCK;

   assert(offset >= 0);
   assert(length >= 0);
   assert(offset < obj->Size);
   assert(offset + length <= obj->Size);

   obj->Pointer = pipe_buffer_map_range(pipe,
                                        st_obj->buffer,
                                        offset, length,
                                        flags,
                                        &st_obj->transfer);
   if (obj->Pointer) {
      obj->Pointer = (ubyte *) obj->Pointer + offset;
   }

   if (obj->Pointer) {
      obj->Offset = offset;
      obj->Length = length;
      obj->AccessFlags = access;
   }

   return obj->Pointer;
}
Пример #6
0
enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
                                unsigned min_out_offset,
                                unsigned size,
                                unsigned *out_offset,
                                struct pipe_resource **outbuf,
                                void **ptr )
{
   unsigned alloc_size = align( size, upload->alignment );
   unsigned alloc_offset = align(min_out_offset, upload->alignment);
   unsigned offset;

   /* Init these return values here in case we fail below to make
    * sure the caller doesn't get garbage values.
    */
   *out_offset = ~0;
   pipe_resource_reference(outbuf, NULL);
   *ptr = NULL;

   /* Make sure we have enough space in the upload buffer
    * for the sub-allocation. */
   if (MAX2(upload->offset, alloc_offset) + alloc_size > upload->size) {
      enum pipe_error ret = u_upload_alloc_buffer(upload,
                                                  alloc_offset + alloc_size);
      if (ret != PIPE_OK)
         return ret;
   }

   offset = MAX2(upload->offset, alloc_offset);

   if (!upload->map) {
      upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
					  offset, upload->size - offset,
					  PIPE_TRANSFER_WRITE |
					  PIPE_TRANSFER_FLUSH_EXPLICIT |
					  PIPE_TRANSFER_UNSYNCHRONIZED,
					  &upload->transfer);
      if (!upload->map) {
         upload->transfer = NULL;
         return PIPE_ERROR_OUT_OF_MEMORY;
      }

      upload->map -= offset;
   }

   assert(offset < upload->buffer->width0);
   assert(offset + size <= upload->buffer->width0);
   assert(size);

   /* Emit the return values: */
   *ptr = upload->map + offset;
   pipe_resource_reference( outbuf, upload->buffer );
   *out_offset = offset;

   upload->offset = offset + alloc_size;
   return PIPE_OK;
}
Пример #7
0
static void *
nv30_render_map_vertices(struct vbuf_render *render)
{
   struct nv30_render *r = nv30_render(render);
   char *map = pipe_buffer_map_range(
         &r->nv30->base.pipe, r->buffer,
         r->offset, r->length,
         PIPE_TRANSFER_WRITE |
         PIPE_TRANSFER_DISCARD_RANGE,
         &r->transfer);
   assert(map);
   return map;
}
Пример #8
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 r600_resource_global* buffer =
		(struct r600_resource_global*)resource;

	struct compute_memory_item *item = buffer->chunk;
	struct pipe_resource *dst = NULL;
	unsigned offset = box->x;

	if (is_item_in_pool(item)) {
		compute_memory_demote_item(pool, item, ctx_);
	}
	else {
		if (item->real_buffer == NULL) {
			item->real_buffer =
					r600_compute_buffer_alloc_vram(pool->screen, item->size_in_dw * 4);
		}
	}

	dst = (struct pipe_resource*)item->real_buffer;

	if (usage & PIPE_TRANSFER_READ)
		buffer->chunk->status |= ITEM_MAPPED_FOR_READING;

	COMPUTE_DBG(rctx->screen, "* r600_compute_global_transfer_map()\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);
	COMPUTE_DBG(rctx->screen, "Buffer id = %"PRIi64" offset = "
		"%u (box.x)\n", item->id, box->x);


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

	///TODO: do it better, mapping is not possible if the pool is too big
	return pipe_buffer_map_range(ctx_, dst,
			offset, box->width, usage, ptransfer);
}
Пример #9
0
enum pipe_error u_upload_alloc( struct u_upload_mgr *upload,
                                unsigned min_out_offset,
                                unsigned size,
                                unsigned *out_offset,
                                struct pipe_resource **outbuf,
                                boolean *flushed,
                                void **ptr )
{
   unsigned alloc_size = align( size, upload->alignment );
   unsigned alloc_offset = align(min_out_offset, upload->alignment);
   unsigned offset;

   /* Make sure we have enough space in the upload buffer
    * for the sub-allocation. */
   if (MAX2(upload->offset, alloc_offset) + alloc_size > upload->size) {
      enum pipe_error ret = u_upload_alloc_buffer(upload,
                                                  alloc_offset + alloc_size);
      if (ret)
         return ret;

      *flushed = TRUE;
   } else {
      *flushed = FALSE;
   }

   offset = MAX2(upload->offset, alloc_offset);

   if (!upload->map) {
      upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
					  offset, upload->size - offset,
					  PIPE_TRANSFER_WRITE |
					  PIPE_TRANSFER_FLUSH_EXPLICIT |
					  PIPE_TRANSFER_UNSYNCHRONIZED,
					  &upload->transfer);
   }

   assert(offset < upload->buffer->width0);
   assert(offset + size <= upload->buffer->width0);
   assert(size);

   /* Emit the return values: */
   *ptr = upload->map + offset;
   pipe_resource_reference( outbuf, upload->buffer );
   *out_offset = offset;

   upload->offset = offset + alloc_size;
   return PIPE_OK;
}
Пример #10
0
static void
u_upload_alloc_buffer(struct u_upload_mgr *upload, unsigned min_size)
{
   struct pipe_screen *screen = upload->pipe->screen;
   struct pipe_resource buffer;
   unsigned size;

   /* Release the old buffer, if present:
    */
   u_upload_release_buffer(upload);

   /* Allocate a new one:
    */
   size = align(MAX2(upload->default_size, min_size), 4096);

   memset(&buffer, 0, sizeof buffer);
   buffer.target = PIPE_BUFFER;
   buffer.format = PIPE_FORMAT_R8_UNORM; /* want TYPELESS or similar */
   buffer.bind = upload->bind;
   buffer.usage = upload->usage;
   buffer.flags = upload->flags;
   buffer.width0 = size;
   buffer.height0 = 1;
   buffer.depth0 = 1;
   buffer.array_size = 1;

   if (upload->map_persistent) {
      buffer.flags |= PIPE_RESOURCE_FLAG_MAP_PERSISTENT |
                      PIPE_RESOURCE_FLAG_MAP_COHERENT;
   }

   upload->buffer = screen->resource_create(screen, &buffer);
   if (upload->buffer == NULL)
      return;

   /* Map the new buffer. */
   upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
                                       0, size, upload->map_flags,
                                       &upload->transfer);
   if (upload->map == NULL) {
      upload->transfer = NULL;
      pipe_resource_reference(&upload->buffer, NULL);
      return;
   }

   upload->offset = 0;
}
Пример #11
0
/* As above, but upload the full contents of a buffer.  Useful for
 * uploading user buffers, avoids generating an explosion of GPU
 * buffers if you have an app that does lots of small vertex buffer
 * renders or DrawElements calls.
 */
enum pipe_error u_upload_buffer( struct u_upload_mgr *upload,
                                 unsigned min_out_offset,
                                 unsigned offset,
                                 unsigned size,
                                 struct pipe_resource *inbuf,
                                 unsigned *out_offset,
                                 struct pipe_resource **outbuf,
                                 boolean *flushed )
{
   enum pipe_error ret = PIPE_OK;
   struct pipe_transfer *transfer = NULL;
   const char *map = NULL;

   map = (const char *)pipe_buffer_map_range(upload->pipe,
                                             inbuf,
                                             offset, size,
                                             PIPE_TRANSFER_READ,
                                             &transfer);

   if (map == NULL) {
      ret = PIPE_ERROR_OUT_OF_MEMORY;
      goto done;
   }

   if (0)
      debug_printf("upload ptr %p ofs %d sz %d\n", map, offset, size);

   ret = u_upload_data( upload,
                        min_out_offset,
                        size,
                        map + offset,
                        out_offset,
                        outbuf, flushed );

done:
   if (map)
      pipe_buffer_unmap( upload->pipe, transfer );

   return ret;
}
Пример #12
0
static enum pipe_error 
u_upload_alloc_buffer( struct u_upload_mgr *upload,
                       unsigned min_size )
{
   unsigned size;

   /* Release the old buffer, if present:
    */
   u_upload_flush( upload );

   /* Allocate a new one: 
    */
   size = align(MAX2(upload->default_size, min_size), 4096);

   upload->buffer = pipe_buffer_create( upload->pipe->screen,
                                        upload->bind,
                                        PIPE_USAGE_STREAM,
                                        size );
   if (upload->buffer == NULL) {
      return PIPE_ERROR_OUT_OF_MEMORY;
   }

   /* Map the new buffer. */
   upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
                                       0, size,
                                       PIPE_TRANSFER_WRITE |
                                       PIPE_TRANSFER_FLUSH_EXPLICIT,
                                       &upload->transfer);
   if (upload->map == NULL) {
      upload->size = 0;
      pipe_resource_reference(&upload->buffer, NULL);
      return PIPE_ERROR_OUT_OF_MEMORY;
   }

   upload->size = size;

   upload->offset = 0;
   return PIPE_OK;
}
Пример #13
0
/**
 * Called via glMapBufferRange().
 */
static void *
st_bufferobj_map_range(GLcontext *ctx, GLenum target, 
                       GLintptr offset, GLsizeiptr length, GLbitfield access,
                       struct gl_buffer_object *obj)
{
   struct pipe_context *pipe = st_context(ctx)->pipe;
   struct st_buffer_object *st_obj = st_buffer_object(obj);
   GLuint flags = 0;
   char *map;

   if (access & GL_MAP_WRITE_BIT)
      flags |= PIPE_BUFFER_USAGE_CPU_WRITE;

   if (access & GL_MAP_READ_BIT)
      flags |= PIPE_BUFFER_USAGE_CPU_READ;

   if (access & GL_MAP_FLUSH_EXPLICIT_BIT)
      flags |= PIPE_BUFFER_USAGE_FLUSH_EXPLICIT;
   
   /* ... other flags ...
    */

   if (access & MESA_MAP_NOWAIT_BIT)
      flags |= PIPE_BUFFER_USAGE_DONTBLOCK;

   assert(offset >= 0);
   assert(length >= 0);
   assert(offset < obj->Size);
   assert(offset + length <= obj->Size);

   map = obj->Pointer = pipe_buffer_map_range(pipe->screen, st_obj->buffer, offset, length, flags);
   if(obj->Pointer) {
      obj->Offset = offset;
      obj->Length = length;
      map += offset;
   }
   
   return map;
}
Пример #14
0
/* This extracts the draw arguments from the info_in->indirect resource,
 * puts them into a new instance of pipe_draw_info, and calls draw_vbo on it.
 */
void
util_draw_indirect(struct pipe_context *pipe,
                   const struct pipe_draw_info *info_in)
{
   struct pipe_draw_info info;
   struct pipe_transfer *transfer;
   uint32_t *params;
   const unsigned num_params = info_in->indexed ? 5 : 4;

   assert(info_in->indirect);
   assert(!info_in->count_from_stream_output);

   memcpy(&info, info_in, sizeof(info));

   params = (uint32_t *)
      pipe_buffer_map_range(pipe,
                            info_in->indirect,
                            info_in->indirect_offset,
                            num_params * sizeof(uint32_t),
                            PIPE_TRANSFER_READ,
                            &transfer);
   if (!transfer) {
      debug_printf("%s: failed to map indirect buffer\n", __FUNCTION__);
      return;
   }

   info.count = params[0];
   info.instance_count = params[1];
   info.start = params[2];
   info.index_bias = info_in->indexed ? params[3] : 0;
   info.start_instance = info_in->indexed ? params[4] : params[3];
   info.indirect = NULL;

   pipe_buffer_unmap(pipe, transfer);

   pipe->draw_vbo(pipe, &info);
}
Пример #15
0
static int update_zero_stride( struct svga_context *svga,
                               unsigned dirty )
{
   unsigned i;

   svga->curr.zero_stride_vertex_elements = 0;
   svga->curr.num_zero_stride_vertex_elements = 0;

   for (i = 0; i < svga->curr.num_vertex_elements; i++) {
      const struct pipe_vertex_element *vel = &svga->curr.ve[i];
      const struct pipe_vertex_buffer *vbuffer = &svga->curr.vb[
         vel->vertex_buffer_index];
      if (vbuffer->stride == 0) {
         unsigned const_idx =
            svga->curr.num_zero_stride_vertex_elements;
         struct translate *translate;
         struct translate_key key;
         void *mapped_buffer;

         svga->curr.zero_stride_vertex_elements |= (1 << i);
         ++svga->curr.num_zero_stride_vertex_elements;

         key.output_stride = 4 * sizeof(float);
         key.nr_elements = 1;
         key.element[0].type = TRANSLATE_ELEMENT_NORMAL;
         key.element[0].input_format = vel->src_format;
         key.element[0].output_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
         key.element[0].input_buffer = vel->vertex_buffer_index;
         key.element[0].input_offset = vel->src_offset;
         key.element[0].instance_divisor = vel->instance_divisor;
         key.element[0].output_offset = const_idx * 4 * sizeof(float);

         translate_key_sanitize(&key);
         /* translate_generic_create is technically private but
          * we don't want to code-generate, just want generic
          * translation */
         translate = translate_generic_create(&key);

         assert(vel->src_offset == 0);
         
         mapped_buffer = pipe_buffer_map_range(svga->pipe.screen, 
                                               vbuffer->buffer,
                                               vel->src_offset,
                                               util_format_get_blocksize(vel->src_format),
                                               PIPE_BUFFER_USAGE_CPU_READ);
         translate->set_buffer(translate, vel->vertex_buffer_index,
                               mapped_buffer,
                               vbuffer->stride);
         translate->run(translate, 0, 1, 0,
                        svga->curr.zero_stride_constants);

         pipe_buffer_unmap(svga->pipe.screen,
                           vbuffer->buffer);
         translate->release(translate);
      }
   }

   if (svga->curr.num_zero_stride_vertex_elements)
      svga->dirty |= SVGA_NEW_ZERO_STRIDE;

   return 0;
}
Пример #16
0
void
u_upload_alloc(struct u_upload_mgr *upload,
               unsigned min_out_offset,
               unsigned size,
               unsigned alignment,
               unsigned *out_offset,
               struct pipe_resource **outbuf,
               void **ptr)
{
   unsigned buffer_size = upload->buffer ? upload->buffer->width0 : 0;
   unsigned offset;

   min_out_offset = align(min_out_offset, alignment);

   offset = align(upload->offset, alignment);
   offset = MAX2(offset, min_out_offset);

   /* Make sure we have enough space in the upload buffer
    * for the sub-allocation.
    */
   if (unlikely(!upload->buffer || offset + size > buffer_size)) {
      u_upload_alloc_buffer(upload, min_out_offset + size);

      if (unlikely(!upload->buffer)) {
         *out_offset = ~0;
         pipe_resource_reference(outbuf, NULL);
         *ptr = NULL;
         return;
      }

      offset = min_out_offset;
      buffer_size = upload->buffer->width0;
   }

   if (unlikely(!upload->map)) {
      upload->map = pipe_buffer_map_range(upload->pipe, upload->buffer,
                                          offset,
                                          buffer_size - offset,
                                          upload->map_flags,
                                          &upload->transfer);
      if (unlikely(!upload->map)) {
         upload->transfer = NULL;
         *out_offset = ~0;
         pipe_resource_reference(outbuf, NULL);
         *ptr = NULL;
         return;
      }

      upload->map -= offset;
   }

   assert(offset < buffer_size);
   assert(offset + size <= buffer_size);
   assert(size);

   /* Emit the return values: */
   *ptr = upload->map + offset;
   pipe_resource_reference(outbuf, upload->buffer);
   *out_offset = offset;

   upload->offset = offset + size;
}
Пример #17
0
void u_vbuf_draw_vbo(struct u_vbuf *mgr, const struct pipe_draw_info *info)
{
   struct pipe_context *pipe = mgr->pipe;
   int start_vertex, min_index;
   unsigned num_vertices;
   boolean unroll_indices = FALSE;
   uint32_t used_vb_mask = mgr->ve->used_vb_mask;
   uint32_t user_vb_mask = mgr->user_vb_mask & used_vb_mask;
   uint32_t incompatible_vb_mask = mgr->incompatible_vb_mask & used_vb_mask;
   struct pipe_draw_info new_info;

   /* Normal draw. No fallback and no user buffers. */
   if (!incompatible_vb_mask &&
       !mgr->ve->incompatible_elem_mask &&
       !user_vb_mask) {

      /* Set vertex buffers if needed. */
      if (mgr->dirty_real_vb_mask & used_vb_mask) {
         u_vbuf_set_driver_vertex_buffers(mgr);
      }

      pipe->draw_vbo(pipe, info);
      return;
   }

   new_info = *info;

   /* Fallback. We need to know all the parameters. */
   if (new_info.indirect) {
      struct pipe_transfer *transfer = NULL;
      int *data;

      if (new_info.indexed) {
         data = pipe_buffer_map_range(pipe, new_info.indirect,
                                      new_info.indirect_offset, 20,
                                      PIPE_TRANSFER_READ, &transfer);
         new_info.index_bias = data[3];
         new_info.start_instance = data[4];
      }
      else {
         data = pipe_buffer_map_range(pipe, new_info.indirect,
                                      new_info.indirect_offset, 16,
                                      PIPE_TRANSFER_READ, &transfer);
         new_info.start_instance = data[3];
      }

      new_info.count = data[0];
      new_info.instance_count = data[1];
      new_info.start = data[2];
      pipe_buffer_unmap(pipe, transfer);
      new_info.indirect = NULL;
   }

   if (new_info.indexed) {
      /* See if anything needs to be done for per-vertex attribs. */
      if (u_vbuf_need_minmax_index(mgr)) {
         int max_index;

         if (new_info.max_index != ~0u) {
            min_index = new_info.min_index;
            max_index = new_info.max_index;
         } else {
            u_vbuf_get_minmax_index(mgr->pipe, &mgr->index_buffer,
                                    new_info.primitive_restart,
                                    new_info.restart_index, new_info.start,
                                    new_info.count, &min_index, &max_index);
         }

         assert(min_index <= max_index);

         start_vertex = min_index + new_info.index_bias;
         num_vertices = max_index + 1 - min_index;

         /* Primitive restart doesn't work when unrolling indices.
          * We would have to break this drawing operation into several ones. */
         /* Use some heuristic to see if unrolling indices improves
          * performance. */
         if (!new_info.primitive_restart &&
             num_vertices > new_info.count*2 &&
             num_vertices - new_info.count > 32 &&
             !u_vbuf_mapping_vertex_buffer_blocks(mgr)) {
            unroll_indices = TRUE;
            user_vb_mask &= ~(mgr->nonzero_stride_vb_mask &
                              mgr->ve->noninstance_vb_mask_any);
         }
      } else {
         /* Nothing to do for per-vertex attribs. */
         start_vertex = 0;
         num_vertices = 0;
         min_index = 0;
      }
   } else {
      start_vertex = new_info.start;
      num_vertices = new_info.count;
      min_index = 0;
   }

   /* Translate vertices with non-native layouts or formats. */
   if (unroll_indices ||
       incompatible_vb_mask ||
       mgr->ve->incompatible_elem_mask) {
      if (!u_vbuf_translate_begin(mgr, start_vertex, num_vertices,
                                  new_info.start_instance,
                                  new_info.instance_count, new_info.start,
                                  new_info.count, min_index, unroll_indices)) {
         debug_warn_once("u_vbuf_translate_begin() failed");
         return;
      }

      if (unroll_indices) {
         new_info.indexed = FALSE;
         new_info.index_bias = 0;
         new_info.min_index = 0;
         new_info.max_index = new_info.count - 1;
         new_info.start = 0;
      }

      user_vb_mask &= ~(incompatible_vb_mask |
                        mgr->ve->incompatible_vb_mask_all);
   }

   /* Upload user buffers. */
   if (user_vb_mask) {
      if (u_vbuf_upload_buffers(mgr, start_vertex, num_vertices,
                                new_info.start_instance,
                                new_info.instance_count) != PIPE_OK) {
         debug_warn_once("u_vbuf_upload_buffers() failed");
         return;
      }

      mgr->dirty_real_vb_mask |= user_vb_mask;
   }

   /*
   if (unroll_indices) {
      printf("unrolling indices: start_vertex = %i, num_vertices = %i\n",
             start_vertex, num_vertices);
      util_dump_draw_info(stdout, info);
      printf("\n");
   }

   unsigned i;
   for (i = 0; i < mgr->nr_vertex_buffers; i++) {
      printf("input %i: ", i);
      util_dump_vertex_buffer(stdout, mgr->vertex_buffer+i);
      printf("\n");
   }
   for (i = 0; i < mgr->nr_real_vertex_buffers; i++) {
      printf("real %i: ", i);
      util_dump_vertex_buffer(stdout, mgr->real_vertex_buffer+i);
      printf("\n");
   }
   */

   u_upload_unmap(pipe->stream_uploader);
   u_vbuf_set_driver_vertex_buffers(mgr);

   pipe->draw_vbo(pipe, &new_info);

   if (mgr->using_translate) {
      u_vbuf_translate_end(mgr);
   }
}
Пример #18
0
static void u_vbuf_get_minmax_index(struct pipe_context *pipe,
                                    struct pipe_index_buffer *ib,
                                    boolean primitive_restart,
                                    unsigned restart_index,
                                    unsigned start, unsigned count,
                                    int *out_min_index,
                                    int *out_max_index)
{
   struct pipe_transfer *transfer = NULL;
   const void *indices;
   unsigned i;

   if (ib->user_buffer) {
      indices = (uint8_t*)ib->user_buffer +
                ib->offset + start * ib->index_size;
   } else {
      indices = pipe_buffer_map_range(pipe, ib->buffer,
                                      ib->offset + start * ib->index_size,
                                      count * ib->index_size,
                                      PIPE_TRANSFER_READ, &transfer);
   }

   switch (ib->index_size) {
   case 4: {
      const unsigned *ui_indices = (const unsigned*)indices;
      unsigned max_ui = 0;
      unsigned min_ui = ~0U;
      if (primitive_restart) {
         for (i = 0; i < count; i++) {
            if (ui_indices[i] != restart_index) {
               if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
               if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (ui_indices[i] > max_ui) max_ui = ui_indices[i];
            if (ui_indices[i] < min_ui) min_ui = ui_indices[i];
         }
      }
      *out_min_index = min_ui;
      *out_max_index = max_ui;
      break;
   }
   case 2: {
      const unsigned short *us_indices = (const unsigned short*)indices;
      unsigned max_us = 0;
      unsigned min_us = ~0U;
      if (primitive_restart) {
         for (i = 0; i < count; i++) {
            if (us_indices[i] != restart_index) {
               if (us_indices[i] > max_us) max_us = us_indices[i];
               if (us_indices[i] < min_us) min_us = us_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (us_indices[i] > max_us) max_us = us_indices[i];
            if (us_indices[i] < min_us) min_us = us_indices[i];
         }
      }
      *out_min_index = min_us;
      *out_max_index = max_us;
      break;
   }
   case 1: {
      const unsigned char *ub_indices = (const unsigned char*)indices;
      unsigned max_ub = 0;
      unsigned min_ub = ~0U;
      if (primitive_restart) {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] != restart_index) {
               if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
               if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
            }
         }
      }
      else {
         for (i = 0; i < count; i++) {
            if (ub_indices[i] > max_ub) max_ub = ub_indices[i];
            if (ub_indices[i] < min_ub) min_ub = ub_indices[i];
         }
      }
      *out_min_index = min_ub;
      *out_max_index = max_ub;
      break;
   }
   default:
      assert(0);
      *out_min_index = 0;
      *out_max_index = 0;
   }

   if (transfer) {
      pipe_buffer_unmap(pipe, transfer);
   }
}
void
vc4_update_shadow_baselevel_texture(struct pipe_context *pctx,
                                    struct pipe_sampler_view *view)
{
    struct vc4_resource *shadow = vc4_resource(view->texture);
    struct vc4_resource *orig = vc4_resource(shadow->shadow_parent);
    assert(orig);

    if (shadow->writes == orig->writes)
        return;

    for (int i = 0; i <= shadow->base.b.last_level; i++) {
        struct pipe_box box = {
            .x = 0,
            .y = 0,
            .z = 0,
            .width = u_minify(shadow->base.b.width0, i),
            .height = u_minify(shadow->base.b.height0, i),
            .depth = 1,
        };

        util_resource_copy_region(pctx,
                                  &shadow->base.b, i, 0, 0, 0,
                                  &orig->base.b,
                                  view->u.tex.first_level + i,
                                  &box);
    }

    shadow->writes = orig->writes;
}

/**
 * Converts a 4-byte index buffer to 2 bytes.
 *
 * Since GLES2 only has support for 1 and 2-byte indices, the hardware doesn't
 * include 4-byte index support, and we have to shrink it down.
 *
 * There's no fallback support for when indices end up being larger than 2^16,
 * though it will at least assertion fail.  Also, if the original index data
 * was in user memory, it would be nice to not have uploaded it to a VBO
 * before translating.
 */
void
vc4_update_shadow_index_buffer(struct pipe_context *pctx,
                               const struct pipe_index_buffer *ib)
{
    struct vc4_resource *shadow = vc4_resource(ib->buffer);
    struct vc4_resource *orig = vc4_resource(shadow->shadow_parent);
    uint32_t count = shadow->base.b.width0 / 2;

    if (shadow->writes == orig->writes)
        return;

    struct pipe_transfer *src_transfer;
    uint32_t *src = pipe_buffer_map_range(pctx, &orig->base.b,
                                          ib->offset,
                                          count * 4,
                                          PIPE_TRANSFER_READ, &src_transfer);

    struct pipe_transfer *dst_transfer;
    uint16_t *dst = pipe_buffer_map_range(pctx, &shadow->base.b,
                                          0,
                                          count * 2,
                                          PIPE_TRANSFER_WRITE, &dst_transfer);

    for (int i = 0; i < count; i++) {
        uint32_t src_index = src[i];
        assert(src_index <= 0xffff);
        dst[i] = src_index;
    }

    pctx->transfer_unmap(pctx, dst_transfer);
    pctx->transfer_unmap(pctx, src_transfer);

    shadow->writes = orig->writes;
}

void
vc4_resource_screen_init(struct pipe_screen *pscreen)
{
    pscreen->resource_create = vc4_resource_create;
    pscreen->resource_from_handle = vc4_resource_from_handle;
    pscreen->resource_get_handle = u_resource_get_handle_vtbl;
    pscreen->resource_destroy = u_resource_destroy_vtbl;
}
Пример #20
0
static enum pipe_error
u_vbuf_translate_buffers(struct u_vbuf *mgr, struct translate_key *key,
                         unsigned vb_mask, unsigned out_vb,
                         int start_vertex, unsigned num_vertices,
                         int start_index, unsigned num_indices, int min_index,
                         boolean unroll_indices)
{
   struct translate *tr;
   struct pipe_transfer *vb_transfer[PIPE_MAX_ATTRIBS] = {0};
   struct pipe_resource *out_buffer = NULL;
   uint8_t *out_map;
   unsigned out_offset, mask;

   /* Get a translate object. */
   tr = translate_cache_find(mgr->translate_cache, key);

   /* Map buffers we want to translate. */
   mask = vb_mask;
   while (mask) {
      struct pipe_vertex_buffer *vb;
      unsigned offset;
      uint8_t *map;
      unsigned i = u_bit_scan(&mask);

      vb = &mgr->vertex_buffer[i];
      offset = vb->buffer_offset + vb->stride * start_vertex;

      if (vb->user_buffer) {
         map = (uint8_t*)vb->user_buffer + offset;
      } else {
         unsigned size = vb->stride ? num_vertices * vb->stride
                                    : sizeof(double)*4;

         if (offset+size > vb->buffer->width0) {
            size = vb->buffer->width0 - offset;
         }

         map = pipe_buffer_map_range(mgr->pipe, vb->buffer, offset, size,
                                     PIPE_TRANSFER_READ, &vb_transfer[i]);
      }

      /* Subtract min_index so that indexing with the index buffer works. */
      if (unroll_indices) {
         map -= (ptrdiff_t)vb->stride * min_index;
      }

      tr->set_buffer(tr, i, map, vb->stride, ~0);
   }

   /* Translate. */
   if (unroll_indices) {
      struct pipe_index_buffer *ib = &mgr->index_buffer;
      struct pipe_transfer *transfer = NULL;
      unsigned offset = ib->offset + start_index * ib->index_size;
      uint8_t *map;

      assert((ib->buffer || ib->user_buffer) && ib->index_size);

      /* Create and map the output buffer. */
      u_upload_alloc(mgr->pipe->stream_uploader, 0,
                     key->output_stride * num_indices, 4,
                     &out_offset, &out_buffer,
                     (void**)&out_map);
      if (!out_buffer)
         return PIPE_ERROR_OUT_OF_MEMORY;

      if (ib->user_buffer) {
         map = (uint8_t*)ib->user_buffer + offset;
      } else {
         map = pipe_buffer_map_range(mgr->pipe, ib->buffer, offset,
                                     num_indices * ib->index_size,
                                     PIPE_TRANSFER_READ, &transfer);
      }

      switch (ib->index_size) {
      case 4:
         tr->run_elts(tr, (unsigned*)map, num_indices, 0, 0, out_map);
         break;
      case 2:
         tr->run_elts16(tr, (uint16_t*)map, num_indices, 0, 0, out_map);
         break;
      case 1:
         tr->run_elts8(tr, map, num_indices, 0, 0, out_map);
         break;
      }

      if (transfer) {
         pipe_buffer_unmap(mgr->pipe, transfer);
      }
   } else {
      /* Create and map the output buffer. */
      u_upload_alloc(mgr->pipe->stream_uploader,
                     key->output_stride * start_vertex,
                     key->output_stride * num_vertices, 4,
                     &out_offset, &out_buffer,
                     (void**)&out_map);
      if (!out_buffer)
         return PIPE_ERROR_OUT_OF_MEMORY;

      out_offset -= key->output_stride * start_vertex;

      tr->run(tr, 0, num_vertices, 0, 0, out_map);
   }

   /* Unmap all buffers. */
   mask = vb_mask;
   while (mask) {
      unsigned i = u_bit_scan(&mask);

      if (vb_transfer[i]) {
         pipe_buffer_unmap(mgr->pipe, vb_transfer[i]);
      }
   }

   /* Setup the new vertex buffer. */
   mgr->real_vertex_buffer[out_vb].buffer_offset = out_offset;
   mgr->real_vertex_buffer[out_vb].stride = key->output_stride;

   /* Move the buffer reference. */
   pipe_resource_reference(
      &mgr->real_vertex_buffer[out_vb].buffer, NULL);
   mgr->real_vertex_buffer[out_vb].buffer = out_buffer;

   return PIPE_OK;
}
Пример #21
0
static enum pipe_error
emit_constbuf_vgpu10(struct svga_context *svga, unsigned shader)
{
   const struct pipe_constant_buffer *cbuf;
   struct pipe_resource *dst_buffer = NULL;
   enum pipe_error ret = PIPE_OK;
   struct pipe_transfer *src_transfer;
   struct svga_winsys_surface *dst_handle;
   float extras[MAX_EXTRA_CONSTS][4];
   unsigned extra_count, extra_size, extra_offset;
   unsigned new_buf_size;
   void *src_map = NULL, *dst_map;
   unsigned offset;
   const struct svga_shader_variant *variant;
   unsigned alloc_buf_size;

   assert(shader == PIPE_SHADER_VERTEX ||
          shader == PIPE_SHADER_GEOMETRY ||
          shader == PIPE_SHADER_FRAGMENT);

   cbuf = &svga->curr.constbufs[shader][0];

   switch (shader) {
   case PIPE_SHADER_VERTEX:
      variant = svga->state.hw_draw.vs;
      extra_count = svga_get_extra_vs_constants(svga, (float *) extras);
      break;
   case PIPE_SHADER_FRAGMENT:
      variant = svga->state.hw_draw.fs;
      extra_count = svga_get_extra_fs_constants(svga, (float *) extras);
      break;
   case PIPE_SHADER_GEOMETRY:
      variant = svga->state.hw_draw.gs;
      extra_count = svga_get_extra_gs_constants(svga, (float *) extras);
      break;
   default:
      assert(!"Unexpected shader type");
      /* Don't return an error code since we don't want to keep re-trying
       * this function and getting stuck in an infinite loop.
       */
      return PIPE_OK;
   }

   assert(variant);

   /* Compute extra constants size and offset in bytes */
   extra_size = extra_count * 4 * sizeof(float);
   extra_offset = 4 * sizeof(float) * variant->extra_const_start;

   if (cbuf->buffer_size + extra_size == 0)
      return PIPE_OK;  /* nothing to do */

   /* Typically, the cbuf->buffer here is a user-space buffer so mapping
    * it is really cheap.  If we ever get real HW buffers for constants
    * we should void mapping and instead use a ResourceCopy command.
    */
   if (cbuf->buffer_size > 0) {
      src_map = pipe_buffer_map_range(&svga->pipe, cbuf->buffer,
                                      cbuf->buffer_offset, cbuf->buffer_size,
                                      PIPE_TRANSFER_READ, &src_transfer);
      assert(src_map);
      if (!src_map) {
         return PIPE_ERROR_OUT_OF_MEMORY;
      }
   }

   /* The new/dest buffer's size must be large enough to hold the original,
    * user-specified constants, plus the extra constants.
    * The size of the original constant buffer _should_ agree with what the
    * shader is expecting, but it might not (it's not enforced anywhere by
    * gallium).
    */
   new_buf_size = MAX2(cbuf->buffer_size, extra_offset) + extra_size;

   /* According to the DX10 spec, the constant buffer size must be
    * in multiples of 16.
    */
   new_buf_size = align(new_buf_size, 16);

   /* Constant buffer size in the upload buffer must be in multiples of 256.
    * In order to maximize the chance of merging the upload buffer chunks
    * when svga_buffer_add_range() is called,
    * the allocate buffer size needs to be in multiples of 256 as well.
    * Otherwise, since there is gap between each dirty range of the upload buffer,
    * each dirty range will end up in its own UPDATE_GB_IMAGE command.
    */
   alloc_buf_size = align(new_buf_size, CONST0_UPLOAD_ALIGNMENT);

   u_upload_alloc(svga->const0_upload, 0, alloc_buf_size,
                  CONST0_UPLOAD_ALIGNMENT, &offset,
                  &dst_buffer, &dst_map);
   if (!dst_map) {
      if (src_map)
         pipe_buffer_unmap(&svga->pipe, src_transfer);
      return PIPE_ERROR_OUT_OF_MEMORY;
   }

   if (src_map) {
      memcpy(dst_map, src_map, cbuf->buffer_size);
      pipe_buffer_unmap(&svga->pipe, src_transfer);
   }

   if (extra_size) {
      assert(extra_offset + extra_size <= new_buf_size);
      memcpy((char *) dst_map + extra_offset, extras, extra_size);
   }
   u_upload_unmap(svga->const0_upload);

   /* Issue the SetSingleConstantBuffer command */
   dst_handle = svga_buffer_handle(svga, dst_buffer);
   if (!dst_handle) {
      pipe_resource_reference(&dst_buffer, NULL);
      return PIPE_ERROR_OUT_OF_MEMORY;
   }

   assert(new_buf_size % 16 == 0);
   ret = SVGA3D_vgpu10_SetSingleConstantBuffer(svga->swc,
                                               0, /* index */
                                               svga_shader_type(shader),
                                               dst_handle,
                                               offset,
                                               new_buf_size);

   if (ret != PIPE_OK) {
      pipe_resource_reference(&dst_buffer, NULL);
      return ret;
   }

   /* Save this const buffer until it's replaced in the future.
    * Otherwise, all references to the buffer will go away after the
    * command buffer is submitted, it'll get recycled and we will have
    * incorrect constant buffer bindings.
    */
   pipe_resource_reference(&svga->state.hw_draw.constbuf[shader], dst_buffer);

   svga->state.hw_draw.default_constbuf_size[shader] = new_buf_size;

   pipe_resource_reference(&dst_buffer, NULL);

   svga->hud.num_const_buf_updates++;

   return ret;
}