/** * Replace data in a subrange of buffer object. If the data range * specified by size + offset extends beyond the end of the buffer or * if data is NULL, no copy is performed. * Called via glBufferSubDataARB(). */ static void intel_bufferobj_subdata(struct gl_context * ctx, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); bool busy; if (size == 0) return; assert(intel_obj); /* If we have a single copy in system memory, update that */ if (intel_obj->sys_buffer) { if (intel_obj->source) release_buffer(intel_obj); if (intel_obj->buffer == NULL) { memcpy((char *)intel_obj->sys_buffer + offset, data, size); return; } free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; } /* Otherwise we need to update the copy in video memory. */ busy = drm_intel_bo_busy(intel_obj->buffer) || drm_intel_bo_references(intel->batch.bo, intel_obj->buffer); if (busy) { if (size == intel_obj->Base.Size) { /* Replace the current busy bo with fresh data. */ drm_intel_bo_unreference(intel_obj->buffer); intel_bufferobj_alloc_buffer(intel, intel_obj); drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } else { perf_debug("Using a blit copy to avoid stalling on %ldb " "glBufferSubData() to a busy buffer object.\n", (long)size); drm_intel_bo *temp_bo = drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64); drm_intel_bo_subdata(temp_bo, 0, size, data); intel_emit_linear_blit(intel, intel_obj->buffer, offset, temp_bo, 0, size); drm_intel_bo_unreference(temp_bo); } } else { drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } }
/** * The BufferData() driver hook. * * Implements glBufferData(), which recreates a buffer object's data store * and populates it with the given data, if present. * * Any data that was previously stored in the buffer object is lost. * * \return true for success, false if out of memory */ static GLboolean intel_bufferobj_data(struct gl_context * ctx, GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage, struct gl_buffer_object *obj) { struct brw_context *brw = brw_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); /* Part of the ABI, but this function doesn't use it. */ (void) target; intel_obj->Base.Size = size; intel_obj->Base.Usage = usage; assert(!obj->Pointer); /* Mesa should have unmapped it */ if (intel_obj->buffer != NULL) release_buffer(intel_obj); if (size != 0) { intel_bufferobj_alloc_buffer(brw, intel_obj); if (!intel_obj->buffer) return false; if (data != NULL) drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } return true; }
/* Ideally we'd use a BO to avoid taking up cache space for the temporary * data, but FlushMappedBufferRange may be followed by further writes to * the pointer, so we would have to re-map after emitting our blit, which * would defeat the point. */ static void intel_bufferobj_flush_mapped_range(GLcontext *ctx, GLenum target, GLintptr offset, GLsizeiptr length, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); drm_intel_bo *temp_bo; /* Unless we're in the range map using a temporary system buffer, * there's no work to do. */ if (intel_obj->range_map_buffer == NULL) return; temp_bo = drm_intel_bo_alloc(intel->bufmgr, "range map flush", length, 64); drm_intel_bo_subdata(temp_bo, 0, length, intel_obj->range_map_buffer); intel_emit_linear_blit(intel, intel_obj->buffer, obj->Offset + offset, temp_bo, 0, length); drm_intel_bo_unreference(temp_bo); }
drm_intel_bo * intel_bufferobj_buffer(struct intel_context *intel, struct intel_buffer_object *intel_obj, GLuint flag) { if (intel_obj->region) { if (flag == INTEL_WRITE_PART) intel_bufferobj_cow(intel, intel_obj); else if (flag == INTEL_WRITE_FULL) { intel_bufferobj_release_region(intel, intel_obj); intel_bufferobj_alloc_buffer(intel, intel_obj); } } if (intel_obj->source) release_buffer(intel_obj); if (intel_obj->buffer == NULL) { intel_bufferobj_alloc_buffer(intel, intel_obj); drm_intel_bo_subdata(intel_obj->buffer, 0, intel_obj->Base.Size, intel_obj->sys_buffer); free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; intel_obj->offset = 0; } return intel_obj->buffer; }
void *intel_upload_map(struct intel_context *intel, GLuint size, GLuint align) { GLuint base, delta; char *ptr; base = (intel->upload.offset + align - 1) / align * align; if (intel->upload.bo == NULL || base + size > intel->upload.bo->size) { wrap_buffers(intel, size); base = 0; } delta = base - intel->upload.offset; if (intel->upload.buffer_len && intel->upload.buffer_len + delta + size > sizeof(intel->upload.buffer)) { drm_intel_bo_subdata(intel->upload.bo, intel->upload.buffer_offset, intel->upload.buffer_len, intel->upload.buffer); intel->upload.buffer_len = 0; } if (size <= sizeof(intel->upload.buffer)) { if (intel->upload.buffer_len == 0) intel->upload.buffer_offset = base; else intel->upload.buffer_len += delta; ptr = intel->upload.buffer + intel->upload.buffer_len; intel->upload.buffer_len += size; } else ptr = malloc(size); return ptr; }
static int batch_flush(struct intel_info *info) { int size, ret; batch_dword(info, MI_BATCH_BUFFER_END); size = batch_count(info); if (size & 1) { batch_dword(info, MI_NOOP); size = batch_count(info); } size *= sizeof(info->batch[0]); ret = drm_intel_bo_subdata(info->batch_ibo, 0, size, info->batch); if (ret) { ALOGE("failed to subdata batch"); goto fail; } ret = drm_intel_bo_mrb_exec(info->batch_ibo, size, NULL, 0, 0, info->exec_blt); if (ret) { ALOGE("failed to exec batch"); goto fail; } return batch_next(info); fail: info->cur = info->batch; return ret; }
void intel_upload_data(struct intel_context *intel, const void *ptr, GLuint size, GLuint align, drm_intel_bo **return_bo, GLuint *return_offset) { GLuint base, delta; base = (intel->upload.offset + align - 1) / align * align; if (intel->upload.bo == NULL || base + size > intel->upload.bo->size) { wrap_buffers(intel, size); base = 0; } drm_intel_bo_reference(intel->upload.bo); *return_bo = intel->upload.bo; *return_offset = base; delta = base - intel->upload.offset; if (intel->upload.buffer_len && intel->upload.buffer_len + delta + size > sizeof(intel->upload.buffer)) { drm_intel_bo_subdata(intel->upload.bo, intel->upload.buffer_offset, intel->upload.buffer_len, intel->upload.buffer); intel->upload.buffer_len = 0; } if (size < sizeof(intel->upload.buffer)) { if (intel->upload.buffer_len == 0) intel->upload.buffer_offset = base; else intel->upload.buffer_len += delta; memcpy(intel->upload.buffer + intel->upload.buffer_len, ptr, size); intel->upload.buffer_len += size; } else { drm_intel_bo_subdata(intel->upload.bo, base, size, ptr); } intel->upload.offset = base + size; }
void intel_upload_data(struct brw_context *brw, const void *ptr, GLuint size, GLuint align, drm_intel_bo **return_bo, GLuint *return_offset) { GLuint base, delta; base = (brw->upload.offset + align - 1) / align * align; if (brw->upload.bo == NULL || base + size > brw->upload.bo->size) { wrap_buffers(brw, size); base = 0; } drm_intel_bo_reference(brw->upload.bo); *return_bo = brw->upload.bo; *return_offset = base; delta = base - brw->upload.offset; if (brw->upload.buffer_len && brw->upload.buffer_len + delta + size > sizeof(brw->upload.buffer)) { drm_intel_bo_subdata(brw->upload.bo, brw->upload.buffer_offset, brw->upload.buffer_len, brw->upload.buffer); brw->upload.buffer_len = 0; } if (size < sizeof(brw->upload.buffer)) { if (brw->upload.buffer_len == 0) brw->upload.buffer_offset = base; else brw->upload.buffer_len += delta; memcpy(brw->upload.buffer + brw->upload.buffer_len, ptr, size); brw->upload.buffer_len += size; } else { drm_intel_bo_subdata(brw->upload.bo, base, size, ptr); } brw->upload.offset = base + size; }
static void gen6_render_flush(struct intel_batchbuffer *batch, uint32_t batch_end) { int ret; ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); if (ret == 0) ret = drm_intel_bo_mrb_exec(batch->bo, batch_end, NULL, 0, 0, 0); assert(ret == 0); }
static void *work(void *arg) { struct intel_batchbuffer *batch; render_copyfunc_t rendercopy = get_render_copyfunc(devid); drm_intel_context *context; drm_intel_bufmgr *bufmgr; int thread_id = *(int *)arg; int td_fd; int i; if (multiple_fds) td_fd = fd = drm_open_any(); else td_fd = fd; assert(td_fd >= 0); bufmgr = drm_intel_bufmgr_gem_init(td_fd, 4096); batch = intel_batchbuffer_alloc(bufmgr, devid); context = drm_intel_gem_context_create(bufmgr); if (!context) { returns[thread_id] = 77; goto out; } for (i = 0; i < iter; i++) { struct scratch_buf src, dst; init_buffer(bufmgr, &src, 4096); init_buffer(bufmgr, &dst, 4096); if (uncontexted) { assert(rendercopy); rendercopy(batch, &src, 0, 0, 0, 0, &dst, 0, 0); } else { int ret; ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); assert(ret == 0); intel_batchbuffer_flush_with_context(batch, context); } } out: drm_intel_gem_context_destroy(context); intel_batchbuffer_free(batch); drm_intel_bufmgr_destroy(bufmgr); if (multiple_fds) close(td_fd); pthread_exit(&returns[thread_id]); }
/** * Allocate space for and store data in a buffer object. Any data that was * previously stored in the buffer object is lost. If data is NULL, * memory will be allocated, but no copy will occur. * Called via ctx->Driver.BufferData(). * \return true for success, false if out of memory */ static GLboolean intel_bufferobj_data(struct gl_context * ctx, GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); /* Part of the ABI, but this function doesn't use it. */ #ifndef I915 (void) target; #endif intel_obj->Base.Size = size; intel_obj->Base.Usage = usage; assert(!obj->Pointer); /* Mesa should have unmapped it */ if (intel_obj->buffer != NULL) release_buffer(intel_obj); free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; if (size != 0) { if (usage == GL_DYNAMIC_DRAW #ifdef I915 /* On pre-965, stick VBOs in system memory, as we're always doing * swtnl with their contents anyway. */ || target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER #endif ) { intel_obj->sys_buffer = malloc(size); if (intel_obj->sys_buffer != NULL) { if (data != NULL) memcpy(intel_obj->sys_buffer, data, size); return true; } } intel_bufferobj_alloc_buffer(intel, intel_obj); if (!intel_obj->buffer) return false; if (data != NULL) drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } return true; }
static int i915_drm_buffer_write(struct i915_winsys *iws, struct i915_winsys_buffer *buffer, size_t offset, size_t size, const void *data) { struct i915_drm_buffer *buf = i915_drm_buffer(buffer); return drm_intel_bo_subdata(buf->bo, offset, size, (void*)data); }
/** * Replace data in a subrange of buffer object. If the data range * specified by size + offset extends beyond the end of the buffer or * if data is NULL, no copy is performed. * Called via glBufferSubDataARB(). */ static void intel_bufferobj_subdata(GLcontext * ctx, GLenum target, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); if (size == 0) return; assert(intel_obj); if (intel_obj->region) intel_bufferobj_cow(intel, intel_obj); if (intel_obj->sys_buffer) memcpy((char *)intel_obj->sys_buffer + offset, data, size); else { /* Flush any existing batchbuffer that might reference this data. */ if (drm_intel_bo_busy(intel_obj->buffer) || drm_intel_bo_references(intel->batch->buf, intel_obj->buffer)) { drm_intel_bo *temp_bo; temp_bo = drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64); drm_intel_bo_subdata(temp_bo, 0, size, data); intel_emit_linear_blit(intel, intel_obj->buffer, offset, temp_bo, 0, size); drm_intel_bo_unreference(temp_bo); } else { drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } } }
static void gen6_render_flush(struct intel_batchbuffer *batch, drm_intel_context *context, uint32_t batch_end) { int ret; ret = drm_intel_bo_subdata(batch->bo, 0, 4096, batch->buffer); if (ret == 0) ret = drm_intel_gem_bo_context_exec(batch->bo, context, batch_end, 0); assert(ret == 0); }
/** * Allocate space for and store data in a buffer object. Any data that was * previously stored in the buffer object is lost. If data is NULL, * memory will be allocated, but no copy will occur. * Called via ctx->Driver.BufferData(). * \return GL_TRUE for success, GL_FALSE if out of memory */ static GLboolean intel_bufferobj_data(GLcontext * ctx, GLenum target, GLsizeiptrARB size, const GLvoid * data, GLenum usage, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); intel_obj->Base.Size = size; intel_obj->Base.Usage = usage; assert(!obj->Pointer); /* Mesa should have unmapped it */ if (intel_obj->region) intel_bufferobj_release_region(intel, intel_obj); if (intel_obj->buffer != NULL) { drm_intel_bo_unreference(intel_obj->buffer); intel_obj->buffer = NULL; } free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; if (size != 0) { #ifdef I915 /* On pre-965, stick VBOs in system memory, as we're always doing swtnl * with their contents anyway. */ if (target == GL_ARRAY_BUFFER || target == GL_ELEMENT_ARRAY_BUFFER) { intel_obj->sys_buffer = malloc(size); if (intel_obj->sys_buffer != NULL) { if (data != NULL) memcpy(intel_obj->sys_buffer, data, size); return GL_TRUE; } } #endif intel_bufferobj_alloc_buffer(intel, intel_obj); if (!intel_obj->buffer) return GL_FALSE; if (data != NULL) drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } return GL_TRUE; }
void intel_batchbuffer_flush_on_ring(struct intel_batchbuffer *batch, int ring) { unsigned int used = flush_on_ring_common(batch, ring); if (used == 0) return; do_or_die(drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer)); batch->ptr = NULL; do_or_die(drm_intel_bo_mrb_exec(batch->bo, used, NULL, 0, 0, ring)); intel_batchbuffer_reset(batch); }
void intel_upload_finish(struct brw_context *brw) { if (!brw->upload.bo) return; if (brw->upload.buffer_len) { drm_intel_bo_subdata(brw->upload.bo, brw->upload.buffer_offset, brw->upload.buffer_len, brw->upload.buffer); brw->upload.buffer_len = 0; } drm_intel_bo_unreference(brw->upload.bo); brw->upload.bo = NULL; }
void intel_upload_finish(struct intel_context *intel) { if (!intel->upload.bo) return; if (intel->upload.buffer_len) { drm_intel_bo_subdata(intel->upload.bo, intel->upload.buffer_offset, intel->upload.buffer_len, intel->upload.buffer); intel->upload.buffer_len = 0; } drm_intel_bo_unreference(intel->upload.bo); intel->upload.bo = NULL; }
static void prw_copyfunc(struct scratch_buf *src, unsigned src_x, unsigned src_y, struct scratch_buf *dst, unsigned dst_x, unsigned dst_y, unsigned logical_tile_no) { uint32_t tmp_tile[options.tile_size*options.tile_size]; int i; assert(batch->ptr == batch->buffer); if (options.ducttape) drm_intel_bo_wait_rendering(dst->bo); if (src->tiling == I915_TILING_NONE) { for (i = 0; i < options.tile_size; i++) { unsigned ofs = src_x*sizeof(uint32_t) + src->stride*(src_y + i); drm_intel_bo_get_subdata(src->bo, ofs, options.tile_size*sizeof(uint32_t), tmp_tile + options.tile_size*i); } } else { if (options.use_cpu_maps) set_to_cpu_domain(src, 0); cpucpy2d(src->data, src->stride/sizeof(uint32_t), src_x, src_y, tmp_tile, options.tile_size, 0, 0, logical_tile_no); } if (dst->tiling == I915_TILING_NONE) { for (i = 0; i < options.tile_size; i++) { unsigned ofs = dst_x*sizeof(uint32_t) + dst->stride*(dst_y + i); drm_intel_bo_subdata(dst->bo, ofs, options.tile_size*sizeof(uint32_t), tmp_tile + options.tile_size*i); } } else { if (options.use_cpu_maps) set_to_cpu_domain(dst, 1); cpucpy2d(tmp_tile, options.tile_size, 0, 0, dst->data, dst->stride/sizeof(uint32_t), dst_x, dst_y, logical_tile_no); } }
void intel_upload_unmap(struct intel_context *intel, const void *ptr, GLuint size, GLuint align, drm_intel_bo **return_bo, GLuint *return_offset) { GLuint base; base = (intel->upload.offset + align - 1) / align * align; if (size > sizeof(intel->upload.buffer)) { drm_intel_bo_subdata(intel->upload.bo, base, size, ptr); free((void*)ptr); } drm_intel_bo_reference(intel->upload.bo); *return_bo = intel->upload.bo; *return_offset = base; intel->upload.offset = base + size; }
void intel_batchbuffer_flush_with_context(struct intel_batchbuffer *batch, drm_intel_context *context) { int ret; unsigned int used = flush_on_ring_common(batch, I915_EXEC_RENDER); if (used == 0) return; ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->buffer); assert(ret == 0); batch->ptr = NULL; ret = drm_intel_gem_bo_context_exec(batch->bo, context, used, I915_EXEC_RENDER); assert(ret == 0); intel_batchbuffer_reset(batch); }
drm_intel_bo * intel_bufferobj_buffer(struct intel_context *intel, struct intel_buffer_object *intel_obj, GLuint flag) { if (intel_obj->source) release_buffer(intel_obj); if (intel_obj->buffer == NULL) { intel_bufferobj_alloc_buffer(intel, intel_obj); drm_intel_bo_subdata(intel_obj->buffer, 0, intel_obj->Base.Size, intel_obj->sys_buffer); free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; intel_obj->offset = 0; } return intel_obj->buffer; }
static void do_render(drm_intel_bufmgr *bufmgr, struct intel_batchbuffer *batch, drm_intel_bo *dst_bo, int width, int height) { uint32_t data[width * height]; drm_intel_bo *src_bo; int i; static uint32_t seed = 1; /* Generate some junk. Real workloads would be doing a lot more * work to generate the junk. */ for (i = 0; i < width * height; i++) { data[i] = seed++; } /* Upload the junk. */ src_bo = drm_intel_bo_alloc(bufmgr, "src", sizeof(data), 4096); drm_intel_bo_subdata(src_bo, 0, sizeof(data), data); /* Render the junk to the dst. */ BLIT_COPY_BATCH_START(0); OUT_BATCH((3 << 24) | /* 32 bits */ (0xcc << 16) | /* copy ROP */ (width * 4) /* dst pitch */); OUT_BATCH(0); /* dst x1,y1 */ OUT_BATCH((height << 16) | width); /* dst x2,y2 */ OUT_RELOC(dst_bo, I915_GEM_DOMAIN_RENDER, I915_GEM_DOMAIN_RENDER, 0); OUT_BATCH(0); /* src x1,y1 */ OUT_BATCH(width * 4); /* src pitch */ OUT_RELOC(src_bo, I915_GEM_DOMAIN_RENDER, 0, 0); ADVANCE_BATCH(); intel_batchbuffer_flush(batch); drm_intel_bo_unreference(src_bo); }
void * intel_upload_map(struct brw_context *brw, GLuint size, GLuint align) { GLuint base, delta; char *ptr; base = (brw->upload.offset + align - 1) / align * align; if (brw->upload.bo == NULL || base + size > brw->upload.bo->size) { wrap_buffers(brw, size); base = 0; } delta = base - brw->upload.offset; if (brw->upload.buffer_len && brw->upload.buffer_len + delta + size > sizeof(brw->upload.buffer)) { drm_intel_bo_subdata(brw->upload.bo, brw->upload.buffer_offset, brw->upload.buffer_len, brw->upload.buffer); brw->upload.buffer_len = 0; } if (size <= sizeof(brw->upload.buffer)) { if (brw->upload.buffer_len == 0) brw->upload.buffer_offset = base; else brw->upload.buffer_len += delta; ptr = brw->upload.buffer + brw->upload.buffer_len; brw->upload.buffer_len += size; } else { ptr = malloc(size); } return ptr; }
/** * Replace data in a subrange of buffer object. If the data range * specified by size + offset extends beyond the end of the buffer or * if data is NULL, no copy is performed. * Called via glBufferSubDataARB(). */ static void intel_bufferobj_subdata(struct gl_context * ctx, GLintptrARB offset, GLsizeiptrARB size, const GLvoid * data, struct gl_buffer_object *obj) { struct intel_context *intel = intel_context(ctx); struct intel_buffer_object *intel_obj = intel_buffer_object(obj); bool busy; if (size == 0) return; assert(intel_obj); /* If we have a single copy in system memory, update that */ if (intel_obj->sys_buffer) { if (intel_obj->source) release_buffer(intel_obj); if (intel_obj->buffer == NULL) { memcpy((char *)intel_obj->sys_buffer + offset, data, size); return; } free(intel_obj->sys_buffer); intel_obj->sys_buffer = NULL; } /* Otherwise we need to update the copy in video memory. */ busy = drm_intel_bo_busy(intel_obj->buffer) || drm_intel_bo_references(intel->batch.bo, intel_obj->buffer); /* replace the current busy bo with fresh data */ if (busy && size == intel_obj->Base.Size) { drm_intel_bo_unreference(intel_obj->buffer); intel_bufferobj_alloc_buffer(intel, intel_obj); drm_intel_bo_subdata(intel_obj->buffer, 0, size, data); } else if (intel->gen < 6) { if (busy) { drm_intel_bo *temp_bo; temp_bo = drm_intel_bo_alloc(intel->bufmgr, "subdata temp", size, 64); drm_intel_bo_subdata(temp_bo, 0, size, data); intel_emit_linear_blit(intel, intel_obj->buffer, offset, temp_bo, 0, size); drm_intel_bo_unreference(temp_bo); } else { drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } } else { /* Can't use the blit to modify the buffer in the middle of batch. */ if (drm_intel_bo_references(intel->batch.bo, intel_obj->buffer)) { intel_batchbuffer_flush(intel); } drm_intel_bo_subdata(intel_obj->buffer, offset, size, data); } }
int intel_bo_pwrite(struct intel_bo *bo, unsigned long offset, unsigned long size, const void *data) { return drm_intel_bo_subdata(gem_bo(bo), offset, size, data); }