/*
* 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);
}