diff options
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/Makefile | 18 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/Makefile.template | 64 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.c | 120 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.h | 55 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_context.c | 79 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_context.h | 48 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_device.c | 260 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_device.h | 70 | ||||
-rw-r--r-- | src/gallium/winsys/drm/intel/gem/intel_be_fence.h | 38 |
9 files changed, 752 insertions, 0 deletions
diff --git a/src/gallium/winsys/drm/intel/gem/Makefile b/src/gallium/winsys/drm/intel/gem/Makefile new file mode 100644 index 00000000000..b25fc258f45 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/Makefile @@ -0,0 +1,18 @@ +TOP = ../../../../../.. +include $(TOP)/configs/current + +LIBNAME = inteldrm + +C_SOURCES = \ + intel_be_batchbuffer.c \ + intel_be_context.c \ + intel_be_device.c + + +include ./Makefile.template + +DRIVER_DEFINES = $(shell pkg-config libdrm --cflags \ + && pkg-config libdrm --atleast-version=2.3.1 \ + && echo "-DDRM_VBLANK_FLIP=DRM_VBLANK_FLIP") +symlinks: + diff --git a/src/gallium/winsys/drm/intel/gem/Makefile.template b/src/gallium/winsys/drm/intel/gem/Makefile.template new file mode 100644 index 00000000000..557070ae02a --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/Makefile.template @@ -0,0 +1,64 @@ +# -*-makefile-*- + + +# We still have a dependency on the "dri" buffer manager. Most likely +# the interface can be reused in non-dri environments, and also as a +# frontend to simpler memory managers. +# +COMMON_SOURCES = + +OBJECTS = $(C_SOURCES:.c=.o) \ + $(CPP_SOURCES:.cpp=.o) \ + $(ASM_SOURCES:.S=.o) + + +### Include directories +INCLUDES = \ + -I. \ + -I$(TOP)/src/gallium/include \ + -I$(TOP)/src/gallium/auxiliary \ + -I$(TOP)/src/gallium/drivers \ + -I$(TOP)/include \ + $(DRIVER_INCLUDES) + + +##### RULES ##### + +.c.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DRIVER_DEFINES) $< -o $@ + +.cpp.o: + $(CXX) -c $(INCLUDES) $(CXXFLAGS) $(DRIVER_DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(INCLUDES) $(CFLAGS) $(DRIVER_DEFINES) $< -o $@ + + +##### TARGETS ##### + +default: depend symlinks $(LIBNAME) + + +$(LIBNAME): $(OBJECTS) Makefile Makefile.template + $(TOP)/bin/mklib -o $@ -static $(OBJECTS) $(DRIVER_LIBS) + + +depend: $(C_SOURCES) $(CPP_SOURCES) $(ASM_SOURCES) $(SYMLINKS) + rm -f depend + touch depend + $(MKDEP) $(MKDEP_OPTIONS) $(DRIVER_DEFINES) $(INCLUDES) $(C_SOURCES) $(CPP_SOURCES) \ + $(ASM_SOURCES) 2> /dev/null + + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + + +# Remove .o and backup files +clean:: + -rm -f *.o */*.o *~ *.so *.a *~ server/*.o $(SYMLINKS) + -rm -f depend depend.bak + + +include depend diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.c b/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.c new file mode 100644 index 00000000000..23999106138 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.c @@ -0,0 +1,120 @@ + +#include "intel_be_batchbuffer.h" +#include "intel_be_context.h" +#include "intel_be_device.h" +#include "intel_be_fence.h" +#include <errno.h> + +#include "util/u_memory.h" + +struct intel_be_batchbuffer * +intel_be_batchbuffer_alloc(struct intel_be_context *intel) +{ + struct intel_be_batchbuffer *batch = CALLOC_STRUCT(intel_be_batchbuffer); + + batch->base.buffer = NULL; + batch->base.winsys = &intel->base; + batch->base.map = NULL; + batch->base.ptr = NULL; + batch->base.size = 0; + batch->base.actual_size = intel->device->max_batch_size; + batch->base.relocs = 0; + batch->base.max_relocs = INTEL_DEFAULT_RELOCS; + + batch->base.map = malloc(batch->base.actual_size); + memset(batch->base.map, 0, batch->base.actual_size); + + batch->base.ptr = batch->base.map; + + intel_be_batchbuffer_reset(batch); + + return NULL; +} + +void +intel_be_batchbuffer_reset(struct intel_be_batchbuffer *batch) +{ + struct intel_be_context *intel = intel_be_context(batch->base.winsys); + struct intel_be_device *dev = intel->device; + + if (batch->bo) + drm_intel_bo_unreference(batch->bo); + + memset(batch->base.map, 0, batch->base.actual_size); + batch->base.ptr = batch->base.map; + batch->base.size = batch->base.actual_size - BATCH_RESERVED; + + batch->base.relocs = 0; + batch->base.max_relocs = INTEL_DEFAULT_RELOCS; + + batch->bo = drm_intel_bo_alloc(dev->pools.gem, + "gallium3d_batch_buffer", + batch->base.actual_size, 0); +} + +int +intel_be_offset_relocation(struct intel_be_batchbuffer *batch, + unsigned pre_add, + drm_intel_bo *bo, + uint32_t read_domains, + uint32_t write_domain) +{ + unsigned offset; + int ret = 0; + + assert(batch->base.relocs < batch->base.max_relocs); + + offset = (unsigned)(batch->base.ptr - batch->base.map); + batch->base.ptr += 4; + +/* + TODO: Enable this when we submit batch buffers to HW + ret = drm_intel_bo_emit_reloc(bo, pre_add, + batch->bo, offset, + read_domains, + write_domain); +*/ + + if (!ret) + batch->base.relocs++; + + return ret; +} + +void +intel_be_batchbuffer_flush(struct intel_be_batchbuffer *batch, + struct intel_be_fence **fence) +{ + struct i915_batchbuffer *i915 = &batch->base; + + assert(i915_batchbuffer_space(i915) >= 0); + + /* TODO: submit stuff to HW */ + + intel_be_batchbuffer_reset(batch); + + if (fence) { + if (*fence) + intel_be_fence_unreference(*fence); + + (*fence) = CALLOC_STRUCT(intel_be_fence); + (*fence)->refcount = 1; + (*fence)->bo = NULL; + } +} + +void +intel_be_batchbuffer_finish(struct intel_be_batchbuffer *batch) +{ + +} + +void +intel_be_batchbuffer_free(struct intel_be_batchbuffer *batch) +{ + if (batch->bo) + drm_intel_bo_unreference(batch->bo); + + free(batch->base.map); + free(batch); +} diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.h b/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.h new file mode 100644 index 00000000000..195bf8dee77 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_batchbuffer.h @@ -0,0 +1,55 @@ + +#ifndef INTEL_BE_BATCHBUFFER_H +#define INTEL_BE_BATCHBUFFER_H + +#include "i915simple/i915_batch.h" + +#include "drm.h" +#include "intel_bufmgr.h" + +#define BATCH_RESERVED 16 + +#define INTEL_DEFAULT_RELOCS 100 +#define INTEL_MAX_RELOCS 400 + +#define INTEL_BATCH_NO_CLIPRECTS 0x1 +#define INTEL_BATCH_CLIPRECTS 0x2 + +struct intel_be_context; +struct intel_be_device; +struct intel_be_fence; + +struct intel_be_batchbuffer +{ + struct i915_batchbuffer base; + + struct intel_be_context *intel; + struct intel_be_device *device; + + drm_intel_bo *bo; +}; + +struct intel_be_batchbuffer * +intel_be_batchbuffer_alloc(struct intel_be_context *intel); + +void +intel_be_batchbuffer_free(struct intel_be_batchbuffer *batch); + +void +intel_be_batchbuffer_finish(struct intel_be_batchbuffer *batch); + +void +intel_be_batchbuffer_flush(struct intel_be_batchbuffer *batch, + struct intel_be_fence **fence); + +void +intel_be_batchbuffer_reset(struct intel_be_batchbuffer *batch); + +int +intel_be_offset_relocation(struct intel_be_batchbuffer *batch, + unsigned pre_add, + drm_intel_bo *bo, + uint32_t read_domains, + uint32_t write_doman); + +#endif diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_context.c b/src/gallium/winsys/drm/intel/gem/intel_be_context.c new file mode 100644 index 00000000000..92fc2dd7679 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_context.c @@ -0,0 +1,79 @@ + +#include "intel_be_device.h" +#include "intel_be_context.h" +#include "intel_be_batchbuffer.h" + +#include "i915_drm.h" + +static struct i915_batchbuffer * +intel_be_batch_get(struct i915_winsys *sws) +{ + struct intel_be_context *intel = intel_be_context(sws); + return &intel->batch->base; +} + +static void +intel_be_batch_reloc(struct i915_winsys *sws, + struct pipe_buffer *buf, + unsigned access_flags, + unsigned delta) +{ + struct intel_be_context *intel = intel_be_context(sws); + drm_intel_bo *bo = intel_bo(buf); + int ret; + uint32_t read = 0; + uint32_t write = 0; + + if (access_flags & I915_BUFFER_ACCESS_WRITE) { + write = I915_GEM_DOMAIN_RENDER; + } + + if (access_flags & I915_BUFFER_ACCESS_READ) { + read = I915_GEM_DOMAIN_SAMPLER | + I915_GEM_DOMAIN_INSTRUCTION | + I915_GEM_DOMAIN_VERTEX; + } + + ret = intel_be_offset_relocation(intel->batch, + delta, + bo, + read, + write); + /* TODO change return type */ + /* return ret; */ +} + +static void +intel_be_batch_flush(struct i915_winsys *sws, + struct pipe_fence_handle **fence) +{ + struct intel_be_context *intel = intel_be_context(sws); + struct intel_be_fence **f = (struct intel_be_fence **)fence; + + if (fence && *fence) + assert(0); + + intel_be_batchbuffer_flush(intel->batch, f); +} + +boolean +intel_be_init_context(struct intel_be_context *intel, struct intel_be_device *device) +{ + assert(intel); + assert(device); + intel->device = device; + + intel->base.batch_get = intel_be_batch_get; + intel->base.batch_reloc = intel_be_batch_reloc; + intel->base.batch_flush = intel_be_batch_flush; + + intel->batch = intel_be_batchbuffer_alloc(intel); + + return true; +} + +void +intel_be_destroy_context(struct intel_be_context *intel) +{ + intel_be_batchbuffer_free(intel->batch); +} diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_context.h b/src/gallium/winsys/drm/intel/gem/intel_be_context.h new file mode 100644 index 00000000000..9cee1a4e52b --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_context.h @@ -0,0 +1,48 @@ + +#ifndef INTEL_BE_CONTEXT_H +#define INTEL_BE_CONTEXT_H + +#include "i915simple/i915_winsys.h" + +struct intel_be_context +{ + /** Interface to i915simple driver */ + struct i915_winsys base; + + struct intel_be_device *device; + struct intel_be_batchbuffer *batch; + + /* + * Hardware lock functions. + * + * Needs to be filled in by the winsys. + */ + void (*hardware_lock)(struct intel_be_context *context); + void (*hardware_unlock)(struct intel_be_context *context); + boolean (*hardware_locked)(struct intel_be_context *context); +}; + +static INLINE struct intel_be_context * +intel_be_context(struct i915_winsys *sws) +{ + return (struct intel_be_context *)sws; +} + +/** + * Intialize a allocated intel_be_context struct. + * + * Remember to set the hardware_* functions. + */ +boolean +intel_be_init_context(struct intel_be_context *intel, + struct intel_be_device *device); + +/** + * Destroy a intel_be_context. + * + * Does not free the struct that is up to the winsys. + */ +void +intel_be_destroy_context(struct intel_be_context *intel); + +#endif diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_device.c b/src/gallium/winsys/drm/intel/gem/intel_be_device.c new file mode 100644 index 00000000000..cf0c1408dc8 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_device.c @@ -0,0 +1,260 @@ + +#include "intel_be_device.h" + +#include "pipe/p_winsys.h" +#include "pipe/p_defines.h" +#include "pipe/p_state.h" +#include "pipe/p_inlines.h" +#include "util/u_memory.h" + +#include "intel_be_fence.h" + +#include "i915simple/i915_screen.h" + + +/** + * Turn a pipe winsys into an intel/pipe winsys: + */ +static INLINE struct intel_be_device * +intel_be_device(struct pipe_winsys *winsys) +{ + return (struct intel_be_device *)winsys; +} + +/* + * Buffer + */ + +static void * +intel_be_buffer_map(struct pipe_winsys *winsys, + struct pipe_buffer *buf, + unsigned flags) +{ + drm_intel_bo *bo = intel_bo(buf); + int write = 0; + int ret; + + if (flags & PIPE_BUFFER_USAGE_CPU_WRITE) + write = 1; + + ret = drm_intel_bo_map(bo, write); + + if (ret) + return NULL; + + return bo->virtual; +} + +static void +intel_be_buffer_unmap(struct pipe_winsys *winsys, + struct pipe_buffer *buf) +{ + drm_intel_bo_unmap(intel_bo(buf)); +} + +static void +intel_be_buffer_destroy(struct pipe_winsys *winsys, + struct pipe_buffer *buf) +{ + drm_intel_bo_unreference(intel_bo(buf)); + free(buf); +} + +static struct pipe_buffer * +intel_be_buffer_create(struct pipe_winsys *winsys, + unsigned alignment, + unsigned usage, + unsigned size) +{ + struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer); + struct intel_be_device *dev = intel_be_device(winsys); + drm_intel_bufmgr *pool; + char *name; + + if (!buffer) + return NULL; + + buffer->base.refcount = 1; + buffer->base.alignment = alignment; + buffer->base.usage = usage; + buffer->base.size = size; + + if (usage & (PIPE_BUFFER_USAGE_VERTEX | PIPE_BUFFER_USAGE_CONSTANT)) { + /* Local buffer */ + name = "gallium3d_local"; + pool = dev->pools.gem; + } else if (usage & PIPE_BUFFER_USAGE_CUSTOM) { + /* For vertex buffers */ + name = "gallium3d_internal_vertex"; + pool = dev->pools.gem; + } else { + /* Regular buffers */ + name = "gallium3d_regular"; + pool = dev->pools.gem; + } + + buffer->bo = drm_intel_bo_alloc(pool, name, size, alignment); + + if (!buffer->bo) + goto err; + + return &buffer->base; + +err: + free(buffer); + return NULL; +} + +static struct pipe_buffer * +intel_be_user_buffer_create(struct pipe_winsys *winsys, void *ptr, unsigned bytes) +{ + struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer); + struct intel_be_device *dev = intel_be_device(winsys); + int ret; + + if (!buffer) + return NULL; + + buffer->base.refcount = 1; + buffer->base.alignment = 0; + buffer->base.usage = 0; + buffer->base.size = bytes; + + buffer->bo = drm_intel_bo_alloc(dev->pools.gem, + "gallium3d_user_buffer", + bytes, 0); + + if (!buffer->bo) + goto err; + + ret = drm_intel_bo_subdata(buffer->bo, + 0, bytes, ptr); + + if (ret) + goto err; + + return &buffer->base; + +err: + free(buffer); + return NULL; +} + +struct pipe_buffer * +intel_be_buffer_from_handle(struct intel_be_device *dev, + const char* name, unsigned handle) +{ + struct intel_be_buffer *buffer = CALLOC_STRUCT(intel_be_buffer); + + if (!buffer) + return NULL; + + buffer->bo = drm_intel_bo_gem_create_from_name(dev->pools.gem, name, handle); + + if (!buffer->bo) + goto err; + + buffer->base.refcount = 1; + buffer->base.alignment = buffer->bo->align; + buffer->base.usage = PIPE_BUFFER_USAGE_GPU_READ | + PIPE_BUFFER_USAGE_GPU_WRITE | + PIPE_BUFFER_USAGE_CPU_READ | + PIPE_BUFFER_USAGE_CPU_WRITE; + buffer->base.size = buffer->bo->size; + + return &buffer->base; + +err: + free(buffer); + return NULL; +} + +/* + * Fence + */ + +static void +intel_be_fence_refunref(struct pipe_winsys *sws, + struct pipe_fence_handle **ptr, + struct pipe_fence_handle *fence) +{ + struct intel_be_fence **p = (struct intel_be_fence **)ptr; + struct intel_be_fence *f = (struct intel_be_fence *)fence; + + assert(p); + + if (f) + intel_be_fence_reference(f); + + if (*p) + intel_be_fence_unreference(*p); + + *p = f; +} + +static int +intel_be_fence_signalled(struct pipe_winsys *sws, + struct pipe_fence_handle *fence, + unsigned flag) +{ + assert(0); + + return 0; +} + +static int +intel_be_fence_finish(struct pipe_winsys *sws, + struct pipe_fence_handle *fence, + unsigned flag) +{ + struct intel_be_fence *f = (struct intel_be_fence *)fence; + + /* fence already expired */ + if (!f->bo) + return 0; + + drm_intel_bo_wait_rendering(f->bo); + drm_intel_bo_unreference(f->bo); + f->bo = NULL; + + return 0; +} + +/* + * Misc functions + */ + +boolean +intel_be_init_device(struct intel_be_device *dev, int fd, unsigned id) +{ + dev->fd = fd; + dev->max_batch_size = 16 * 4096; + dev->max_vertex_size = 128 * 4096; + + dev->base.buffer_create = intel_be_buffer_create; + dev->base.user_buffer_create = intel_be_user_buffer_create; + dev->base.buffer_map = intel_be_buffer_map; + dev->base.buffer_unmap = intel_be_buffer_unmap; + dev->base.buffer_destroy = intel_be_buffer_destroy; + + /* Not used anymore */ + dev->base.surface_alloc = NULL; + dev->base.surface_alloc_storage = NULL; + dev->base.surface_release = NULL; + + dev->base.fence_reference = intel_be_fence_refunref; + dev->base.fence_signalled = intel_be_fence_signalled; + dev->base.fence_finish = intel_be_fence_finish; + + dev->pools.gem = drm_intel_bufmgr_gem_init(dev->fd, dev->max_batch_size); + + dev->screen = i915_create_screen(&dev->base, id); + + return true; +} + +void +intel_be_destroy_device(struct intel_be_device *dev) +{ + drm_intel_bufmgr_destroy(dev->pools.gem); +} diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_device.h b/src/gallium/winsys/drm/intel/gem/intel_be_device.h new file mode 100644 index 00000000000..53d63536c97 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_device.h @@ -0,0 +1,70 @@ + +#ifndef INTEL_DRM_DEVICE_H +#define INTEL_DRM_DEVICE_H + +#include "pipe/p_winsys.h" +#include "pipe/p_context.h" + +#include "drm.h" +#include "intel_bufmgr.h" + +/* + * Device + */ + +struct intel_be_device +{ + struct pipe_winsys base; + + /** + * Hw level screen + */ + struct pipe_screen *screen; + + int fd; /**< Drm file discriptor */ + + size_t max_batch_size; + size_t max_vertex_size; + + struct { + drm_intel_bufmgr *gem; + } pools; +}; + +boolean +intel_be_init_device(struct intel_be_device *device, int fd, unsigned id); + +void +intel_be_destroy_device(struct intel_be_device *dev); + +/* + * Buffer + */ + +struct intel_be_buffer { + struct pipe_buffer base; + drm_intel_bo *bo; +}; + +/** + * Create a be buffer from a drm bo handle + * + * Takes a reference + */ +struct pipe_buffer * +intel_be_buffer_from_handle(struct intel_be_device *device, + const char* name, unsigned handle); + +static INLINE struct intel_be_buffer * +intel_be_buffer(struct pipe_buffer *buf) +{ + return (struct intel_be_buffer *)buf; +} + +static INLINE drm_intel_bo * +intel_bo(struct pipe_buffer *buf) +{ + return intel_be_buffer(buf)->bo; +} + +#endif diff --git a/src/gallium/winsys/drm/intel/gem/intel_be_fence.h b/src/gallium/winsys/drm/intel/gem/intel_be_fence.h new file mode 100644 index 00000000000..0fe18f66f83 --- /dev/null +++ b/src/gallium/winsys/drm/intel/gem/intel_be_fence.h @@ -0,0 +1,38 @@ + +#ifndef INTEL_BE_FENCE_H +#define INTEL_BE_FENCE_H + +#include "pipe/p_defines.h" + +#include "drm.h" +#include "intel_bufmgr.h" + +/** + * Because gem does not have fence's we have to create our own fences. + * + * They work by keeping the batchbuffer around and checking if that has + * been idled. If bo is NULL fence has expired. + */ +struct intel_be_fence +{ + uint32_t refcount; + drm_intel_bo *bo; +}; + +static INLINE void +intel_be_fence_reference(struct intel_be_fence *f) +{ + f->refcount++; +} + +static INLINE void +intel_be_fence_unreference(struct intel_be_fence *f) +{ + if (!--f->refcount) { + if (f->bo) + drm_intel_bo_unreference(f->bo); + free(f); + } +} + +#endif |