f58334ffffa4e64f454b92afc018cd76acc66ffc
[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 static struct pipe_buffer *
213 intel_be_buffer_from_handle(struct drm_api *api,
214 struct pipe_screen *screen,
215 const char* name, unsigned handle)
216 {
217 struct intel_be_device *dev = intel_be_device(screen->winsys);
218 struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer);
219
220 if (!buffer)
221 return NULL;
222
223 buffer->bo = drm_intel_bo_gem_create_from_name(dev->pools.gem, name, handle);
224
225 if (!buffer->bo)
226 goto err;
227
228 pipe_reference_init(&buffer->base.reference, 1);
229 buffer->base.screen = screen;
230 buffer->base.alignment = buffer->bo->align;
231 buffer->base.usage = PIPE_BUFFER_USAGE_GPU_READ |
232 PIPE_BUFFER_USAGE_GPU_WRITE |
233 PIPE_BUFFER_USAGE_CPU_READ |
234 PIPE_BUFFER_USAGE_CPU_WRITE;
235 buffer->base.size = buffer->bo->size;
236
237 return &buffer->base;
238
239 err:
240 free(buffer);
241 return NULL;
242 }
243
244 struct pipe_texture *
245 intel_be_texture_from_shared_handle(struct drm_api *api,
246 struct pipe_screen *screen,
247 struct pipe_texture *templ,
248 const char* name,
249 unsigned pitch,
250 unsigned handle)
251 {
252 struct pipe_buffer *buffer;
253
254 buffer = intel_be_buffer_from_handle(api,
255 screen,
256 name,
257 handle);
258 if (!buffer)
259 return NULL;
260
261 return screen->texture_blanket(screen, templ, &pitch, buffer);
262 }
263
264 static boolean
265 intel_be_get_texture_buffer(struct drm_api *api,
266 struct pipe_texture *texture,
267 struct pipe_buffer **buffer,
268 unsigned *stride)
269 {
270 struct intel_be_device *dev;
271
272 if (!texture)
273 return FALSE;
274
275 dev = intel_be_device(texture->screen->winsys);
276 if (dev->softpipe)
277 return softpipe_get_texture_buffer(texture, buffer, stride);
278 else
279 return i915_get_texture_buffer(texture, buffer, stride);
280 }
281
282 boolean
283 intel_be_shared_handle_from_texture(struct drm_api *api,
284 struct pipe_screen *screen,
285 struct pipe_texture *texture,
286 unsigned *pitch,
287 unsigned *handle)
288 {
289 struct pipe_buffer *buffer;
290 struct intel_be_buffer *buf;
291 if (!intel_be_get_texture_buffer(api,
292 texture,
293 &buffer,
294 pitch))
295 return FALSE;
296
297 buf = intel_be_buffer(buffer);
298 if (!buf->flinked) {
299 if (drm_intel_bo_flink(intel_bo(buffer), &buf->flink))
300 return FALSE;
301 buf->flinked = TRUE;
302 }
303
304 *handle = buf->flink;
305
306 pipe_buffer_reference(&buffer, NULL);
307
308 return TRUE;
309 }
310
311 boolean
312 intel_be_local_handle_from_texture(struct drm_api *api,
313 struct pipe_screen *screen,
314 struct pipe_texture *texture,
315 unsigned *pitch,
316 unsigned *handle)
317 {
318 struct pipe_buffer *buffer;
319 if (!intel_be_get_texture_buffer(api,
320 texture,
321 &buffer,
322 pitch))
323 return FALSE;
324
325 *handle = intel_bo(buffer)->handle;
326
327 pipe_buffer_reference(&buffer, NULL);
328
329 return TRUE;
330 }
331
332 /*
333 * Fence
334 */
335
336 static void
337 intel_be_fence_refunref(struct pipe_winsys *sws,
338 struct pipe_fence_handle **ptr,
339 struct pipe_fence_handle *fence)
340 {
341 struct intel_be_fence **p = (struct intel_be_fence **)ptr;
342 struct intel_be_fence *f = (struct intel_be_fence *)fence;
343
344 intel_be_fence_reference(p, f);
345 }
346
347 static int
348 intel_be_fence_signalled(struct pipe_winsys *sws,
349 struct pipe_fence_handle *fence,
350 unsigned flag)
351 {
352 assert(0);
353
354 return 0;
355 }
356
357 static int
358 intel_be_fence_finish(struct pipe_winsys *sws,
359 struct pipe_fence_handle *fence,
360 unsigned flag)
361 {
362 struct intel_be_fence *f = (struct intel_be_fence *)fence;
363
364 /* fence already expired */
365 if (!f->bo)
366 return 0;
367
368 drm_intel_bo_wait_rendering(f->bo);
369 drm_intel_bo_unreference(f->bo);
370 f->bo = NULL;
371
372 return 0;
373 }
374
375 /*
376 * Misc functions
377 */
378
379 static void
380 intel_be_destroy_winsys(struct pipe_winsys *winsys)
381 {
382 struct intel_be_device *dev = intel_be_device(winsys);
383
384 drm_intel_bufmgr_destroy(dev->pools.gem);
385
386 free(dev);
387 }
388
389 boolean
390 intel_be_init_device(struct intel_be_device *dev, int fd, unsigned id)
391 {
392 dev->fd = fd;
393 dev->id = id;
394 dev->max_batch_size = 16 * 4096;
395 dev->max_vertex_size = 128 * 4096;
396
397 dev->base.buffer_create = intel_be_buffer_create;
398 dev->base.user_buffer_create = intel_be_user_buffer_create;
399 dev->base.buffer_map = intel_be_buffer_map;
400 dev->base.buffer_unmap = intel_be_buffer_unmap;
401 dev->base.buffer_destroy = intel_be_buffer_destroy;
402
403 /* Used by softpipe */
404 dev->base.surface_buffer_create = intel_be_surface_buffer_create;
405
406 dev->base.fence_reference = intel_be_fence_refunref;
407 dev->base.fence_signalled = intel_be_fence_signalled;
408 dev->base.fence_finish = intel_be_fence_finish;
409
410 dev->base.destroy = intel_be_destroy_winsys;
411
412 dev->pools.gem = drm_intel_bufmgr_gem_init(dev->fd, dev->max_batch_size);
413
414 dev->softpipe = debug_get_bool_option("INTEL_SOFTPIPE", FALSE);
415 dev->dump_cmd = debug_get_bool_option("INTEL_DUMP_CMD", FALSE);
416
417 return true;
418 }
419
420 static void
421 intel_be_get_device_id(unsigned int *device_id)
422 {
423 char path[512];
424 FILE *file;
425 void *shutup_gcc;
426
427 /*
428 * FIXME: Fix this up to use a drm ioctl or whatever.
429 */
430
431 snprintf(path, sizeof(path), "/sys/class/drm/card0/device/device");
432 file = fopen(path, "r");
433 if (!file) {
434 return;
435 }
436
437 shutup_gcc = fgets(path, sizeof(path), file);
438 sscanf(path, "%x", device_id);
439 fclose(file);
440 }
441
442 struct pipe_screen *
443 intel_be_create_screen(struct drm_api *api, int drmFD,
444 struct drm_create_screen_arg *arg)
445 {
446 struct intel_be_device *dev;
447 struct pipe_screen *screen;
448 unsigned int deviceID;
449
450 if (arg != NULL) {
451 switch(arg->mode) {
452 case DRM_CREATE_NORMAL:
453 break;
454 default:
455 return NULL;
456 }
457 }
458
459 /* Allocate the private area */
460 dev = malloc(sizeof(*dev));
461 if (!dev)
462 return NULL;
463 memset(dev, 0, sizeof(*dev));
464
465 intel_be_get_device_id(&deviceID);
466 intel_be_init_device(dev, drmFD, deviceID);
467
468 if (dev->softpipe) {
469 screen = softpipe_create_screen(&dev->base);
470 } else
471 screen = i915_create_screen(&dev->base, deviceID);
472
473 return screen;
474 }