/* * 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 #include #include #include #include #include #include #include #include #include /* dri_interface.h uses some GL integer types... */ #include "eagle-internal.h" #define INTEL_STRIDE_ALIGNMENT 64 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); } 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; buffer->pitch = align_to(width * 4, INTEL_STRIDE_ALIGNMENT); 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; } 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 void intelGetBuffers(EGLSurface surface, unsigned int *attachments, int count) { EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface; __DRIbuffer *buffer; struct drm_gem_open open_arg; int 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]; if (buffer->attachment == __DRI_BUFFER_FRONT_LEFT && nativeSurface->front.name != ~0 && !nativeSurface->backBuffer) { buffer->name = nativeSurface->front.name; buffer->pitch = nativeSurface->front.pitch; buffer->cpp = 4; 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; } nativeSurface->handles[i] = intelCreateBuffer(surface->display->fd, surface->width, surface->height, buffer); } surface->count = count; } static EGLBoolean intelDestroySurface(EGLDisplay display, EGLSurface surface) { EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface; struct drm_gem_close close; int i; 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 EGLBoolean intelSwapBuffers(EGLDisplay display, EGLSurface surface) { EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface; EGLContext context; if (!nativeSurface->backBuffer) return EGL_TRUE; context = eglGetCurrentContext(); display->copyBuffer->copyBuffer(context->driContext, &nativeSurface->front, 0, 0, surface->driDrawable, __DRI_BUFFER_FRONT_LEFT, 0, 0, surface->width, surface->height); glFlush(); return EGL_TRUE; } static EGLSurface intelCreateSurfaceForName(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; if (name == 0) { nativeSurface->frontHandle = intelCreateBuffer(display->fd, width, height, &nativeSurface->front); } else { 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; } static const struct EagleBackend intelBackend = { intelGetBuffers, intelSwapBuffers, intelDestroySurface, intelCreateSurfaceForName }; static EGLDisplay intelCreateDisplay(struct udev_device *device, const char *driver) { 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 = &intelBackend; return display; } EAGLE_EXPORT EGLBoolean eglGetNativeBuffer(EGLSurface surface, GLenum buffer, uint32_t *name, uint32_t *stride) { EGLSurfaceNative nativeSurface = (EGLSurfaceNative) surface; switch (buffer) { case GL_FRONT_LEFT: *name = nativeSurface->front.name; *stride = nativeSurface->front.pitch; return EGL_TRUE; case GL_BACK_LEFT: *name = surface->buffers[0].name; *stride = surface->buffers[0].pitch; return EGL_TRUE; default: return EGL_FALSE; } } EGLDisplay i915CreateDisplay(struct udev_device *device) { return intelCreateDisplay(device, "i915"); } EGLDisplay i965CreateDisplay(struct udev_device *device) { return intelCreateDisplay(device, "i965"); }