/* * Copyright (c) 2011 Intel Corporation * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice (including the next * paragraph) shall be included in all copies or substantial portions of the * Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Authors: * Chris Wilson * */ #include #include #include #include #ifndef KGEM_H #define KGEM_H struct kgem_bo { struct kgem_bo *proxy; struct list list; struct list request; struct kgem_request *rq; struct drm_i915_gem_exec_object2 *exec; uint16_t src_bound, dst_bound; uint32_t unique_id; uint32_t refcnt; uint32_t handle; uint32_t presumed_offset; uint32_t size; uint32_t aperture_size; uint32_t delta; uint32_t pitch : 16; uint32_t tiling : 2; uint32_t reusable : 1; uint32_t dirty : 1; uint32_t gpu : 1; uint32_t needs_flush : 1; uint32_t cpu_read : 1; uint32_t cpu_write : 1; uint32_t flush : 1; uint32_t sync : 1; uint32_t deleted : 1; }; struct kgem_request { struct list list; struct kgem_bo *bo; struct list buffers; }; struct kgem { int fd; int wedged; int gen; uint32_t unique_id; enum kgem_mode { /* order matches I915_EXEC_RING ordering */ KGEM_NONE = 0, KGEM_RENDER, KGEM_BSD, KGEM_BLT, } mode, ring; struct list active; struct list inactive[16]; struct list partial; struct list requests; struct kgem_request *next_request; uint16_t nbatch; uint16_t surface; uint16_t nexec; uint16_t nreloc; uint16_t nfence; uint32_t retire; uint32_t flush; uint32_t need_purge; uint32_t has_vmap :1; uint32_t has_relaxed_fencing :1; uint16_t fence_max; uint32_t aperture_high, aperture_low, aperture; uint32_t batch[4*1024]; struct drm_i915_gem_exec_object2 exec[256]; struct drm_i915_gem_relocation_entry reloc[384]; }; #define KGEM_BATCH_RESERVED 2 #define KGEM_RELOC_RESERVED 4 #define KGEM_EXEC_RESERVED 1 #define ARRAY_SIZE(a) (sizeof(a)/sizeof((a)[0])) #define KGEM_BATCH_SIZE(K) (ARRAY_SIZE((K)->batch)-KGEM_BATCH_RESERVED) #define KGEM_EXEC_SIZE(K) (ARRAY_SIZE((K)->exec)-KGEM_EXEC_RESERVED) #define KGEM_RELOC_SIZE(K) (ARRAY_SIZE((K)->reloc)-KGEM_RELOC_RESERVED) void kgem_init(struct kgem *kgem, int fd, int gen); struct kgem_bo *kgem_create_map(struct kgem *kgem, void *ptr, uint32_t size, bool read_only); struct kgem_bo *kgem_create_for_name(struct kgem *kgem, uint32_t name); struct kgem_bo *kgem_create_linear(struct kgem *kgem, int size); struct kgem_bo *kgem_create_proxy(struct kgem_bo *target, int offset, int length); struct kgem_bo *kgem_upload_source_image(struct kgem *kgem, const void *data, int x, int y, int width, int height, int stride, int bpp); int kgem_choose_tiling(struct kgem *kgem, int tiling, int width, int height, int bpp); bool kgem_can_create_2d(struct kgem *kgem, int width, int height, int bpp, int tiling); enum { CREATE_EXACT = 0x1, CREATE_INACTIVE = 0x2, }; struct kgem_bo *kgem_create_2d(struct kgem *kgem, int width, int height, int bpp, int tiling, uint32_t flags); void _kgem_retire(struct kgem *kgem); static inline void kgem_retire(struct kgem *kgem) { if (kgem->retire) _kgem_retire(kgem); } void _kgem_submit(struct kgem *kgem); static inline void kgem_submit(struct kgem *kgem) { if (kgem->nbatch) _kgem_submit(kgem); } static inline void kgem_bo_submit(struct kgem *kgem, struct kgem_bo *bo) { if (bo->exec) _kgem_submit(kgem); } void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo); static inline void kgem_bo_flush(struct kgem *kgem, struct kgem_bo *bo) { kgem_bo_submit(kgem, bo); __kgem_flush(kgem, bo); } static inline struct kgem_bo *kgem_bo_reference(struct kgem_bo *bo) { bo->refcnt++; return bo; } void _kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo); static inline void kgem_bo_destroy(struct kgem *kgem, struct kgem_bo *bo) { assert(bo->refcnt); if (--bo->refcnt == 0) _kgem_bo_destroy(kgem, bo); } void kgem_emit_flush(struct kgem *kgem); void kgem_clear_dirty(struct kgem *kgem); extern void sna_kgem_context_switch(struct kgem *kgem, int new_mode); static inline void kgem_set_mode(struct kgem *kgem, enum kgem_mode mode) { #if DEBUG_FLUSH_CACHE kgem_emit_flush(kgem); #endif #if DEBUG_FLUSH_BATCH kgem_submit(kgem); #endif if (kgem->mode == mode) return; sna_kgem_context_switch(kgem, mode); kgem->mode = mode; } static inline void _kgem_set_mode(struct kgem *kgem, enum kgem_mode mode) { if (kgem->nbatch) kgem->mode = mode; } static inline bool kgem_check_batch(struct kgem *kgem, int num_dwords) { return kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED <= kgem->surface; } static inline bool kgem_check_reloc(struct kgem *kgem, int num_reloc) { return kgem->nreloc + num_reloc <= KGEM_RELOC_SIZE(kgem); } static inline bool kgem_check_batch_with_surfaces(struct kgem *kgem, int num_dwords, int num_surfaces) { return (int)(kgem->nbatch + num_dwords + KGEM_BATCH_RESERVED) <= (int)(kgem->surface - num_surfaces*8) && kgem_check_reloc(kgem, num_surfaces); } static inline uint32_t *kgem_get_batch(struct kgem *kgem, int num_dwords) { if (!kgem_check_batch(kgem, num_dwords)) _kgem_submit(kgem); return kgem->batch + kgem->nbatch; } static inline void kgem_advance_batch(struct kgem *kgem, int num_dwords) { kgem->nbatch += num_dwords; } bool kgem_check_bo(struct kgem *kgem, struct kgem_bo *bo); bool kgem_check_bo_fenced(struct kgem *kgem, ...) __attribute__((sentinel(NULL))); void _kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo); static inline void kgem_add_bo(struct kgem *kgem, struct kgem_bo *bo) { if (bo->proxy) bo = bo->proxy; if (bo->exec == NULL) _kgem_add_bo(kgem, bo); } #define KGEM_RELOC_FENCED 0x8000 uint32_t kgem_add_reloc(struct kgem *kgem, uint32_t pos, struct kgem_bo *bo, uint32_t read_write_domains, uint32_t delta); void *kgem_bo_map(struct kgem *kgem, struct kgem_bo *bo, int prot); uint32_t kgem_bo_flink(struct kgem *kgem, struct kgem_bo *bo); Bool kgem_bo_write(struct kgem *kgem, struct kgem_bo *bo, const void *data, int length); static inline bool kgem_bo_is_busy(struct kgem *kgem, struct kgem_bo *bo) { if (bo->exec) return true; if (!bo->gpu) return false; kgem_retire(kgem); return bo->rq != NULL; } static inline bool kgem_bo_is_dirty(struct kgem_bo *bo) { if (bo == NULL) return FALSE; if (bo->proxy) bo = bo->proxy; return bo->dirty; } static inline void kgem_bo_mark_dirty(struct kgem_bo *bo) { if (bo->proxy) bo = bo->proxy; bo->dirty = true; } void kgem_bo_sync(struct kgem *kgem, struct kgem_bo *bo, bool for_write); #define KGEM_BUFFER_WRITE 0x1 #define KGEM_BUFFER_LAST 0x2 struct kgem_bo *kgem_create_buffer(struct kgem *kgem, uint32_t size, uint32_t flags, void **ret); void kgem_buffer_sync(struct kgem *kgem, struct kgem_bo *bo); void kgem_throttle(struct kgem *kgem); bool kgem_needs_expire(struct kgem *kgem); bool kgem_expire_cache(struct kgem *kgem); #if HAS_EXTRA_DEBUG void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch); #else static inline void __kgem_batch_debug(struct kgem *kgem, uint32_t nbatch) {} #endif #endif /* KGEM_H */