summaryrefslogtreecommitdiff
path: root/native.c
diff options
context:
space:
mode:
Diffstat (limited to 'native.c')
-rw-r--r--native.c442
1 files changed, 442 insertions, 0 deletions
diff --git a/native.c b/native.c
new file mode 100644
index 0000000..da1be59
--- /dev/null
+++ b/native.c
@@ -0,0 +1,442 @@
+/*
+ * Copyright © 2008, 2009 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <i915_drm.h>
+#include <radeon_drm.h>
+#include <GL/gl.h> /* dri_interface.h uses some GL integer types... */
+#include "eagle-internal.h"
+
+#define INTEL_STRIDE_ALIGNMENT 64
+
+struct EagleBackendNative {
+ struct EagleBackend base;
+ int (*createBuffer)(int fd,
+ GLint width, GLint height, __DRIbuffer *buffer);
+};
+
+typedef struct EGLSurfaceNative *EGLSurfaceNative;
+struct EGLSurfaceNative {
+ struct EGLSurface base;
+ __DRIbuffer *current;
+ __DRIbuffer colorBuffers[2];
+ int colorBufferCount;
+ uint32_t colorBufferHandles[2];
+ uint32_t handles[10];
+};
+
+static inline uint32_t
+align_to(uint32_t value, uint32_t align)
+{
+ return (value + align - 1) & ~(align - 1);
+}
+
+static void
+nativeGetBuffers(EGLSurface surface, unsigned int *attachments, int count)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+ struct EagleBackendNative *backend =
+ (struct EagleBackendNative *) surface->display->backend;
+ __DRIbuffer *buffer;
+ int i;
+
+ buffer = &surface->buffers[0];
+ buffer->pitch = nativeSurface->current->pitch;
+ buffer->name = nativeSurface->current->name;
+ buffer->cpp = nativeSurface->current->cpp;
+
+ if (count == surface->count)
+ return;
+
+ for (i = 0; i < count; i++) {
+ if (attachments[i] == __DRI_BUFFER_DEPTH)
+ surface->depth = i;
+
+ buffer = &surface->buffers[i];
+ buffer->attachment = attachments[i];
+
+ if (buffer->attachment == __DRI_BUFFER_FRONT_LEFT) {
+ buffer->pitch = nativeSurface->current->pitch;
+ buffer->name = nativeSurface->current->name;
+ buffer->cpp = nativeSurface->current->cpp;
+ continue;
+ }
+
+ if (attachments[i] == __DRI_BUFFER_STENCIL) {
+ buffer->name = surface->buffers[surface->depth].name;
+ nativeSurface->handles[i] =
+ nativeSurface->handles[surface->depth];
+ continue;
+ }
+
+ nativeSurface->handles[i] =
+ backend->createBuffer(surface->display->fd,
+ surface->width,
+ surface->height,
+ buffer);
+ }
+
+ surface->count = count;
+}
+
+static EGLBoolean
+nativeDestroySurface(EGLDisplay display, EGLSurface surface)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+ struct drm_gem_close close;
+ int i;
+
+ for (i = 0; i < nativeSurface->colorBufferCount; i++) {
+ close.handle = nativeSurface->colorBufferHandles[i];
+ if (ioctl(surface->display->fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
+ fprintf(stderr, "close of bo %d failed\n", close.handle);
+ }
+
+ for (i = 0; i < surface->count; i++) {
+ close.handle = nativeSurface->handles[i];
+ if (ioctl(surface->display->fd, DRM_IOCTL_GEM_CLOSE, &close) < 0)
+ fprintf(stderr, "close of bo %d failed\n", close.handle);
+ }
+
+ free(surface);
+
+ return EGL_TRUE;
+}
+
+static EGLDisplay
+nativeCreateDisplay(struct udev_device *device,
+ const char *driver, const struct EagleBackend *backend)
+{
+ EGLDisplay display;
+ const char *path;
+
+ display = malloc(sizeof *display);
+ if (display == NULL)
+ return NULL;
+
+ path = udev_device_get_devnode(device);
+ if (eglInitDisplay(display, path, driver) < 0) {
+ free(display);
+ return NULL;
+ }
+
+ display->backend = backend;
+
+ return display;
+}
+
+/* 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);
+ 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");
+ return -1;
+ }
+
+ flink.handle = create.handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
+ fprintf(stderr, "failed to create buffer\n");
+ return -1;
+ }
+
+ buffer->name = flink.name;
+ buffer->cpp = 4;
+
+ return create.handle;
+}
+
+static const struct EagleBackendNative intelBackend = {
+ {
+ nativeGetBuffers,
+ nativeDestroySurface,
+ },
+ intelCreateBuffer
+};
+
+EGLDisplay
+i915CreateDisplay(struct udev_device *device)
+{
+ return nativeCreateDisplay(device, "i915", &intelBackend.base);
+}
+
+EGLDisplay
+i965CreateDisplay(struct udev_device *device)
+{
+ return nativeCreateDisplay(device, "i965", &intelBackend.base);
+}
+
+#define RADEON_ALIGNMENT 64
+
+static int
+radeonCreateBuffer(int fd, GLint width, GLint height, __DRIbuffer *buffer)
+{
+#ifdef DRM_IOCTL_RADEON_GEM_CREATE
+ struct drm_radeon_gem_create create;
+ struct drm_gem_flink flink;
+
+ buffer->pitch = align_to(width * 4, RADEON_ALIGNMENT);
+ buffer->cpp = 4;
+
+ create.size = buffer->pitch * height;
+ create.alignment = 4096;
+ create.initial_domain = RADEON_GEM_DOMAIN_VRAM;
+ create.flags = RADEON_GEM_NO_BACKING_STORE;
+
+ if (ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &create)) {
+ fprintf(stderr, "failed to create buffer\n");
+ return -1;
+ }
+
+ flink.handle = create.handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
+ fprintf(stderr, "failed to create buffer\n");
+ return -1;
+ }
+
+ buffer->name = flink.name;
+
+ return create.handle;
+#else
+ return -1;
+#endif
+}
+
+static const struct EagleBackendNative radeonBackend = {
+ {
+ nativeGetBuffers,
+ nativeDestroySurface,
+ },
+
+ radeonCreateBuffer
+};
+
+EGLDisplay
+r300CreateDisplay(struct udev_device *device)
+{
+ return nativeCreateDisplay(device, "r300", &radeonBackend.base);
+}
+
+EAGLE_EXPORT EGLSurface
+eglCreateSurface(EGLDisplay display, EGLConfig config,
+ uint32_t width, uint32_t height,
+ uint32_t colorBufferCount, const EGLint *attribList)
+{
+ EGLSurfaceNative nativeSurface;
+ int i;
+
+ if (colorBufferCount < 1 || colorBufferCount > 2)
+ return NULL;
+
+ nativeSurface = malloc(sizeof *nativeSurface);
+ if (nativeSurface == NULL)
+ return NULL;
+
+ nativeSurface->current = &nativeSurface->colorBuffers[0];
+ nativeSurface->colorBufferCount = colorBufferCount;
+ for (i = 0; i < colorBufferCount; i++) {
+ nativeSurface->colorBufferHandles[i] =
+ intelCreateBuffer(display->fd,
+ width,
+ height,
+ &nativeSurface->colorBuffers[i]);
+ }
+
+ eglInitSurface(&nativeSurface->base, display, config, width, height);
+
+ return &nativeSurface->base;
+}
+
+EAGLE_EXPORT EGLSurface
+eglCreateSurfaceForName(EGLDisplay display, EGLConfig config,
+ uint32_t name, uint32_t width,
+ uint32_t height, uint32_t stride, const EGLint *attribList)
+{
+ EGLSurfaceNative nativeSurface;
+ struct drm_gem_open open_arg;
+ int ret;
+
+ nativeSurface = malloc(sizeof *nativeSurface);
+ if (nativeSurface == NULL)
+ return NULL;
+
+ nativeSurface->current = &nativeSurface->colorBuffers[0];
+ nativeSurface->colorBufferCount = 1;
+ nativeSurface->colorBuffers[0].attachment = __DRI_BUFFER_FRONT_LEFT;
+ nativeSurface->colorBuffers[0].name = name;
+ nativeSurface->colorBuffers[0].pitch = stride;
+ nativeSurface->colorBuffers[0].cpp = 4;
+ nativeSurface->colorBuffers[0].flags = 0;
+
+ open_arg.name = name;
+ ret = ioctl(display->fd, DRM_IOCTL_GEM_OPEN, &open_arg);
+ if (ret < 0) {
+ free(nativeSurface);
+ return NULL;
+ }
+ nativeSurface->colorBufferHandles[0] = open_arg.handle;
+
+ eglInitSurface(&nativeSurface->base, display, config, width, height);
+
+ return &nativeSurface->base;
+}
+
+EAGLE_EXPORT EGLBoolean
+eglGetColorBuffer(EGLSurface surface, uint32_t index,
+ uint32_t *name, uint32_t *handle, uint32_t *stride)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+
+ if (index >= nativeSurface->colorBufferCount)
+ return EGL_FALSE;
+
+ *name = nativeSurface->colorBuffers[index].name;
+ *handle = nativeSurface->colorBufferHandles[index];
+ *stride = nativeSurface->colorBuffers[index].pitch;
+
+ return EGL_TRUE;
+}
+
+EAGLE_EXPORT EGLBoolean
+eglBindColorBuffer(EGLDisplay display, EGLSurface surface, uint32_t index)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+
+ if (index >= nativeSurface->colorBufferCount)
+ return EGL_FALSE;
+
+ display->flush->flushInvalidate(surface->driDrawable);
+ nativeSurface->current = &nativeSurface->colorBuffers[index];
+
+ return EGL_TRUE;
+}