1 
2 #include "i915_drm_winsys.h"
3 #include "util/u_memory.h"
4 
5 #include "i915_drm.h"
6 #include "i915/i915_debug.h"
7 #include <xf86drm.h>
8 #include <stdio.h>
9 
10 #define BATCH_RESERVED 16
11 
12 #define INTEL_DEFAULT_RELOCS 100
13 #define INTEL_MAX_RELOCS 400
14 
15 #define INTEL_BATCH_NO_CLIPRECTS 0x1
16 #define INTEL_BATCH_CLIPRECTS    0x2
17 
18 #undef INTEL_RUN_SYNC
19 
20 struct i915_drm_batchbuffer
21 {
22    struct i915_winsys_batchbuffer base;
23 
24    size_t actual_size;
25 
26    drm_intel_bo *bo;
27 };
28 
29 static INLINE struct i915_drm_batchbuffer *
i915_drm_batchbuffer(struct i915_winsys_batchbuffer * batch)30 i915_drm_batchbuffer(struct i915_winsys_batchbuffer *batch)
31 {
32    return (struct i915_drm_batchbuffer *)batch;
33 }
34 
35 static void
i915_drm_batchbuffer_reset(struct i915_drm_batchbuffer * batch)36 i915_drm_batchbuffer_reset(struct i915_drm_batchbuffer *batch)
37 {
38    struct i915_drm_winsys *idws = i915_drm_winsys(batch->base.iws);
39 
40    if (batch->bo)
41       drm_intel_bo_unreference(batch->bo);
42    batch->bo = drm_intel_bo_alloc(idws->gem_manager,
43                                   "gallium3d_batchbuffer",
44                                   batch->actual_size,
45                                   4096);
46 
47    memset(batch->base.map, 0, batch->actual_size);
48    batch->base.ptr = batch->base.map;
49    batch->base.size = batch->actual_size - BATCH_RESERVED;
50    batch->base.relocs = 0;
51 }
52 
53 static struct i915_winsys_batchbuffer *
i915_drm_batchbuffer_create(struct i915_winsys * iws)54 i915_drm_batchbuffer_create(struct i915_winsys *iws)
55 {
56    struct i915_drm_winsys *idws = i915_drm_winsys(iws);
57    struct i915_drm_batchbuffer *batch = CALLOC_STRUCT(i915_drm_batchbuffer);
58 
59    batch->actual_size = idws->max_batch_size;
60 
61    batch->base.map = MALLOC(batch->actual_size);
62    batch->base.ptr = NULL;
63    batch->base.size = 0;
64 
65    batch->base.relocs = 0;
66 
67    batch->base.iws = iws;
68 
69    i915_drm_batchbuffer_reset(batch);
70 
71    return &batch->base;
72 }
73 
74 static boolean
i915_drm_batchbuffer_validate_buffers(struct i915_winsys_batchbuffer * batch,struct i915_winsys_buffer ** buffer,int num_of_buffers)75 i915_drm_batchbuffer_validate_buffers(struct i915_winsys_batchbuffer *batch,
76 				      struct i915_winsys_buffer **buffer,
77 				      int num_of_buffers)
78 {
79    struct i915_drm_batchbuffer *drm_batch = i915_drm_batchbuffer(batch);
80    drm_intel_bo *bos[num_of_buffers + 1];
81    int i, ret;
82 
83    bos[0] = drm_batch->bo;
84    for (i = 0; i < num_of_buffers; i++)
85       bos[i+1] = intel_bo(buffer[i]);
86 
87    ret = drm_intel_bufmgr_check_aperture_space(bos, num_of_buffers);
88    if (ret != 0)
89       return FALSE;
90 
91    return TRUE;
92 }
93 
94 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)95 i915_drm_batchbuffer_reloc(struct i915_winsys_batchbuffer *ibatch,
96                             struct i915_winsys_buffer *buffer,
97                             enum i915_winsys_buffer_usage usage,
98                             unsigned pre_add, boolean fenced)
99 {
100    struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
101    unsigned write_domain = 0;
102    unsigned read_domain = 0;
103    unsigned offset;
104    int ret = 0;
105 
106    switch (usage) {
107    case I915_USAGE_SAMPLER:
108       write_domain = 0;
109       read_domain = I915_GEM_DOMAIN_SAMPLER;
110       break;
111    case I915_USAGE_RENDER:
112       write_domain = I915_GEM_DOMAIN_RENDER;
113       read_domain = I915_GEM_DOMAIN_RENDER;
114       break;
115    case I915_USAGE_2D_TARGET:
116       write_domain = I915_GEM_DOMAIN_RENDER;
117       read_domain = I915_GEM_DOMAIN_RENDER;
118       break;
119    case I915_USAGE_2D_SOURCE:
120       write_domain = 0;
121       read_domain = I915_GEM_DOMAIN_RENDER;
122       break;
123    case I915_USAGE_VERTEX:
124       write_domain = 0;
125       read_domain = I915_GEM_DOMAIN_VERTEX;
126       break;
127    default:
128       assert(0);
129       return -1;
130    }
131 
132    offset = (unsigned)(batch->base.ptr - batch->base.map);
133 
134    if (fenced)
135       ret = drm_intel_bo_emit_reloc_fence(batch->bo, offset,
136 				    intel_bo(buffer), pre_add,
137 				    read_domain,
138 				    write_domain);
139    else
140       ret = drm_intel_bo_emit_reloc(batch->bo, offset,
141 				    intel_bo(buffer), pre_add,
142 				    read_domain,
143 				    write_domain);
144 
145    ((uint32_t*)batch->base.ptr)[0] = intel_bo(buffer)->offset + pre_add;
146    batch->base.ptr += 4;
147 
148    if (!ret)
149       batch->base.relocs++;
150 
151    return ret;
152 }
153 
154 static void
i915_drm_throttle(struct i915_drm_winsys * idws)155 i915_drm_throttle(struct i915_drm_winsys *idws)
156 {
157    drmIoctl(idws->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL);
158 }
159 
160 static void
i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer * ibatch,struct pipe_fence_handle ** fence)161 i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer *ibatch,
162                             struct pipe_fence_handle **fence)
163 {
164    struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
165    unsigned used;
166    int ret;
167 
168    /* MI_BATCH_BUFFER_END */
169    i915_winsys_batchbuffer_dword_unchecked(ibatch, (0xA<<23));
170 
171    used = batch->base.ptr - batch->base.map;
172    if (used & 4) {
173       /* MI_NOOP */
174       i915_winsys_batchbuffer_dword_unchecked(ibatch, 0);
175       used += 4;
176    }
177 
178    /* Do the sending to HW */
179    ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->base.map);
180    if (ret == 0 && i915_drm_winsys(ibatch->iws)->send_cmd)
181       ret = drm_intel_bo_exec(batch->bo, used, NULL, 0, 0);
182 
183    i915_drm_throttle(i915_drm_winsys(ibatch->iws));
184 
185    if (ret != 0 || i915_drm_winsys(ibatch->iws)->dump_cmd) {
186       i915_dump_batchbuffer(ibatch);
187       assert(ret == 0);
188    }
189 
190    if (i915_drm_winsys(ibatch->iws)->dump_raw_file) {
191       FILE *file = fopen(i915_drm_winsys(ibatch->iws)->dump_raw_file, "a");
192       if (file) {
193 	 fwrite(batch->base.map, used, 1, file);
194 	 fclose(file);
195       }
196    }
197 
198 #ifdef INTEL_RUN_SYNC
199    drm_intel_bo_wait_rendering(batch->bo);
200 #endif
201 
202    if (fence) {
203       ibatch->iws->fence_reference(ibatch->iws, fence, NULL);
204 
205 #ifdef INTEL_RUN_SYNC
206       /* we run synced to GPU so just pass null */
207       (*fence) = i915_drm_fence_create(NULL);
208 #else
209       (*fence) = i915_drm_fence_create(batch->bo);
210 #endif
211    }
212 
213    i915_drm_batchbuffer_reset(batch);
214 }
215 
216 static void
i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer * ibatch)217 i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch)
218 {
219    struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
220 
221    if (batch->bo)
222       drm_intel_bo_unreference(batch->bo);
223 
224    FREE(batch->base.map);
225    FREE(batch);
226 }
227 
i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys * idws)228 void i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys *idws)
229 {
230    idws->base.batchbuffer_create = i915_drm_batchbuffer_create;
231    idws->base.validate_buffers = i915_drm_batchbuffer_validate_buffers;
232    idws->base.batchbuffer_reloc = i915_drm_batchbuffer_reloc;
233    idws->base.batchbuffer_flush = i915_drm_batchbuffer_flush;
234    idws->base.batchbuffer_destroy = i915_drm_batchbuffer_destroy;
235 }
236