ilo: Support DRI Image 7
[mesa.git] / src / gallium / winsys / intel / drm / intel_drm_winsys.c
1 /*
2 * Mesa 3-D graphics library
3 *
4 * Copyright (C) 2012-2013 LunarG, Inc.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *
24 * Authors:
25 * Chia-I Wu <olv@lunarg.com>
26 */
27
28 #include <string.h>
29 #include <errno.h>
30 #ifndef ETIME
31 #define ETIME ETIMEDOUT
32 #endif
33
34 #include <xf86drm.h>
35 #include <i915_drm.h>
36 #include <intel_bufmgr.h>
37
38 #include "state_tracker/drm_driver.h"
39 #include "pipe/p_state.h"
40 #include "util/u_inlines.h"
41 #include "util/u_memory.h"
42 #include "util/u_debug.h"
43 #include "../intel_winsys.h"
44
45 #define BATCH_SZ (8192 * sizeof(uint32_t))
46
47 struct intel_winsys {
48 int fd;
49 drm_intel_bufmgr *bufmgr;
50 struct intel_winsys_info info;
51
52 struct drm_intel_decode *decode;
53 };
54
55 static bool
56 get_param(struct intel_winsys *winsys, int param, int *value)
57 {
58 struct drm_i915_getparam gp;
59 int err;
60
61 *value = 0;
62
63 memset(&gp, 0, sizeof(gp));
64 gp.param = param;
65 gp.value = value;
66
67 err = drmCommandWriteRead(winsys->fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
68 if (err) {
69 *value = 0;
70 return false;
71 }
72
73 return true;
74 }
75
76 static bool
77 test_address_swizzling(struct intel_winsys *winsys)
78 {
79 drm_intel_bo *bo;
80 uint32_t tiling = I915_TILING_X, swizzle;
81 unsigned long pitch;
82
83 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr,
84 "address swizzling test", 64, 64, 4, &tiling, &pitch, 0);
85 if (bo) {
86 drm_intel_bo_get_tiling(bo, &tiling, &swizzle);
87 drm_intel_bo_unreference(bo);
88 }
89 else {
90 swizzle = I915_BIT_6_SWIZZLE_NONE;
91 }
92
93 return (swizzle != I915_BIT_6_SWIZZLE_NONE);
94 }
95
96 static bool
97 init_info(struct intel_winsys *winsys)
98 {
99 struct intel_winsys_info *info = &winsys->info;
100 int val;
101
102 /* follow the classic driver here */
103 get_param(winsys, I915_PARAM_HAS_RELAXED_DELTA, &val);
104 if (!val) {
105 debug_error("kernel 2.6.39 required");
106 return false;
107 }
108
109 info->devid = drm_intel_bufmgr_gem_get_devid(winsys->bufmgr);
110
111 get_param(winsys, I915_PARAM_HAS_LLC, &val);
112 info->has_llc = val;
113
114 get_param(winsys, I915_PARAM_HAS_GEN7_SOL_RESET, &val);
115 info->has_gen7_sol_reset = val;
116
117 info->has_address_swizzling = test_address_swizzling(winsys);
118
119 return true;
120 }
121
122 struct intel_winsys *
123 intel_winsys_create_for_fd(int fd)
124 {
125 struct intel_winsys *winsys;
126
127 winsys = CALLOC_STRUCT(intel_winsys);
128 if (!winsys)
129 return NULL;
130
131 winsys->fd = fd;
132
133 winsys->bufmgr = drm_intel_bufmgr_gem_init(winsys->fd, BATCH_SZ);
134 if (!winsys->bufmgr) {
135 debug_error("failed to create GEM buffer manager");
136 FREE(winsys);
137 return NULL;
138 }
139
140 if (!init_info(winsys)) {
141 drm_intel_bufmgr_destroy(winsys->bufmgr);
142 FREE(winsys);
143 return NULL;
144 }
145
146 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys->bufmgr);
147
148 return winsys;
149 }
150
151 void
152 intel_winsys_destroy(struct intel_winsys *winsys)
153 {
154 if (winsys->decode)
155 drm_intel_decode_context_free(winsys->decode);
156
157 drm_intel_bufmgr_destroy(winsys->bufmgr);
158 FREE(winsys);
159 }
160
161 const struct intel_winsys_info *
162 intel_winsys_get_info(const struct intel_winsys *winsys)
163 {
164 return &winsys->info;
165 }
166
167 void
168 intel_winsys_enable_reuse(struct intel_winsys *winsys)
169 {
170 drm_intel_bufmgr_gem_enable_reuse(winsys->bufmgr);
171 }
172
173 struct intel_context *
174 intel_winsys_create_context(struct intel_winsys *winsys)
175 {
176 return (struct intel_context *)
177 drm_intel_gem_context_create(winsys->bufmgr);
178 }
179
180 void
181 intel_winsys_destroy_context(struct intel_winsys *winsys,
182 struct intel_context *ctx)
183 {
184 drm_intel_gem_context_destroy((drm_intel_context *) ctx);
185 }
186
187 int
188 intel_winsys_read_reg(struct intel_winsys *winsys,
189 uint32_t reg, uint64_t *val)
190 {
191 return drm_intel_reg_read(winsys->bufmgr, reg, val);
192 }
193
194 struct intel_bo *
195 intel_winsys_alloc_buffer(struct intel_winsys *winsys,
196 const char *name,
197 unsigned long size,
198 unsigned long flags)
199 {
200 const int alignment = 4096; /* always page-aligned */
201 drm_intel_bo *bo;
202
203 if (flags == INTEL_ALLOC_FOR_RENDER) {
204 bo = drm_intel_bo_alloc_for_render(winsys->bufmgr,
205 name, size, alignment);
206 }
207 else {
208 assert(!flags);
209 bo = drm_intel_bo_alloc(winsys->bufmgr, name, size, alignment);
210 }
211
212 return (struct intel_bo *) bo;
213 }
214
215 struct intel_bo *
216 intel_winsys_alloc_texture(struct intel_winsys *winsys,
217 const char *name,
218 int width, int height, int cpp,
219 enum intel_tiling_mode tiling,
220 unsigned long flags,
221 unsigned long *pitch)
222 {
223 uint32_t real_tiling = tiling;
224 drm_intel_bo *bo;
225
226 bo = drm_intel_bo_alloc_tiled(winsys->bufmgr, name,
227 width, height, cpp, &real_tiling, pitch, flags);
228 if (!bo)
229 return NULL;
230
231 if (real_tiling != tiling) {
232 assert(!"tiling mismatch");
233 drm_intel_bo_unreference(bo);
234 return NULL;
235 }
236
237 return (struct intel_bo *) bo;
238 }
239
240 struct intel_bo *
241 intel_winsys_import_handle(struct intel_winsys *winsys,
242 const char *name,
243 const struct winsys_handle *handle,
244 int width, int height, int cpp,
245 enum intel_tiling_mode *tiling,
246 unsigned long *pitch)
247 {
248 uint32_t real_tiling, swizzle;
249 drm_intel_bo *bo;
250 int err;
251
252 switch (handle->type) {
253 case DRM_API_HANDLE_TYPE_SHARED:
254 {
255 const uint32_t gem_name = handle->handle;
256 bo = drm_intel_bo_gem_create_from_name(winsys->bufmgr,
257 name, gem_name);
258 }
259 break;
260 case DRM_API_HANDLE_TYPE_FD:
261 {
262 const int fd = (int) handle->handle;
263 bo = drm_intel_bo_gem_create_from_prime(winsys->bufmgr,
264 fd, height * handle->stride);
265 }
266 break;
267 default:
268 bo = NULL;
269 break;
270 }
271
272 if (!bo)
273 return NULL;
274
275 err = drm_intel_bo_get_tiling(bo, &real_tiling, &swizzle);
276 if (err) {
277 drm_intel_bo_unreference(bo);
278 return NULL;
279 }
280
281 *tiling = real_tiling;
282 *pitch = handle->stride;
283
284 return (struct intel_bo *) bo;
285 }
286
287 int
288 intel_winsys_export_handle(struct intel_winsys *winsys,
289 struct intel_bo *bo,
290 enum intel_tiling_mode tiling,
291 unsigned long pitch,
292 struct winsys_handle *handle)
293 {
294 int err = 0;
295
296 switch (handle->type) {
297 case DRM_API_HANDLE_TYPE_SHARED:
298 {
299 uint32_t name;
300
301 err = drm_intel_bo_flink((drm_intel_bo *) bo, &name);
302 if (!err)
303 handle->handle = name;
304 }
305 break;
306 case DRM_API_HANDLE_TYPE_KMS:
307 handle->handle = ((drm_intel_bo *) bo)->handle;
308 break;
309 #if 0
310 case DRM_API_HANDLE_TYPE_FD:
311 {
312 int fd;
313
314 err = drm_intel_bo_gem_export_to_prime((drm_intel_bo *) bo, &fd);
315 if (!err)
316 handle->handle = fd;
317 }
318 break;
319 #endif
320 default:
321 err = -EINVAL;
322 break;
323 }
324
325 if (err)
326 return err;
327
328 handle->stride = pitch;
329
330 return 0;
331 }
332
333 int
334 intel_winsys_check_aperture_space(struct intel_winsys *winsys,
335 struct intel_bo **bo_array,
336 int count)
337 {
338 return drm_intel_bufmgr_check_aperture_space((drm_intel_bo **) bo_array,
339 count);
340 }
341
342 void
343 intel_winsys_decode_commands(struct intel_winsys *winsys,
344 struct intel_bo *bo, int used)
345 {
346 int err;
347
348 if (!winsys->decode) {
349 winsys->decode = drm_intel_decode_context_alloc(winsys->info.devid);
350 if (!winsys->decode)
351 return;
352
353 /* debug_printf()/debug_error() uses stderr by default */
354 drm_intel_decode_set_output_file(winsys->decode, stderr);
355 }
356
357 err = intel_bo_map(bo, false);
358 if (err) {
359 debug_printf("failed to map buffer for decoding\n");
360 return;
361 }
362
363 /* in dwords */
364 used /= 4;
365
366 drm_intel_decode_set_batch_pointer(winsys->decode,
367 intel_bo_get_virtual(bo), intel_bo_get_offset(bo), used);
368
369 drm_intel_decode(winsys->decode);
370
371 intel_bo_unmap(bo);
372 }
373
374 void
375 intel_bo_reference(struct intel_bo *bo)
376 {
377 drm_intel_bo_reference((drm_intel_bo *) bo);
378 }
379
380 void
381 intel_bo_unreference(struct intel_bo *bo)
382 {
383 drm_intel_bo_unreference((drm_intel_bo *) bo);
384 }
385
386 unsigned long
387 intel_bo_get_size(const struct intel_bo *bo)
388 {
389 return ((drm_intel_bo *) bo)->size;
390 }
391
392 unsigned long
393 intel_bo_get_offset(const struct intel_bo *bo)
394 {
395 return ((drm_intel_bo *) bo)->offset;
396 }
397
398 void *
399 intel_bo_get_virtual(const struct intel_bo *bo)
400 {
401 return ((drm_intel_bo *) bo)->virtual;
402 }
403
404 int
405 intel_bo_map(struct intel_bo *bo, bool write_enable)
406 {
407 return drm_intel_bo_map((drm_intel_bo *) bo, write_enable);
408 }
409
410 int
411 intel_bo_map_gtt(struct intel_bo *bo)
412 {
413 return drm_intel_gem_bo_map_gtt((drm_intel_bo *) bo);
414 }
415
416 int
417 intel_bo_map_unsynchronized(struct intel_bo *bo)
418 {
419 return drm_intel_gem_bo_map_unsynchronized((drm_intel_bo *) bo);
420 }
421
422 void
423 intel_bo_unmap(struct intel_bo *bo)
424 {
425 int err;
426
427 err = drm_intel_bo_unmap((drm_intel_bo *) bo);
428 assert(!err);
429 }
430
431 int
432 intel_bo_pwrite(struct intel_bo *bo, unsigned long offset,
433 unsigned long size, const void *data)
434 {
435 return drm_intel_bo_subdata((drm_intel_bo *) bo, offset, size, data);
436 }
437
438 int
439 intel_bo_pread(struct intel_bo *bo, unsigned long offset,
440 unsigned long size, void *data)
441 {
442 return drm_intel_bo_get_subdata((drm_intel_bo *) bo, offset, size, data);
443 }
444
445 int
446 intel_bo_emit_reloc(struct intel_bo *bo, uint32_t offset,
447 struct intel_bo *target_bo, uint32_t target_offset,
448 uint32_t read_domains, uint32_t write_domain)
449 {
450 return drm_intel_bo_emit_reloc((drm_intel_bo *) bo, offset,
451 (drm_intel_bo *) target_bo, target_offset,
452 read_domains, write_domain);
453 }
454
455 int
456 intel_bo_get_reloc_count(struct intel_bo *bo)
457 {
458 return drm_intel_gem_bo_get_reloc_count((drm_intel_bo *) bo);
459 }
460
461 void
462 intel_bo_clear_relocs(struct intel_bo *bo, int start)
463 {
464 return drm_intel_gem_bo_clear_relocs((drm_intel_bo *) bo, start);
465 }
466
467 bool
468 intel_bo_references(struct intel_bo *bo, struct intel_bo *target_bo)
469 {
470 return drm_intel_bo_references((drm_intel_bo *) bo,
471 (drm_intel_bo *) target_bo);
472 }
473
474 int
475 intel_bo_exec(struct intel_bo *bo, int used,
476 struct intel_context *ctx, unsigned long flags)
477 {
478 if (ctx) {
479 return drm_intel_gem_bo_context_exec((drm_intel_bo *) bo,
480 (drm_intel_context *) ctx, used, flags);
481 }
482 else {
483 return drm_intel_bo_mrb_exec((drm_intel_bo *) bo,
484 used, NULL, 0, 0, flags);
485 }
486 }
487
488 int
489 intel_bo_wait(struct intel_bo *bo, int64_t timeout)
490 {
491 int err;
492
493 err = drm_intel_gem_bo_wait((drm_intel_bo *) bo, timeout);
494 /* consider the bo idle on errors */
495 if (err && err != -ETIME)
496 err = 0;
497
498 return err;
499 }