5312865a039ef9d20b03ffc2ac1baacb9ca94849
[mesa.git] / src / gallium / winsys / drm / intel / gem / intel_be_device.c
1
2 #include "intel_be_device.h"
3
4 #include "pipe/internal/p_winsys_screen.h"
5 #include "pipe/p_defines.h"
6 #include "pipe/p_state.h"
7 #include "pipe/p_inlines.h"
8 #include "util/u_memory.h"
9 #include "util/u_debug.h"
10 #include "util/u_math.h"
11
12 #include "intel_be_fence.h"
13
14 #include "i915simple/i915_winsys.h"
15 #include "softpipe/sp_winsys.h"
16
17 #include "intel_be_api.h"
18 #include <stdio.h>
19
20 #define I915_TILING_X 1
21
22 /*
23 * Buffer
24 */
25
26 static void *
27 intel_be_buffer_map(struct pipe_winsys *winsys,
28 struct pipe_buffer *buf,
29 unsigned flags)
30 {
31 struct intel_be_buffer *buffer = intel_be_buffer(buf);
32 drm_intel_bo *bo = intel_bo(buf);
33 int write = 0;
34 int ret = 0;
35
36 if (flags & PIPE_BUFFER_USAGE_DONTBLOCK) {
37 /* Remove this when drm_intel_bo_map supports DONTBLOCK
38 */
39 return NULL;
40 }
41
42 if (flags & PIPE_BUFFER_USAGE_CPU_WRITE)
43 write = 1;
44
45 if (buffer->map_count)
46 goto out;
47
48 if (buffer->map_gtt)
49 ret = drm_intel_gem_bo_map_gtt(bo);
50 else
51 ret = drm_intel_bo_map(bo, write);
52
53 buffer->ptr = bo->virtual;
54
55 out:
56 if (ret)
57 return NULL;
58
59 buffer->map_count++;
60 return buffer->ptr;
61 }
62
63 static void
64 intel_be_buffer_unmap(struct pipe_winsys *winsys,
65 struct pipe_buffer *buf)
66 {
67 struct intel_be_buffer *buffer = intel_be_buffer(buf);
68
69 if (--buffer->map_count)
70 return;
71
72 if (buffer->map_gtt)
73 drm_intel_gem_bo_unmap_gtt(intel_bo(buf));
74 else
75 drm_intel_bo_unmap(intel_bo(buf));
76 }
77
78 static void
79 intel_be_buffer_destroy(struct pipe_buffer *buf)
80 {
81 drm_intel_bo_unreference(intel_bo(buf));
82 free(buf);
83 }
84
85 static struct pipe_buffer *
86 intel_be_buffer_create(struct pipe_winsys *winsys,
87 unsigned alignment,
88 unsigned usage,
89 unsigned size)
90 {
91 struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer);
92 struct intel_be_device *dev = intel_be_device(winsys);
93 drm_intel_bufmgr *pool;
94 char *name;
95
96 if (!buffer)
97 return NULL;
98
99 pipe_reference_init(&buffer->base.reference, 1);
100 buffer->base.alignment = alignment;
101 buffer->base.usage = usage;
102 buffer->base.size = size;
103 buffer->flinked = FALSE;
104 buffer->flink = 0;
105 buffer->map_gtt = FALSE;
106
107 if (usage & I915_BUFFER_USAGE_SCANOUT) {
108 /* Scanout buffer */
109 name = "gallium3d_scanout";
110 pool = dev->pools.gem;
111 } else if (usage & (PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_CONSTANT)) {
112 /* Local buffer */
113 name = "gallium3d_local";
114 pool = dev->pools.gem;
115 } else if (usage & PIPE_BUFFER_USAGE_CUSTOM) {
116 /* For vertex buffers */
117 name = "gallium3d_internal_vertex";
118 pool = dev->pools.gem;
119 } else {
120 /* Regular buffers */
121 name = "gallium3d_regular";
122 pool = dev->pools.gem;
123 }
124
125 buffer->bo = drm_intel_bo_alloc(pool, name, size, alignment);
126 if (usage & I915_BUFFER_USAGE_SCANOUT) {
127 unsigned tiling = I915_TILING_X;
128 unsigned stride = 2048 * 4; /* TODO do something smarter here */
129 drm_intel_bo_set_tiling(buffer->bo, &tiling, stride);
130 buffer->map_gtt = TRUE;
131 }
132
133 if (!buffer->bo)
134 goto err;
135
136 return &buffer->base;
137
138 err:
139 free(buffer);
140 return NULL;
141 }
142
143 static struct pipe_buffer *
144 intel_be_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes)
145 {
146 struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer);
147 struct intel_be_device *dev = intel_be_device(winsys);
148 int ret;
149
150 if (!buffer)
151 return NULL;
152
153 pipe_reference_init(&buffer->base.reference, 1);
154 buffer->base.alignment = 0;
155 buffer->base.usage = 0;
156 buffer->base.size = bytes;
157
158 buffer->bo = drm_intel_bo_alloc(dev->pools.gem,
159 "gallium3d_user_buffer",
160 bytes, 0);
161
162 if (!buffer->bo)
163 goto err;
164
165 ret = drm_intel_bo_subdata(buffer->bo,
166 0, bytes, ptr);
167
168 if (ret)
169 goto err;
170
171 return &buffer->base;
172
173 err:
174 free(buffer);
175 return NULL;
176 }
177
178 static struct pipe_buffer *
179 intel_be_surface_buffer_create(struct pipe_winsys *winsys,
180 unsigned width, unsigned height,
181 enum pipe_format format,
182 unsigned usage,
183 unsigned tex_usage,
184 unsigned *stride)
185 {
186 struct pipe_format_block block;
187 unsigned buf_usage = 0;
188 unsigned buf_stride = 0;
189 unsigned buf_size = 0;
190
191 pf_get_block(format, &block);
192 buf_stride = pf_get_stride(&block, width);
193 buf_stride = align(buf_stride, 64);
194
195 if (tex_usage & PIPE_TEXTURE_USAGE_PRIMARY) {
196 /* TODO more checks */
197 assert(buf_stride <= 2048*4);
198 assert(height % 8 == 0);
199 buf_stride = 2048 * 4;
200 buf_usage |= I915_BUFFER_USAGE_SCANOUT;
201 }
202
203 buf_size = buf_stride * height;
204 *stride = buf_stride;
205
206 return intel_be_buffer_create(winsys,
207 0,
208 buf_usage,
209 buf_size);
210 }
211
212 boolean
213 intel_be_get_texture_buffer(struct drm_api *api,
214 struct pipe_texture *texture,
215 struct pipe_buffer **buffer,
216 unsigned *stride)
217 {
218 struct intel_be_device *dev;
219
220 if (!texture)
221 return FALSE;
222
223 dev = intel_be_device(texture->screen->winsys);
224 if (dev->softpipe)
225 return softpipe_get_texture_buffer(texture, buffer, stride);
226 else
227 return i915_get_texture_buffer(texture, buffer, stride);
228 }
229
230 struct pipe_buffer *
231 intel_be_buffer_from_handle(struct drm_api *api,
232 struct pipe_screen *screen,
233 const char* name, unsigned handle)
234 {
235 struct intel_be_device *dev = intel_be_device(screen->winsys);
236 struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer);
237
238 if (!buffer)
239 return NULL;
240
241 buffer->bo = drm_intel_bo_gem_create_from_name(dev->pools.gem, name, handle);
242
243 if (!buffer->bo)
244 goto err;
245
246 pipe_reference_init(&buffer->base.reference, 1);
247 buffer->base.screen = screen;
248 buffer->base.alignment = buffer->bo->align;
249 buffer->base.usage = PIPE_BUFFER_USAGE_GPU_READ |
250 PIPE_BUFFER_USAGE_GPU_WRITE |
251 PIPE_BUFFER_USAGE_CPU_READ |
252 PIPE_BUFFER_USAGE_CPU_WRITE;
253 buffer->base.size = buffer->bo->size;
254
255 return &buffer->base;
256
257 err:
258 free(buffer);
259 return NULL;
260 }
261
262 boolean
263 intel_be_handle_from_buffer(struct drm_api *api,
264 struct pipe_screen *screen,
265 struct pipe_buffer *buffer,
266 unsigned *handle)
267 {
268 if (!buffer)
269 return FALSE;
270
271 *handle = intel_bo(buffer)->handle;
272 return TRUE;
273 }
274
275 boolean
276 intel_be_global_handle_from_buffer(struct drm_api *api,
277 struct pipe_screen *screen,
278 struct pipe_buffer *buffer,
279 unsigned *handle)
280 {
281 struct intel_be_buffer *buf = intel_be_buffer(buffer);
282
283 if (!buffer)
284 return FALSE;
285
286 if (!buf->flinked) {
287 if (drm_intel_bo_flink(intel_bo(buffer), &buf->flink))
288 return FALSE;
289 buf->flinked = TRUE;
290 }
291
292 *handle = buf->flink;
293 return TRUE;
294 }
295
296 /*
297 * Fence
298 */
299
300 static void
301 intel_be_fence_refunref(struct pipe_winsys *sws,
302 struct pipe_fence_handle **ptr,
303 struct pipe_fence_handle *fence)
304 {
305 struct intel_be_fence **p = (struct intel_be_fence **)ptr;
306 struct intel_be_fence *f = (struct intel_be_fence *)fence;
307
308 intel_be_fence_reference(p, f);
309 }
310
311 static int
312 intel_be_fence_signalled(struct pipe_winsys *sws,
313 struct pipe_fence_handle *fence,
314 unsigned flag)
315 {
316 assert(0);
317
318 return 0;
319 }
320
321 static int
322 intel_be_fence_finish(struct pipe_winsys *sws,
323 struct pipe_fence_handle *fence,
324 unsigned flag)
325 {
326 struct intel_be_fence *f = (struct intel_be_fence *)fence;
327
328 /* fence already expired */
329 if (!f->bo)
330 return 0;
331
332 drm_intel_bo_wait_rendering(f->bo);
333 drm_intel_bo_unreference(f->bo);
334 f->bo = NULL;
335
336 return 0;
337 }
338
339 /*
340 * Misc functions
341 */
342
343 static void
344 intel_be_destroy_winsys(struct pipe_winsys *winsys)
345 {
346 struct intel_be_device *dev = intel_be_device(winsys);
347
348 drm_intel_bufmgr_destroy(dev->pools.gem);
349
350 free(dev);
351 }
352
353 boolean
354 intel_be_init_device(struct intel_be_device *dev, int fd, unsigned id)
355 {
356 dev->fd = fd;
357 dev->id = id;
358 dev->max_batch_size = 16 * 4096;
359 dev->max_vertex_size = 128 * 4096;
360
361 dev->base.buffer_create = intel_be_buffer_create;
362 dev->base.user_buffer_create = intel_be_user_buffer_create;
363 dev->base.buffer_map = intel_be_buffer_map;
364 dev->base.buffer_unmap = intel_be_buffer_unmap;
365 dev->base.buffer_destroy = intel_be_buffer_destroy;
366
367 /* Used by softpipe */
368 dev->base.surface_buffer_create = intel_be_surface_buffer_create;
369
370 dev->base.fence_reference = intel_be_fence_refunref;
371 dev->base.fence_signalled = intel_be_fence_signalled;
372 dev->base.fence_finish = intel_be_fence_finish;
373
374 dev->base.destroy = intel_be_destroy_winsys;
375
376 dev->pools.gem = drm_intel_bufmgr_gem_init(dev->fd, dev->max_batch_size);
377
378 dev->softpipe = debug_get_bool_option("INTEL_SOFTPIPE", FALSE);
379 dev->dump_cmd = debug_get_bool_option("INTEL_DUMP_CMD", FALSE);
380
381 return true;
382 }
383
384 static void
385 intel_be_get_device_id(unsigned int *device_id)
386 {
387 char path[512];
388 FILE *file;
389 void *shutup_gcc;
390
391 /*
392 * FIXME: Fix this up to use a drm ioctl or whatever.
393 */
394
395 snprintf(path, sizeof(path), "/sys/class/drm/card0/device/device");
396 file = fopen(path, "r");
397 if (!file) {
398 return;
399 }
400
401 shutup_gcc = fgets(path, sizeof(path), file);
402 sscanf(path, "%x", device_id);
403 fclose(file);
404 }
405
406 struct pipe_screen *
407 intel_be_create_screen(struct drm_api *api, int drmFD,
408 struct drm_create_screen_arg *arg)
409 {
410 struct intel_be_device *dev;
411 struct pipe_screen *screen;
412 unsigned int deviceID;
413
414 if (arg != NULL) {
415 switch(arg->mode) {
416 case DRM_CREATE_NORMAL:
417 break;
418 default:
419 return NULL;
420 }
421 }
422
423 /* Allocate the private area */
424 dev = malloc(sizeof(*dev));
425 if (!dev)
426 return NULL;
427 memset(dev, 0, sizeof(*dev));
428
429 intel_be_get_device_id(&deviceID);
430 intel_be_init_device(dev, drmFD, deviceID);
431
432 if (dev->softpipe) {
433 screen = softpipe_create_screen(&dev->base);
434 } else
435 screen = i915_create_screen(&dev->base, deviceID);
436
437 return screen;
438 }