2 * Mesa 3-D graphics library
4 * Copyright (C) 2012-2014 LunarG, Inc.
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:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
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.
25 * Chia-I Wu <olv@lunarg.com>
31 #define ETIME ETIMEDOUT
36 #include <intel_bufmgr.h>
38 #include "os/os_thread.h"
39 #include "state_tracker/drm_driver.h"
40 #include "pipe/p_state.h"
41 #include "util/u_inlines.h"
42 #include "util/u_memory.h"
43 #include "util/u_debug.h"
44 #include "../intel_winsys.h"
46 #define BATCH_SZ (8192 * sizeof(uint32_t))
50 drm_intel_bufmgr
*bufmgr
;
51 struct intel_winsys_info info
;
52 unsigned long exec_flags
;
54 /* these are protected by the mutex */
56 struct drm_intel_decode
*decode
;
60 gem_bo(const struct intel_bo
*bo
)
62 return (drm_intel_bo
*) bo
;
66 get_param(struct intel_winsys
*winsys
, int param
, int *value
)
68 struct drm_i915_getparam gp
;
73 memset(&gp
, 0, sizeof(gp
));
77 err
= drmCommandWriteRead(winsys
->fd
, DRM_I915_GETPARAM
, &gp
, sizeof(gp
));
87 test_address_swizzling(struct intel_winsys
*winsys
)
90 uint32_t tiling
= I915_TILING_X
, swizzle
;
93 bo
= drm_intel_bo_alloc_tiled(winsys
->bufmgr
,
94 "address swizzling test", 64, 64, 4, &tiling
, &pitch
, 0);
96 drm_intel_bo_get_tiling(bo
, &tiling
, &swizzle
);
97 drm_intel_bo_unreference(bo
);
100 swizzle
= I915_BIT_6_SWIZZLE_NONE
;
103 return (swizzle
!= I915_BIT_6_SWIZZLE_NONE
);
107 test_reg_read(struct intel_winsys
*winsys
, uint32_t reg
)
111 return !drm_intel_reg_read(winsys
->bufmgr
, reg
, &dummy
);
115 probe_winsys(struct intel_winsys
*winsys
)
117 struct intel_winsys_info
*info
= &winsys
->info
;
121 * When we need the Nth vertex from a user vertex buffer, and the vertex is
122 * uploaded to, say, the beginning of a bo, we want the first vertex in the
123 * bo to be fetched. One way to do this is to set the base address of the
126 * bo->offset64 + (vb->buffer_offset - vb->stride * N).
128 * The second term may be negative, and we need kernel support to do that.
130 * This check is taken from the classic driver. u_vbuf_upload_buffers()
131 * guarantees the term is never negative, but it is good to require a
134 get_param(winsys
, I915_PARAM_HAS_RELAXED_DELTA
, &val
);
136 debug_error("kernel 2.6.39 required");
140 info
->devid
= drm_intel_bufmgr_gem_get_devid(winsys
->bufmgr
);
142 info
->max_batch_size
= BATCH_SZ
;
144 get_param(winsys
, I915_PARAM_HAS_LLC
, &val
);
146 info
->has_address_swizzling
= test_address_swizzling(winsys
);
148 /* test TIMESTAMP read */
149 info
->has_timestamp
= test_reg_read(winsys
, 0x2358);
151 get_param(winsys
, I915_PARAM_HAS_GEN7_SOL_RESET
, &val
);
152 info
->has_gen7_sol_reset
= val
;
155 * pipe drivers are expected to write the presumed offsets after adding
158 get_param(winsys
, I915_PARAM_HAS_EXEC_NO_RELOC
, &val
);
160 winsys
->exec_flags
|= I915_EXEC_NO_RELOC
;
165 struct intel_winsys
*
166 intel_winsys_create_for_fd(int fd
)
168 struct intel_winsys
*winsys
;
170 winsys
= CALLOC_STRUCT(intel_winsys
);
176 winsys
->bufmgr
= drm_intel_bufmgr_gem_init(winsys
->fd
, BATCH_SZ
);
177 if (!winsys
->bufmgr
) {
178 debug_error("failed to create GEM buffer manager");
183 pipe_mutex_init(winsys
->mutex
);
185 if (!probe_winsys(winsys
)) {
186 drm_intel_bufmgr_destroy(winsys
->bufmgr
);
192 * No need to implicitly set up a fence register for each non-linear reloc
193 * entry. When a fence register is needed for a reloc entry,
194 * drm_intel_bo_emit_reloc_fence() will be called explicitly.
196 * intel_bo_add_reloc() currently lacks "bool fenced" for this to work.
197 * But we never need a fence register on GEN4+ so we do not need to worry
200 drm_intel_bufmgr_gem_enable_fenced_relocs(winsys
->bufmgr
);
202 drm_intel_bufmgr_gem_enable_reuse(winsys
->bufmgr
);
208 intel_winsys_destroy(struct intel_winsys
*winsys
)
211 drm_intel_decode_context_free(winsys
->decode
);
213 pipe_mutex_destroy(winsys
->mutex
);
214 drm_intel_bufmgr_destroy(winsys
->bufmgr
);
218 const struct intel_winsys_info
*
219 intel_winsys_get_info(const struct intel_winsys
*winsys
)
221 return &winsys
->info
;
224 struct intel_context
*
225 intel_winsys_create_context(struct intel_winsys
*winsys
)
227 return (struct intel_context
*)
228 drm_intel_gem_context_create(winsys
->bufmgr
);
232 intel_winsys_destroy_context(struct intel_winsys
*winsys
,
233 struct intel_context
*ctx
)
235 drm_intel_gem_context_destroy((drm_intel_context
*) ctx
);
239 intel_winsys_read_reg(struct intel_winsys
*winsys
,
240 uint32_t reg
, uint64_t *val
)
242 return drm_intel_reg_read(winsys
->bufmgr
, reg
, val
);
246 intel_winsys_alloc_buffer(struct intel_winsys
*winsys
,
249 uint32_t initial_domain
)
251 const bool for_render
=
252 (initial_domain
& (INTEL_DOMAIN_RENDER
| INTEL_DOMAIN_INSTRUCTION
));
253 const int alignment
= 4096; /* always page-aligned */
257 bo
= drm_intel_bo_alloc_for_render(winsys
->bufmgr
,
258 name
, size
, alignment
);
261 bo
= drm_intel_bo_alloc(winsys
->bufmgr
, name
, size
, alignment
);
264 return (struct intel_bo
*) bo
;
268 intel_winsys_alloc_texture(struct intel_winsys
*winsys
,
270 int width
, int height
, int cpp
,
271 enum intel_tiling_mode tiling
,
272 uint32_t initial_domain
,
273 unsigned long *pitch
)
275 const unsigned long flags
=
276 (initial_domain
& (INTEL_DOMAIN_RENDER
| INTEL_DOMAIN_INSTRUCTION
)) ?
277 BO_ALLOC_FOR_RENDER
: 0;
278 uint32_t real_tiling
= tiling
;
281 bo
= drm_intel_bo_alloc_tiled(winsys
->bufmgr
, name
,
282 width
, height
, cpp
, &real_tiling
, pitch
, flags
);
286 if (real_tiling
!= tiling
) {
287 assert(!"tiling mismatch");
288 drm_intel_bo_unreference(bo
);
292 return (struct intel_bo
*) bo
;
296 intel_winsys_import_handle(struct intel_winsys
*winsys
,
298 const struct winsys_handle
*handle
,
299 int width
, int height
, int cpp
,
300 enum intel_tiling_mode
*tiling
,
301 unsigned long *pitch
)
303 uint32_t real_tiling
, swizzle
;
307 switch (handle
->type
) {
308 case DRM_API_HANDLE_TYPE_SHARED
:
310 const uint32_t gem_name
= handle
->handle
;
311 bo
= drm_intel_bo_gem_create_from_name(winsys
->bufmgr
,
315 case DRM_API_HANDLE_TYPE_FD
:
317 const int fd
= (int) handle
->handle
;
318 bo
= drm_intel_bo_gem_create_from_prime(winsys
->bufmgr
,
319 fd
, height
* handle
->stride
);
330 err
= drm_intel_bo_get_tiling(bo
, &real_tiling
, &swizzle
);
332 drm_intel_bo_unreference(bo
);
336 *tiling
= real_tiling
;
337 *pitch
= handle
->stride
;
339 return (struct intel_bo
*) bo
;
343 intel_winsys_export_handle(struct intel_winsys
*winsys
,
345 enum intel_tiling_mode tiling
,
347 struct winsys_handle
*handle
)
351 switch (handle
->type
) {
352 case DRM_API_HANDLE_TYPE_SHARED
:
356 err
= drm_intel_bo_flink(gem_bo(bo
), &name
);
358 handle
->handle
= name
;
361 case DRM_API_HANDLE_TYPE_KMS
:
362 handle
->handle
= gem_bo(bo
)->handle
;
364 case DRM_API_HANDLE_TYPE_FD
:
368 err
= drm_intel_bo_gem_export_to_prime(gem_bo(bo
), &fd
);
381 handle
->stride
= pitch
;
387 intel_winsys_can_submit_bo(struct intel_winsys
*winsys
,
388 struct intel_bo
**bo_array
,
391 return !drm_intel_bufmgr_check_aperture_space((drm_intel_bo
**) bo_array
,
396 intel_winsys_submit_bo(struct intel_winsys
*winsys
,
397 enum intel_ring_type ring
,
398 struct intel_bo
*bo
, int used
,
399 struct intel_context
*ctx
,
402 const unsigned long exec_flags
=
403 winsys
->exec_flags
| (unsigned long) ring
| flags
;
405 /* logical contexts are only available for the render ring */
406 if (ring
!= INTEL_RING_RENDER
)
410 return drm_intel_gem_bo_context_exec(gem_bo(bo
),
411 (drm_intel_context
*) ctx
, used
, exec_flags
);
414 return drm_intel_bo_mrb_exec(gem_bo(bo
),
415 used
, NULL
, 0, 0, exec_flags
);
420 intel_winsys_decode_bo(struct intel_winsys
*winsys
,
421 struct intel_bo
*bo
, int used
)
425 ptr
= intel_bo_map(bo
, false);
427 debug_printf("failed to map buffer for decoding\n");
431 pipe_mutex_lock(winsys
->mutex
);
433 if (!winsys
->decode
) {
434 winsys
->decode
= drm_intel_decode_context_alloc(winsys
->info
.devid
);
435 if (!winsys
->decode
) {
436 pipe_mutex_unlock(winsys
->mutex
);
441 /* debug_printf()/debug_error() uses stderr by default */
442 drm_intel_decode_set_output_file(winsys
->decode
, stderr
);
448 drm_intel_decode_set_batch_pointer(winsys
->decode
,
449 ptr
, gem_bo(bo
)->offset64
, used
);
451 drm_intel_decode(winsys
->decode
);
453 pipe_mutex_unlock(winsys
->mutex
);
459 intel_bo_reference(struct intel_bo
*bo
)
461 drm_intel_bo_reference(gem_bo(bo
));
465 intel_bo_unreference(struct intel_bo
*bo
)
467 drm_intel_bo_unreference(gem_bo(bo
));
471 intel_bo_map(struct intel_bo
*bo
, bool write_enable
)
475 err
= drm_intel_bo_map(gem_bo(bo
), write_enable
);
477 debug_error("failed to map bo");
481 return gem_bo(bo
)->virtual;
485 intel_bo_map_gtt(struct intel_bo
*bo
)
489 err
= drm_intel_gem_bo_map_gtt(gem_bo(bo
));
491 debug_error("failed to map bo");
495 return gem_bo(bo
)->virtual;
499 intel_bo_map_unsynchronized(struct intel_bo
*bo
)
503 err
= drm_intel_gem_bo_map_unsynchronized(gem_bo(bo
));
505 debug_error("failed to map bo");
509 return gem_bo(bo
)->virtual;
513 intel_bo_unmap(struct intel_bo
*bo
)
517 err
= drm_intel_bo_unmap(gem_bo(bo
));
522 intel_bo_pwrite(struct intel_bo
*bo
, unsigned long offset
,
523 unsigned long size
, const void *data
)
525 return drm_intel_bo_subdata(gem_bo(bo
), offset
, size
, data
);
529 intel_bo_pread(struct intel_bo
*bo
, unsigned long offset
,
530 unsigned long size
, void *data
)
532 return drm_intel_bo_get_subdata(gem_bo(bo
), offset
, size
, data
);
536 intel_bo_add_reloc(struct intel_bo
*bo
, uint32_t offset
,
537 struct intel_bo
*target_bo
, uint32_t target_offset
,
538 uint32_t read_domains
, uint32_t write_domain
,
539 uint64_t *presumed_offset
)
543 err
= drm_intel_bo_emit_reloc(gem_bo(bo
), offset
,
544 gem_bo(target_bo
), target_offset
,
545 read_domains
, write_domain
);
547 *presumed_offset
= gem_bo(target_bo
)->offset64
+ target_offset
;
553 intel_bo_get_reloc_count(struct intel_bo
*bo
)
555 return drm_intel_gem_bo_get_reloc_count(gem_bo(bo
));
559 intel_bo_truncate_relocs(struct intel_bo
*bo
, int start
)
561 drm_intel_gem_bo_clear_relocs(gem_bo(bo
), start
);
565 intel_bo_has_reloc(struct intel_bo
*bo
, struct intel_bo
*target_bo
)
567 return drm_intel_bo_references(gem_bo(bo
), gem_bo(target_bo
));
571 intel_bo_wait(struct intel_bo
*bo
, int64_t timeout
)
575 err
= drm_intel_gem_bo_wait(gem_bo(bo
), timeout
);
576 /* consider the bo idle on errors */
577 if (err
&& err
!= -ETIME
)