| |
| #include "i915_drm_winsys.h" |
| #include "util/u_memory.h" |
| |
| #include "i915_drm.h" |
| #include "i915/i915_debug.h" |
| #include <xf86drm.h> |
| #include <stdio.h> |
| |
| #define BATCH_RESERVED 16 |
| |
| #define INTEL_DEFAULT_RELOCS 100 |
| #define INTEL_MAX_RELOCS 400 |
| |
| #define INTEL_BATCH_NO_CLIPRECTS 0x1 |
| #define INTEL_BATCH_CLIPRECTS 0x2 |
| |
| #undef INTEL_RUN_SYNC |
| |
| struct i915_drm_batchbuffer |
| { |
| struct i915_winsys_batchbuffer base; |
| |
| size_t actual_size; |
| |
| drm_intel_bo *bo; |
| }; |
| |
| static INLINE struct i915_drm_batchbuffer * |
| i915_drm_batchbuffer(struct i915_winsys_batchbuffer *batch) |
| { |
| return (struct i915_drm_batchbuffer *)batch; |
| } |
| |
| static void |
| i915_drm_batchbuffer_reset(struct i915_drm_batchbuffer *batch) |
| { |
| struct i915_drm_winsys *idws = i915_drm_winsys(batch->base.iws); |
| |
| if (batch->bo) |
| drm_intel_bo_unreference(batch->bo); |
| batch->bo = drm_intel_bo_alloc(idws->gem_manager, |
| "gallium3d_batchbuffer", |
| batch->actual_size, |
| 4096); |
| |
| memset(batch->base.map, 0, batch->actual_size); |
| batch->base.ptr = batch->base.map; |
| batch->base.size = batch->actual_size - BATCH_RESERVED; |
| batch->base.relocs = 0; |
| } |
| |
| static struct i915_winsys_batchbuffer * |
| i915_drm_batchbuffer_create(struct i915_winsys *iws) |
| { |
| struct i915_drm_winsys *idws = i915_drm_winsys(iws); |
| struct i915_drm_batchbuffer *batch = CALLOC_STRUCT(i915_drm_batchbuffer); |
| |
| batch->actual_size = idws->max_batch_size; |
| |
| batch->base.map = MALLOC(batch->actual_size); |
| batch->base.ptr = NULL; |
| batch->base.size = 0; |
| |
| batch->base.relocs = 0; |
| |
| batch->base.iws = iws; |
| |
| i915_drm_batchbuffer_reset(batch); |
| |
| return &batch->base; |
| } |
| |
| static boolean |
| i915_drm_batchbuffer_validate_buffers(struct i915_winsys_batchbuffer *batch, |
| struct i915_winsys_buffer **buffer, |
| int num_of_buffers) |
| { |
| struct i915_drm_batchbuffer *drm_batch = i915_drm_batchbuffer(batch); |
| drm_intel_bo *bos[num_of_buffers + 1]; |
| int i, ret; |
| |
| bos[0] = drm_batch->bo; |
| for (i = 0; i < num_of_buffers; i++) |
| bos[i+1] = intel_bo(buffer[i]); |
| |
| ret = drm_intel_bufmgr_check_aperture_space(bos, num_of_buffers); |
| if (ret != 0) |
| return FALSE; |
| |
| return TRUE; |
| } |
| |
| static int |
| i915_drm_batchbuffer_reloc(struct i915_winsys_batchbuffer *ibatch, |
| struct i915_winsys_buffer *buffer, |
| enum i915_winsys_buffer_usage usage, |
| unsigned pre_add, boolean fenced) |
| { |
| struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch); |
| unsigned write_domain = 0; |
| unsigned read_domain = 0; |
| unsigned offset; |
| int ret = 0; |
| |
| switch (usage) { |
| case I915_USAGE_SAMPLER: |
| write_domain = 0; |
| read_domain = I915_GEM_DOMAIN_SAMPLER; |
| break; |
| case I915_USAGE_RENDER: |
| write_domain = I915_GEM_DOMAIN_RENDER; |
| read_domain = I915_GEM_DOMAIN_RENDER; |
| break; |
| case I915_USAGE_2D_TARGET: |
| write_domain = I915_GEM_DOMAIN_RENDER; |
| read_domain = I915_GEM_DOMAIN_RENDER; |
| break; |
| case I915_USAGE_2D_SOURCE: |
| write_domain = 0; |
| read_domain = I915_GEM_DOMAIN_RENDER; |
| break; |
| case I915_USAGE_VERTEX: |
| write_domain = 0; |
| read_domain = I915_GEM_DOMAIN_VERTEX; |
| break; |
| default: |
| assert(0); |
| return -1; |
| } |
| |
| offset = (unsigned)(batch->base.ptr - batch->base.map); |
| |
| if (fenced) |
| ret = drm_intel_bo_emit_reloc_fence(batch->bo, offset, |
| intel_bo(buffer), pre_add, |
| read_domain, |
| write_domain); |
| else |
| ret = drm_intel_bo_emit_reloc(batch->bo, offset, |
| intel_bo(buffer), pre_add, |
| read_domain, |
| write_domain); |
| |
| ((uint32_t*)batch->base.ptr)[0] = intel_bo(buffer)->offset + pre_add; |
| batch->base.ptr += 4; |
| |
| if (!ret) |
| batch->base.relocs++; |
| |
| return ret; |
| } |
| |
| static void |
| i915_drm_throttle(struct i915_drm_winsys *idws) |
| { |
| drmIoctl(idws->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL); |
| } |
| |
| static void |
| i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer *ibatch, |
| struct pipe_fence_handle **fence) |
| { |
| struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch); |
| unsigned used; |
| int ret; |
| |
| /* MI_BATCH_BUFFER_END */ |
| i915_winsys_batchbuffer_dword_unchecked(ibatch, (0xA<<23)); |
| |
| used = batch->base.ptr - batch->base.map; |
| if (used & 4) { |
| /* MI_NOOP */ |
| i915_winsys_batchbuffer_dword_unchecked(ibatch, 0); |
| used += 4; |
| } |
| |
| /* Do the sending to HW */ |
| ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->base.map); |
| if (ret == 0 && i915_drm_winsys(ibatch->iws)->send_cmd) |
| ret = drm_intel_bo_exec(batch->bo, used, NULL, 0, 0); |
| |
| i915_drm_throttle(i915_drm_winsys(ibatch->iws)); |
| |
| if (ret != 0 || i915_drm_winsys(ibatch->iws)->dump_cmd) { |
| i915_dump_batchbuffer(ibatch); |
| assert(ret == 0); |
| } |
| |
| if (i915_drm_winsys(ibatch->iws)->dump_raw_file) { |
| FILE *file = fopen(i915_drm_winsys(ibatch->iws)->dump_raw_file, "a"); |
| if (file) { |
| fwrite(batch->base.map, used, 1, file); |
| fclose(file); |
| } |
| } |
| |
| #ifdef INTEL_RUN_SYNC |
| drm_intel_bo_wait_rendering(batch->bo); |
| #endif |
| |
| if (fence) { |
| ibatch->iws->fence_reference(ibatch->iws, fence, NULL); |
| |
| #ifdef INTEL_RUN_SYNC |
| /* we run synced to GPU so just pass null */ |
| (*fence) = i915_drm_fence_create(NULL); |
| #else |
| (*fence) = i915_drm_fence_create(batch->bo); |
| #endif |
| } |
| |
| i915_drm_batchbuffer_reset(batch); |
| } |
| |
| static void |
| i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch) |
| { |
| struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch); |
| |
| if (batch->bo) |
| drm_intel_bo_unreference(batch->bo); |
| |
| FREE(batch->base.map); |
| FREE(batch); |
| } |
| |
| void i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys *idws) |
| { |
| idws->base.batchbuffer_create = i915_drm_batchbuffer_create; |
| idws->base.validate_buffers = i915_drm_batchbuffer_validate_buffers; |
| idws->base.batchbuffer_reloc = i915_drm_batchbuffer_reloc; |
| idws->base.batchbuffer_flush = i915_drm_batchbuffer_flush; |
| idws->base.batchbuffer_destroy = i915_drm_batchbuffer_destroy; |
| } |