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