summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-02-13 22:52:25 +0000
committerKristian Høgsberg <krh@redhat.com>2009-05-10 23:22:46 -0400
commit113248631063bd490bcf5e27b07a53bd145efe38 (patch)
tree766d2abd198061d22453abec6afbeac14075c6dd
parent3f52082004f68909307ab0200be92f7dbbba3c26 (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.c100
1 files changed, 99 insertions, 1 deletions
diff --git a/intel.c b/intel.c
index 24c867e..74cb80f 100644
--- a/intel.c
+++ b/intel.c
@@ -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");