summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-10-06 14:34:06 -0700
committerEric Anholt <eric@anholt.net>2009-10-06 15:45:10 -0700
commit3a7dfcdfafdd6ac83a4d3e7b4c1c52fd901b93ae (patch)
tree8182457bf0f074d83137a176f228f01370ef31c2
parent02c775fc750b48ae25b6a4af51afbfe090ebada4 (diff)
intel: Add a bo_alloc function for tiled BOs.
This simplifies driver code in handling object allocation, and also gives us an opportunity to possibly cache tiled buffers if it turns out to be a win. [anholt: This is chopped out of the execbuf2 patch, as it seems to be useful separately and cleans up the execbuf2 changes to be more obvious]
-rw-r--r--libdrm/intel/intel_bufmgr.c9
-rw-r--r--libdrm/intel/intel_bufmgr.h8
-rw-r--r--libdrm/intel/intel_bufmgr_fake.c29
-rw-r--r--libdrm/intel/intel_bufmgr_gem.c114
-rw-r--r--libdrm/intel/intel_bufmgr_priv.h26
5 files changed, 178 insertions, 8 deletions
diff --git a/libdrm/intel/intel_bufmgr.c b/libdrm/intel/intel_bufmgr.c
index fd5a2e75..2469cd84 100644
--- a/libdrm/intel/intel_bufmgr.c
+++ b/libdrm/intel/intel_bufmgr.c
@@ -58,6 +58,15 @@ drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
return bufmgr->bo_alloc_for_render(bufmgr, name, size, alignment);
}
+drm_intel_bo *
+drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
+ int x, int y, int cpp, uint32_t *tiling_mode,
+ unsigned long *pitch, unsigned long flags)
+{
+ return bufmgr->bo_alloc_tiled(bufmgr, name, x, y, cpp,
+ tiling_mode, pitch, flags);
+}
+
void drm_intel_bo_reference(drm_intel_bo *bo)
{
bo->bufmgr->bo_reference(bo);
diff --git a/libdrm/intel/intel_bufmgr.h b/libdrm/intel/intel_bufmgr.h
index 0dbe8801..3801ff31 100644
--- a/libdrm/intel/intel_bufmgr.h
+++ b/libdrm/intel/intel_bufmgr.h
@@ -77,12 +77,20 @@ struct _drm_intel_bo {
int handle;
};
+#define BO_ALLOC_FOR_RENDER (1<<0)
+
drm_intel_bo *drm_intel_bo_alloc(drm_intel_bufmgr *bufmgr, const char *name,
unsigned long size, unsigned int alignment);
drm_intel_bo *drm_intel_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
unsigned int alignment);
+drm_intel_bo *drm_intel_bo_alloc_tiled(drm_intel_bufmgr *bufmgr,
+ const char *name,
+ int x, int y, int cpp,
+ uint32_t *tiling_mode,
+ unsigned long *pitch,
+ unsigned long flags);
void drm_intel_bo_reference(drm_intel_bo *bo);
void drm_intel_bo_unreference(drm_intel_bo *bo);
int drm_intel_bo_map(drm_intel_bo *bo, int write_enable);
diff --git a/libdrm/intel/intel_bufmgr_fake.c b/libdrm/intel/intel_bufmgr_fake.c
index f3254825..54b3cb80 100644
--- a/libdrm/intel/intel_bufmgr_fake.c
+++ b/libdrm/intel/intel_bufmgr_fake.c
@@ -51,8 +51,6 @@
#include "mm.h"
#include "libdrm_lists.h"
-#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1))
-
#define DBG(...) do { \
if (bufmgr_fake->bufmgr.debug) \
drmMsg(__VA_ARGS__); \
@@ -838,6 +836,32 @@ drm_intel_fake_bo_alloc(drm_intel_bufmgr *bufmgr,
return &bo_fake->bo;
}
+static drm_intel_bo *
+drm_intel_fake_bo_alloc_tiled(drm_intel_bufmgr * bufmgr,
+ const char *name,
+ int x, int y, int cpp,
+ uint32_t *tiling_mode,
+ unsigned long *pitch,
+ unsigned long flags)
+{
+ unsigned long stride, aligned_y;
+
+ /* No runtime tiling support for fake. */
+ *tiling_mode = I915_TILING_NONE;
+
+ /* Align it for being a render target. Shouldn't need anything else. */
+ stride = x * cpp;
+ stride = ROUND_UP_TO(stride, 64);
+
+ /* 965 subspan loading alignment */
+ aligned_y = ALIGN(y, 2);
+
+ *pitch = stride;
+
+ return drm_intel_fake_bo_alloc(bufmgr, name, stride * aligned_y,
+ 4096);
+}
+
drm_intel_bo *
drm_intel_bo_fake_alloc_static(drm_intel_bufmgr *bufmgr,
const char *name,
@@ -1565,6 +1589,7 @@ drm_intel_bufmgr *drm_intel_bufmgr_fake_init(int fd,
/* Hook in methods */
bufmgr_fake->bufmgr.bo_alloc = drm_intel_fake_bo_alloc;
bufmgr_fake->bufmgr.bo_alloc_for_render = drm_intel_fake_bo_alloc;
+ bufmgr_fake->bufmgr.bo_alloc_tiled = drm_intel_fake_bo_alloc_tiled;
bufmgr_fake->bufmgr.bo_reference = drm_intel_fake_bo_reference;
bufmgr_fake->bufmgr.bo_unreference = drm_intel_fake_bo_unreference;
bufmgr_fake->bufmgr.bo_map = drm_intel_fake_bo_map;
diff --git a/libdrm/intel/intel_bufmgr_gem.c b/libdrm/intel/intel_bufmgr_gem.c
index aa55f2dd..3e46f532 100644
--- a/libdrm/intel/intel_bufmgr_gem.c
+++ b/libdrm/intel/intel_bufmgr_gem.c
@@ -193,6 +193,66 @@ static void drm_intel_gem_bo_unreference(drm_intel_bo *bo);
static void drm_intel_gem_bo_free(drm_intel_bo *bo);
+static unsigned long
+drm_intel_gem_bo_tile_size(drm_intel_bufmgr_gem *bufmgr_gem, unsigned long size,
+ uint32_t *tiling_mode)
+{
+ unsigned long min_size, max_size;
+ unsigned long i;
+
+ if (*tiling_mode == I915_TILING_NONE)
+ return size;
+
+ /* 965+ just need multiples of page size for tiling */
+ if (IS_I965G(bufmgr_gem))
+ return ROUND_UP_TO(size, 4096);
+
+ /* Older chips need powers of two, of at least 512k or 1M */
+ if (IS_I9XX(bufmgr_gem)) {
+ min_size = 1024*1024;
+ max_size = 128*1024*1024;
+ } else {
+ min_size = 512*1024;
+ max_size = 64*1024*1024;
+ }
+
+ if (size > max_size) {
+ *tiling_mode = I915_TILING_NONE;
+ return size;
+ }
+
+ for (i = min_size; i < size; i <<= 1)
+ ;
+
+ return i;
+}
+
+/*
+ * Round a given pitch up to the minimum required for X tiling on a
+ * given chip. We use 512 as the minimum to allow for a later tiling
+ * change.
+ */
+static unsigned long
+drm_intel_gem_bo_tile_pitch(drm_intel_bufmgr_gem *bufmgr_gem,
+ unsigned long pitch, uint32_t tiling_mode)
+{
+ unsigned long tile_width = 512;
+ unsigned long i;
+
+ if (tiling_mode == I915_TILING_NONE)
+ return ROUND_UP_TO(pitch, tile_width);
+
+ /* 965 is flexible */
+ if (IS_I965G(bufmgr_gem))
+ return ROUND_UP_TO(pitch, tile_width);
+
+ /* Pre-965 needs power of two tile width */
+ for (i = tile_width; i < pitch; i <<= 1)
+ ;
+
+ return i;
+}
+
static struct drm_intel_gem_bo_bucket *
drm_intel_gem_bo_bucket_for_size(drm_intel_bufmgr_gem *bufmgr_gem,
unsigned long size)
@@ -372,8 +432,7 @@ static drm_intel_bo *
drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr,
const char *name,
unsigned long size,
- unsigned int alignment,
- int for_render)
+ unsigned long flags)
{
drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *) bufmgr;
drm_intel_bo_gem *bo_gem;
@@ -382,6 +441,10 @@ drm_intel_gem_bo_alloc_internal(drm_intel_bufmgr *bufmgr,
struct drm_intel_gem_bo_bucket *bucket;
int alloc_from_cache;
unsigned long bo_size;
+ int for_render = 0;
+
+ if (flags & BO_ALLOC_FOR_RENDER)
+ for_render = 1;
/* Round the allocated size up to a power of two number of pages. */
bucket = drm_intel_gem_bo_bucket_for_size(bufmgr_gem, size);
@@ -482,8 +545,9 @@ drm_intel_gem_bo_alloc_for_render(drm_intel_bufmgr *bufmgr,
unsigned long size,
unsigned int alignment)
{
- return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment,
- 1);
+ assert(alignment <= 4096);
+ return drm_intel_gem_bo_alloc_internal(bufmgr, name, size,
+ BO_ALLOC_FOR_RENDER);
}
static drm_intel_bo *
@@ -492,8 +556,45 @@ drm_intel_gem_bo_alloc(drm_intel_bufmgr *bufmgr,
unsigned long size,
unsigned int alignment)
{
- return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, alignment,
- 0);
+ assert(alignment <= 4096);
+ return drm_intel_gem_bo_alloc_internal(bufmgr, name, size, 0);
+}
+
+static drm_intel_bo *
+drm_intel_gem_bo_alloc_tiled(drm_intel_bufmgr *bufmgr, const char *name,
+ int x, int y, int cpp, uint32_t *tiling_mode,
+ unsigned long *pitch, unsigned long flags)
+{
+ drm_intel_bufmgr_gem *bufmgr_gem = (drm_intel_bufmgr_gem *)bufmgr;
+ drm_intel_bo *bo;
+ unsigned long size, stride, aligned_y = y;
+ int ret;
+
+ if (*tiling_mode == I915_TILING_NONE)
+ aligned_y = ALIGN(y, 2);
+ else if (*tiling_mode == I915_TILING_X)
+ aligned_y = ALIGN(y, 8);
+ else if (*tiling_mode == I915_TILING_Y)
+ aligned_y = ALIGN(y, 32);
+
+ stride = x * cpp;
+ stride = drm_intel_gem_bo_tile_pitch(bufmgr_gem, stride, *tiling_mode);
+ size = stride * aligned_y;
+ size = drm_intel_gem_bo_tile_size(bufmgr_gem, size, tiling_mode);
+
+ bo = drm_intel_gem_bo_alloc_internal(bufmgr, name, size, flags);
+ if (!bo)
+ return NULL;
+
+ ret = drm_intel_gem_bo_set_tiling(bo, tiling_mode, stride);
+ if (ret != 0) {
+ drm_intel_gem_bo_unreference(bo);
+ return NULL;
+ }
+
+ *pitch = stride;
+
+ return bo;
}
/**
@@ -1565,6 +1666,7 @@ drm_intel_bufmgr_gem_init(int fd, int batch_size)
bufmgr_gem->bufmgr.bo_alloc = drm_intel_gem_bo_alloc;
bufmgr_gem->bufmgr.bo_alloc_for_render =
drm_intel_gem_bo_alloc_for_render;
+ bufmgr_gem->bufmgr.bo_alloc_tiled = drm_intel_gem_bo_alloc_tiled;
bufmgr_gem->bufmgr.bo_reference = drm_intel_gem_bo_reference;
bufmgr_gem->bufmgr.bo_unreference = drm_intel_gem_bo_unreference;
bufmgr_gem->bufmgr.bo_map = drm_intel_gem_bo_map;
diff --git a/libdrm/intel/intel_bufmgr_priv.h b/libdrm/intel/intel_bufmgr_priv.h
index 3b19eca1..475c402f 100644
--- a/libdrm/intel/intel_bufmgr_priv.h
+++ b/libdrm/intel/intel_bufmgr_priv.h
@@ -61,6 +61,28 @@ struct _drm_intel_bufmgr {
unsigned long size,
unsigned int alignment);
+ /**
+ * Allocate a tiled buffer object.
+ *
+ * Alignment for tiled objects is set automatically; the 'flags'
+ * argument provides a hint about how the object will be used initially.
+ *
+ * Valid tiling formats are:
+ * I915_TILING_NONE
+ * I915_TILING_X
+ * I915_TILING_Y
+ *
+ * Note the tiling format may be rejected; callers should check the
+ * 'tiling_mode' field on return, as well as the pitch value, which
+ * may have been rounded up to accommodate for tiling restrictions.
+ */
+ drm_intel_bo *(*bo_alloc_tiled) (drm_intel_bufmgr *bufmgr,
+ const char *name,
+ int x, int y, int cpp,
+ uint32_t *tiling_mode,
+ unsigned long *pitch,
+ unsigned long flags);
+
/** Takes a reference on a buffer object */
void (*bo_reference) (drm_intel_bo *bo);
@@ -225,4 +247,8 @@ struct _drm_intel_bufmgr {
int debug;
};
+#define ALIGN(value, alignment) ((value + alignment - 1) & ~(alignment - 1))
+#define ROUND_UP_TO(x, y) (((x) + (y) - 1) / (y) * (y))
+#define ROUND_UP_TO_MB(x) ROUND_UP_TO((x), 1024*1024)
+
#endif /* INTEL_BUFMGR_PRIV_H */