1
2 #include "i915_drm_winsys.h"
3 #include "util/u_memory.h"
4
5 #include "drm-uapi/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 bool
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 /* 1 extra for drm_batch->bo */
81 int count = num_of_buffers + 1;
82 drm_intel_bo *bos[count];
83 int i, ret;
84
85 bos[0] = drm_batch->bo;
86 for (i = 0; i < num_of_buffers; i++)
87 bos[i+1] = intel_bo(buffer[i]);
88
89 ret = drm_intel_bufmgr_check_aperture_space(bos, count);
90 if (ret != 0)
91 return false;
92
93 return true;
94 }
95
96 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,bool fenced)97 i915_drm_batchbuffer_reloc(struct i915_winsys_batchbuffer *ibatch,
98 struct i915_winsys_buffer *buffer,
99 enum i915_winsys_buffer_usage usage,
100 unsigned pre_add, bool fenced)
101 {
102 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
103 unsigned write_domain = 0;
104 unsigned read_domain = 0;
105 unsigned offset;
106 int ret = 0;
107
108 switch (usage) {
109 case I915_USAGE_SAMPLER:
110 write_domain = 0;
111 read_domain = I915_GEM_DOMAIN_SAMPLER;
112 break;
113 case I915_USAGE_RENDER:
114 write_domain = I915_GEM_DOMAIN_RENDER;
115 read_domain = I915_GEM_DOMAIN_RENDER;
116 break;
117 case I915_USAGE_2D_TARGET:
118 write_domain = I915_GEM_DOMAIN_RENDER;
119 read_domain = I915_GEM_DOMAIN_RENDER;
120 break;
121 case I915_USAGE_2D_SOURCE:
122 write_domain = 0;
123 read_domain = I915_GEM_DOMAIN_RENDER;
124 break;
125 case I915_USAGE_VERTEX:
126 write_domain = 0;
127 read_domain = I915_GEM_DOMAIN_VERTEX;
128 break;
129 default:
130 assert(0);
131 return -1;
132 }
133
134 offset = (unsigned)(batch->base.ptr - batch->base.map);
135
136 if (fenced)
137 ret = drm_intel_bo_emit_reloc_fence(batch->bo, offset,
138 intel_bo(buffer), pre_add,
139 read_domain,
140 write_domain);
141 else
142 ret = drm_intel_bo_emit_reloc(batch->bo, offset,
143 intel_bo(buffer), pre_add,
144 read_domain,
145 write_domain);
146
147 ((uint32_t*)batch->base.ptr)[0] = intel_bo(buffer)->offset + pre_add;
148 batch->base.ptr += 4;
149
150 if (!ret)
151 batch->base.relocs++;
152
153 return ret;
154 }
155
156 static void
i915_drm_throttle(struct i915_drm_winsys * idws)157 i915_drm_throttle(struct i915_drm_winsys *idws)
158 {
159 drmIoctl(idws->fd, DRM_IOCTL_I915_GEM_THROTTLE, NULL);
160 }
161
162 static void
i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer * ibatch,struct pipe_fence_handle ** fence,enum i915_winsys_flush_flags flags)163 i915_drm_batchbuffer_flush(struct i915_winsys_batchbuffer *ibatch,
164 struct pipe_fence_handle **fence,
165 enum i915_winsys_flush_flags flags)
166 {
167 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
168 unsigned used;
169 int ret;
170
171 /* MI_BATCH_BUFFER_END */
172 i915_winsys_batchbuffer_dword_unchecked(ibatch, (0xA<<23));
173
174 used = batch->base.ptr - batch->base.map;
175 if (used & 4) {
176 /* MI_NOOP */
177 i915_winsys_batchbuffer_dword_unchecked(ibatch, 0);
178 used += 4;
179 }
180
181 /* Do the sending to HW */
182 ret = drm_intel_bo_subdata(batch->bo, 0, used, batch->base.map);
183 if (ret == 0 && i915_drm_winsys(ibatch->iws)->send_cmd)
184 ret = drm_intel_bo_exec(batch->bo, used, NULL, 0, 0);
185
186 if (flags & I915_FLUSH_END_OF_FRAME)
187 i915_drm_throttle(i915_drm_winsys(ibatch->iws));
188
189 if (ret != 0 || i915_drm_winsys(ibatch->iws)->dump_cmd) {
190 i915_dump_batchbuffer(ibatch);
191 assert(ret == 0);
192 }
193
194 if (i915_drm_winsys(ibatch->iws)->dump_raw_file) {
195 FILE *file = fopen(i915_drm_winsys(ibatch->iws)->dump_raw_file, "a");
196 if (file) {
197 fwrite(batch->base.map, used, 1, file);
198 fclose(file);
199 }
200 }
201
202 #ifdef INTEL_RUN_SYNC
203 drm_intel_bo_wait_rendering(batch->bo);
204 #endif
205
206 if (fence) {
207 ibatch->iws->fence_reference(ibatch->iws, fence, NULL);
208
209 #ifdef INTEL_RUN_SYNC
210 /* we run synced to GPU so just pass null */
211 (*fence) = i915_drm_fence_create(NULL);
212 #else
213 (*fence) = i915_drm_fence_create(batch->bo);
214 #endif
215 }
216
217 i915_drm_batchbuffer_reset(batch);
218 }
219
220 static void
i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer * ibatch)221 i915_drm_batchbuffer_destroy(struct i915_winsys_batchbuffer *ibatch)
222 {
223 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
224
225 if (batch->bo)
226 drm_intel_bo_unreference(batch->bo);
227
228 FREE(batch->base.map);
229 FREE(batch);
230 }
231
232 static void
i915_drm_batchbuffer_emit_start(struct i915_winsys_batchbuffer * ibatch)233 i915_drm_batchbuffer_emit_start(struct i915_winsys_batchbuffer *ibatch)
234 {
235 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
236 ibatch->ptr_start = ibatch->ptr;
237 ibatch->reloc_count_start = drm_intel_gem_bo_get_reloc_count(batch->bo);
238 }
239
240 static void
i915_drm_batchbuffer_emit_restart(struct i915_winsys_batchbuffer * ibatch)241 i915_drm_batchbuffer_emit_restart(struct i915_winsys_batchbuffer *ibatch)
242 {
243 struct i915_drm_batchbuffer *batch = i915_drm_batchbuffer(ibatch);
244 drm_intel_gem_bo_clear_relocs(batch->bo, ibatch->reloc_count_start);
245 ibatch->ptr = ibatch->ptr_start;
246 }
247
i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys * idws)248 void i915_drm_winsys_init_batchbuffer_functions(struct i915_drm_winsys *idws)
249 {
250 idws->base.batchbuffer_create = i915_drm_batchbuffer_create;
251 idws->base.validate_buffers = i915_drm_batchbuffer_validate_buffers;
252 idws->base.batchbuffer_reloc = i915_drm_batchbuffer_reloc;
253 idws->base.batchbuffer_flush = i915_drm_batchbuffer_flush;
254 idws->base.batchbuffer_destroy = i915_drm_batchbuffer_destroy;
255 idws->base.emit_start = i915_drm_batchbuffer_emit_start;
256 idws->base.emit_restart = i915_drm_batchbuffer_emit_restart;
257 }
258