/* * Copyright © 2016 Canonical Ltd. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License version 3 as * published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * * Author: Kevin DuBois */ #include "mir_egl_platform_shim.h" #include "mir_toolkit/mir_client_library.h" #include "mir_toolkit/mir_extension_core.h" #include "mir_toolkit/extensions/android_egl.h" #include #include #include #include //Information the driver will have to maintain typedef struct { MirConnection* connection; //EGLNativeDisplayType MirRenderSurface* surface; //EGLNativeWindowType MirBufferStream* stream; //the internal semantics a driver might want to use... //could be MirRenderSurface as well int current_physical_width; //The driver is in charge of the physical width int current_physical_height; //The driver is in charge of the physical height struct MirExtensionAndroidEGL* ext; PFNEGLCREATEIMAGEKHRPROC eglCreateImageKHR; PFNEGLDESTROYIMAGEKHRPROC eglDestroyImageKHR; PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2DOES; } DriverInfo; static DriverInfo* info = NULL; typedef struct { struct ANativeWindowBuffer *buffer; EGLImageKHR img; } ShimEGLImageKHR; EGLSurface future_driver_eglCreateWindowSurface( EGLDisplay display, EGLConfig config, MirRenderSurface* surface, const EGLint* attr) { if (info->surface) { printf("shim only supports one surface at the moment"); return EGL_NO_SURFACE; } info->surface = surface; mir_render_surface_get_size(surface, &info->current_physical_width, &info->current_physical_height); //TODO: the driver needs to be selecting a pixel format that's acceptable based on // the EGLConfig. mir_connection_get_egl_pixel_format // needs to be deprecated once the drivers support the Mir EGL platform. MirPixelFormat pixel_format = mir_connection_get_egl_pixel_format(info->connection, display, config); //this particular [silly] driver has chosen the buffer stream as the way it wants to post //its hardware content. I'd think most drivers would want MirPresentationChain for flexibility info->stream = mir_render_surface_get_buffer_stream(surface, info->current_physical_width, info->current_physical_height, pixel_format, mir_buffer_usage_hardware); printf("The driver chose pixel format %d.\n", pixel_format); return eglCreateWindowSurface(display, config, (EGLNativeWindowType) surface, attr); } EGLBoolean future_driver_eglSwapBuffers(EGLDisplay display, EGLSurface surface) { int width = -1; int height = -1; mir_render_surface_get_size(info->surface, &width, &height); if (width != info->current_physical_width || height != info->current_physical_height) { //note that this affects the next buffer that we get after swapbuffers. mir_buffer_stream_set_size(info->stream, width, height); info->current_physical_width = width; info->current_physical_height = height; } return eglSwapBuffers(display, surface); } EGLDisplay future_driver_eglGetDisplay(MirConnection* connection) { if (info) { printf("shim only supports one display connection at the moment"); return EGL_NO_DISPLAY; } info = malloc(sizeof(DriverInfo)); memset(info, 0, sizeof(*info)); info->connection = connection; info->ext = (struct MirExtensionAndroidEGL*) mir_connection_request_interface( info->connection, MIR_EXTENSION_ANDROID_EGL, MIR_EXTENSION_ANDROID_EGL_VERSION_1); info->eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR"); info->eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR"); info->glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES"); return eglGetDisplay(mir_connection_get_egl_native_display(connection)); } EGLBoolean future_driver_eglTerminate(EGLDisplay display) { if (info) free(info); return eglTerminate(display); } EGLImageKHR future_driver_eglCreateImageKHR( EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list) { //bit pedantic, but we should validate the parameters we require from the extension if ( (target != EGL_NATIVE_PIXMAP_KHR) || (ctx != EGL_NO_CONTEXT) || !info || !info->ext ) return EGL_NO_IMAGE_KHR; //check we have subloaded extension available. if(!strstr(eglQueryString(dpy, EGL_EXTENSIONS), "EGL_ANDROID_image_native_buffer")) return EGL_NO_IMAGE_KHR; static EGLint const expected_attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE }; int i = 0; while ( (attrib_list[i] != EGL_NONE) && (expected_attrs[i] != EGL_NONE) ) { if (attrib_list[i] != expected_attrs[i]) return EGL_NO_IMAGE_KHR; i++; } ShimEGLImageKHR* img = (ShimEGLImageKHR*) malloc(sizeof(ShimEGLImageKHR)); img->buffer = info->ext->create_buffer(buffer); img->img = info->eglCreateImageKHR(dpy, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, img->buffer, attrib_list); return (EGLImageKHR) img; } EGLBoolean future_driver_eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image) { if (!info) return EGL_FALSE; ShimEGLImageKHR* img = (ShimEGLImageKHR*) image; EGLBoolean rc = info->eglDestroyImageKHR(dpy, image); info->ext->destroy_buffer(img->buffer); free(img); return rc; } void future_driver_glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image) { if (!info) return; ShimEGLImageKHR* img = (ShimEGLImageKHR*) image; info->glEGLImageTargetTexture2DOES(target, img->img); }