diff options
author | Chris Wilson <chris@chris-wilson.co.uk> | 2009-02-13 22:52:25 +0000 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2009-05-10 23:22:46 -0400 |
commit | 113248631063bd490bcf5e27b07a53bd145efe38 (patch) | |
tree | 766d2abd198061d22453abec6afbeac14075c6dd | |
parent | 3f52082004f68909307ab0200be92f7dbbba3c26 (diff) |
intel: Add i915 tiling support.
For low-end devices like the i915, tiling is a huge win (you can measure a
performance difference of up to 20x). The cost is that you need to allocate
much larger buffers (and GEM needs to impose much more severe alignment
restrictions costing even more memory). However, without tiling, the
performance is nigh-on unusable - once tiled you won't go back!
In order to enable tiling on i915 you need to pull various patches from
intel-gfx or wait for a post-2.6.29 kernel.
-rw-r--r-- | intel.c | 100 |
1 files changed, 99 insertions, 1 deletions
@@ -49,15 +49,113 @@ align_to(uint32_t value, uint32_t align) return (value + align - 1) & ~(align - 1); } +/* Look at xf86-video-intel/src/common.h for the full horror of device + * identification. + */ +enum { + GEN_1 = 0x10, + GEN_2 = 0x20, + GEN_3 = 0x40, + GEN_31 = 0x41, + GEN_4 = 0x80, + + GEN_MAJOR_MASK = 0xf0, + GEN_MINOR_MASK = 0x0f, +}; + +#define IS_I965(x) ((x) & GEN_4) +#define IS_I915(x) ((x) & GEN_3) +#define IS_I9xx(x) ((x) & (GEN_3 | GEN_4)) +#define IS_I8xx(x) ((x) & (GEN_1 | GEN_2)) + +#define HAS_128_BYTE_Y_TILING(x) (((x) & (GEN_3 | GEN_4 | GEN_MINOR_MASK)) > GEN_3) + +static uint32_t +tiling_stride (int dev, int tiling_mode, uint32_t pitch) +{ + uint32_t tile_width; + + if (tiling_mode == I915_TILING_NONE) + return pitch; + + if (tiling_mode == I915_TILING_Y && HAS_128_BYTE_Y_TILING (dev)) + tile_width = 128; + else + tile_width = 512; + + /* 965+ just needs multiples of tile width */ + if (IS_I965 (dev)) + return align_to (pitch, tile_width); + + /* Pre-965 needs power of two tile widths */ + while (tile_width < pitch) + tile_width <<= 1; + + return tile_width; +} + +static uint32_t +tiling_size (int dev, uint32_t tiling, uint32_t size) +{ + uint32_t fence; + + if (tiling == I915_TILING_NONE) + return size; + + /* The 965 can have fences at any page boundary. */ + if (IS_I965 (dev)) + return align_to (size, 4096); + + /* Align the size to a power of two greater than the smallest fence. */ + if (IS_I9xx (dev)) + fence = 1024 * 1024; /* 1 MiB */ + else + fence = 512 * 1024; /* 512 KiB */ + while (fence < size) + fence <<= 1; + + return fence; +} + static int intelCreateBuffer(int fd, GLint width, GLint height, __DRIbuffer *buffer) { struct drm_i915_gem_create create; struct drm_gem_flink flink; uint32_t size; + int tiling; + int dev = GEN_4; /* XXX query using I915_GETPARAM + PARAM_CHIPSET_ID */ + tiling = I915_TILING_X; buffer->pitch = align_to(width * 4, INTEL_STRIDE_ALIGNMENT); - size = buffer->pitch * height; + if (tiling != I915_TILING_NONE) { + buffer->pitch = tiling_stride (dev, tiling, buffer->pitch); + size = buffer->pitch * height; + size = tiling_size (dev, tiling, size); + } else { + size = buffer->pitch * height; + } + + create.size = size; + if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create)) { + fprintf(stderr, "failed to create buffer\n"); + return -1; + } + + if (tiling != I915_TILING_NONE) { + struct drm_i915_gem_set_tiling set_tiling; + + memset (&set_tiling, 0, sizeof (set_tiling)); + set_tiling.handle = create.handle; + set_tiling.tiling_mode = tiling; + set_tiling.stride = buffer->pitch; + + if (ioctl (fd, + DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) { + fprintf(stderr, "failed to enable tiling\n"); + } + } + create.size = size; if (ioctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create)) { fprintf(stderr, "failed to create buffer\n"); |