diff options
-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"); |