~mir-team/mir/chain-simplification

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
/*
 * 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 <http://www.gnu.org/licenses/>.
 *
 * Author: Kevin DuBois <kevin.dubois@canonical.com>
 */

#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 <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <stdlib.h>
#include <string.h>

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