summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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");