summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@redhat.com>2008-12-15 17:34:46 -0500
committerKristian Høgsberg <krh@redhat.com>2008-12-15 17:34:46 -0500
commitc1512b69a5d5414e6712fe47b1ea19f34c1ed5d1 (patch)
tree808f10b1c0cc0a568029bbbd0361b3d857e10507
parent8684ecf0166629773b2ef1b1e049bf0afd0c6e68 (diff)
Add a first attemp at radeon support.
-rw-r--r--Makefile.in15
-rw-r--r--configure.ac6
-rw-r--r--radeon.c334
3 files changed, 354 insertions, 1 deletions
diff --git a/Makefile.in b/Makefile.in
index 152abb1..601763c 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -8,7 +8,17 @@ all : libeagle.so test
x11_dri2_objs = x11-dri2.o libdri2.o
-objs = eagle.o intel.o $(x11_dri2_objs) glapi/glapi.o glapi/dispatch.o glapi/glthread.o glapi/glapi_getproc.o
+intel_objs = intel.o
+radeon_objs = radeon.o
+
+objs = \
+ eagle.o \
+ $(@DRIVER@_objs) \
+ $(x11_dri2_objs) \
+ glapi/glapi.o \
+ glapi/dispatch.o \
+ glapi/glthread.o \
+ glapi/glapi_getproc.o
$(objs) : eagle.h eagle-internal.h
@@ -41,3 +51,6 @@ install : libeagle.so eagle.pc
clean :
rm -f *.o glapi/*.o libeagle.so test
+
+Makefile : Makefile.in
+ ./config.status
diff --git a/configure.ac b/configure.ac
index 30dc6f4..4895300 100644
--- a/configure.ac
+++ b/configure.ac
@@ -11,5 +11,11 @@ if test $CC = gcc; then
fi
AC_SUBST(GCC_CFLAGS)
+# FIXME: We should support both drivers and select at runtime, of course.
+AC_ARG_WITH(driver, AS_HELP_STRING([--with-driver=[intel/radeon]],
+ [Driver to compile for]),
+ [DRIVER=$withval], [DRIVER=intel])
+AC_SUBST(DRIVER)
+
AC_CONFIG_FILES([Makefile eagle.pc])
AC_OUTPUT \ No newline at end of file
diff --git a/radeon.c b/radeon.c
new file mode 100644
index 0000000..5a6fc58
--- /dev/null
+++ b/radeon.c
@@ -0,0 +1,334 @@
+/*
+ * Copyright © 2008 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 <drm.h>
+#include <radeon_drm.h>
+#include <GL/gl.h> /* dri_interface.h uses some GL integer types... */
+#include "eagle-internal.h"
+
+typedef struct EGLDisplayNative *EGLDisplayNative;
+struct EGLDisplayNative {
+ struct EGLDisplay base;
+
+#ifdef __DRI_COPY_BUFFER
+ __DRIcopyBufferExtension *copyBuffer;
+#endif
+};
+
+typedef struct EGLSurfaceNative *EGLSurfaceNative;
+struct EGLSurfaceNative {
+ struct EGLSurface base;
+ uint32_t handles[10];
+ EGLBoolean backBuffer;
+ __DRIbuffer front;
+ uint32_t frontHandle;
+};
+
+static inline uint32_t
+align_to(uint32_t value, uint32_t align)
+{
+ return (value + align - 1) & ~(align - 1);
+}
+
+#define RADEON_ALIGNMENT 64
+
+static void
+nativeGetBuffers(EGLSurface surface, unsigned int *attachments, int count)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+ struct drm_radeon_gem_create create;
+ struct drm_gem_flink flink;
+ struct drm_gem_open open_arg;
+ __DRIbuffer *buffer;
+ uint32_t size;
+ int fd, i, ret;
+
+ 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];
+ buffer->pitch = align_to(surface->width * 4,
+ RADEON_ALIGNMENT);
+ buffer->cpp = 4;
+
+ if (buffer->attachment == __DRI_BUFFER_FRONT_LEFT &&
+ nativeSurface->front.name != ~0 &&
+ !nativeSurface->backBuffer) {
+ buffer->name = nativeSurface->front.name;
+ buffer->pitch = nativeSurface->front.pitch;
+ open_arg.name = buffer->name;
+ ret = ioctl(surface->display->fd,
+ DRM_IOCTL_GEM_OPEN, &open_arg);
+ nativeSurface->handles[i] = open_arg.handle;
+ continue;
+ }
+
+ if (attachments[i] == __DRI_BUFFER_STENCIL) {
+ buffer->name = surface->buffers[surface->depth].name;
+ nativeSurface->handles[i] =
+ nativeSurface->handles[surface->depth];
+ continue;
+ }
+
+ size = buffer->pitch * surface->height;
+ fd = surface->display->fd;
+
+ create.size = size;
+ create.alignment = 4096;
+ create.initial_domain = RADEON_GEM_DOMAIN_VRAM;
+ create.no_backing_store = 1;
+
+ if (ioctl(fd, DRM_IOCTL_RADEON_GEM_CREATE, &create)) {
+ fprintf(stderr, "failed to create buffer\n");
+ return;
+ }
+ nativeSurface->handles[i] = create.handle;
+
+ flink.handle = create.handle;
+ if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
+ fprintf(stderr, "failed to create buffer\n");
+ return;
+ }
+
+ buffer->name = flink.name;
+ }
+
+ surface->count = count;
+}
+
+static EGLBoolean
+nativeDestroySurface(EGLDisplay display, EGLSurface surface)
+{
+ free(surface);
+
+ return EGL_TRUE;
+}
+
+static EGLBoolean
+nativeMemcpySwapBuffers(EGLDisplay display, EGLSurface surface)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+ struct drm_radeon_gem_pread pread;
+ struct drm_radeon_gem_pwrite pwrite;
+ char *data;
+ int stride, i;
+
+ if (!nativeSurface->backBuffer)
+ return EGL_TRUE;
+
+ stride = surface->buffers[0].pitch;
+
+ pread.handle = nativeSurface->handles[0];
+ pread.pad = 0;
+ pread.offset = 0;
+ pread.size = stride * surface->height;
+
+ data = malloc(pread.size);
+ if (data == NULL) {
+ fprintf(stderr, "swap buffers malloc failed\n");
+ return EGL_FALSE;
+ }
+
+ pread.data_ptr = (long) data;
+
+ if (ioctl(display->fd, DRM_IOCTL_RADEON_GEM_PREAD, &pread)) {
+ fprintf(stderr, "gem pread failed\n");
+ return EGL_FALSE;
+ }
+
+ if (nativeSurface->frontHandle == 0) {
+ struct drm_gem_open open_arg;
+
+ open_arg.name = nativeSurface->front.name;
+ if (ioctl(display->fd, DRM_IOCTL_GEM_OPEN, &open_arg)) {
+ fprintf(stderr, "failed to gem_open back buffer\n");
+ return EGL_FALSE;
+ }
+
+ nativeSurface->frontHandle = open_arg.handle;
+ }
+
+
+ for (i = 0; i < surface->height; i++) {
+ pwrite.handle = nativeSurface->frontHandle;
+ pwrite.offset = nativeSurface->front.pitch * i;
+ pwrite.size = surface->width * 4;
+ pwrite.data_ptr = (intptr_t) data + i * stride;
+ if (ioctl(display->fd, DRM_IOCTL_RADEON_GEM_PWRITE, &pwrite)) {
+ fprintf(stderr, "gem pread failed\n");
+ return EGL_FALSE;
+ }
+ }
+
+ free(data);
+
+ return EGL_TRUE;
+}
+
+static const struct EagleBackend radeonMemcpyBackend = {
+ nativeGetBuffers,
+ nativeMemcpySwapBuffers,
+ nativeDestroySurface,
+};
+
+static const char fb_device[] = "/dev/fb";
+
+static void
+nativeInitMemcpy(EGLDisplay display)
+{
+ display->backend = &radeonMemcpyBackend;
+
+ printf("Using memcpy swapbuffer\n");
+}
+
+EGLDisplay
+eglCreateDisplayNative(const char *device, const char *driver)
+{
+ EGLDisplayNative nativeDisplay;
+
+ nativeDisplay = malloc(sizeof *nativeDisplay);
+ if (nativeDisplay == NULL)
+ return NULL;
+
+ if (eglInitDisplay(&nativeDisplay->base, device, driver) < 0) {
+ free(nativeDisplay);
+ return NULL;
+ }
+
+ if (nativeDisplay->base.backend == NULL)
+ nativeInitMemcpy(&nativeDisplay->base);
+
+ return &nativeDisplay->base;
+}
+
+EGLSurface
+eglCreateSurfaceForName(EGLDisplay display, EGLConfig config,
+ uint32_t name, uint32_t width,
+ uint32_t height, uint32_t stride, const EGLint *attribList)
+{
+ EGLSurfaceNative nativeSurface;
+ int i;
+
+ nativeSurface = malloc(sizeof *nativeSurface);
+ if (nativeSurface == NULL)
+ return NULL;
+
+ nativeSurface->backBuffer = EGL_FALSE;
+
+ nativeSurface->front.attachment = __DRI_BUFFER_FRONT_LEFT;
+ nativeSurface->front.name = name;
+ nativeSurface->front.pitch = stride;
+ nativeSurface->front.cpp = 4;
+ nativeSurface->front.flags = 0;
+ nativeSurface->frontHandle = 0;
+
+ eglInitSurface(&nativeSurface->base, display, config, width, height);
+
+ for (i = 0; attribList && attribList[i] != EGL_NONE; i += 2) {
+ if (attribList[i] == EGL_RENDER_BUFFER &&
+ attribList[i + 1] == EGL_BACK_BUFFER)
+ nativeSurface->backBuffer = EGL_TRUE;
+ }
+
+ return &nativeSurface->base;
+}
+
+#ifdef __DRI_COPY_BUFFER
+
+EGLBoolean
+eglCopyNativeBuffers(EGLDisplay display,
+ EGLSurface dst, GLenum dstBuffer, int32_t dst_x, int32_t dst_y,
+ EGLSurface src, GLenum srcBuffer, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ EGLDisplayNative nativeDisplay = (EGLDisplayNative) display;
+ EGLContext context;
+ __DRIbuffer *srcDRIBuffer, *dstDRIBuffer;
+ unsigned int attachments[1];
+
+ context = eglGetCurrentContext();
+
+ /* FIXME: glCopyPixels should work, but then we'll have to
+ * call eglMakeCurrent to set up the src and dest surfaces
+ * first. This seems cheaper, but maybe there's a better way
+ * to accomplish this. */
+
+ attachments[0] = __DRI_BUFFER_FRONT_LEFT;
+ nativeGetBuffers(src, attachments, 1);
+
+ /* FIXME: Actually use dstBuffer and srcBuffer (eg
+ * GL_FRONT_LEFT) to look up the buffers to use. */
+
+ dstDRIBuffer = &dst->buffers[0];
+ srcDRIBuffer = &src->buffers[0];
+
+ return nativeDisplay->copyBuffer->copyBuffer(context->driContext,
+ dstDRIBuffer,
+ dst_x, dst_y,
+ srcDRIBuffer,
+ x, y, width, height);
+}
+
+#endif
+
+void *
+eglReadBuffer(EGLDisplay display,
+ EGLSurface surface, GLenum buffer, GLuint *stride)
+{
+ EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface;
+ struct drm_radeon_gem_pread pread;
+ void *data;
+
+ *stride = surface->buffers[0].pitch;
+ pread.handle = nativeSurface->handles[0];
+ pread.pad = 0;
+ pread.offset = 0;
+ pread.size = *stride * surface->height;
+
+ data = malloc(pread.size);
+ if (data == NULL) {
+ fprintf(stderr, "swap buffers malloc failed\n");
+ return NULL;
+ }
+
+ pread.data_ptr = (long) data;
+
+ if (ioctl(display->fd, DRM_IOCTL_RADEON_GEM_PREAD, &pread)) {
+ fprintf(stderr, "gem pread failed\n");
+ free(data);
+ return NULL;
+ }
+
+ return data;
+}