diff options
author | Kristian Høgsberg <krh@redhat.com> | 2008-12-15 17:34:46 -0500 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2008-12-15 17:34:46 -0500 |
commit | c1512b69a5d5414e6712fe47b1ea19f34c1ed5d1 (patch) | |
tree | 808f10b1c0cc0a568029bbbd0361b3d857e10507 | |
parent | 8684ecf0166629773b2ef1b1e049bf0afd0c6e68 (diff) |
Add a first attemp at radeon support.
-rw-r--r-- | Makefile.in | 15 | ||||
-rw-r--r-- | configure.ac | 6 | ||||
-rw-r--r-- | radeon.c | 334 |
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; +} |