Mir

Merge lp:~cemil-azizoglu/mir/egl-native-window-for-PCs into lp:mir

Proposed by Cemil Azizoglu
Status: Work in progress
Proposed branch: lp:~cemil-azizoglu/mir/egl-native-window-for-PCs
Merge into: lp:mir
Prerequisite: lp:~kdub/mir/fix-1584784
Diff against target: 2285 lines (+1513/-425)
24 files modified
playground/CMakeLists.txt (+10/-0)
playground/eglflash_nbs.c (+155/-0)
src/client/CMakeLists.txt (+2/-0)
src/client/buffer_semantics.h (+410/-0)
src/client/buffer_stream.cpp (+3/-363)
src/client/buffer_stream.h (+1/-2)
src/client/error_chain.cpp (+5/-0)
src/client/error_chain.h (+1/-0)
src/client/exchange_semantics.cpp (+173/-0)
src/client/exchange_semantics.h (+70/-0)
src/client/mir_connection.cpp (+1/-1)
src/client/mir_presentation_chain.h (+13/-0)
src/client/mir_presentation_chain_api.cpp (+13/-0)
src/client/new_buffer_semantics.cpp (+181/-0)
src/client/new_buffer_semantics.h (+79/-0)
src/client/presentation_chain.cpp (+99/-6)
src/client/presentation_chain.h (+31/-4)
src/client/server_buffer_semantics.h (+59/-0)
src/client/symbols.map (+1/-0)
src/include/client/mir_toolkit/mir_presentation_chain.h (+17/-0)
tests/unit-tests/client/stub_client_platform.h (+79/-0)
tests/unit-tests/client/test_client_buffer_stream.cpp (+2/-43)
tests/unit-tests/client/test_connection_resource_map.cpp (+1/-1)
tests/unit-tests/client/test_presentation_chain.cpp (+107/-5)
To merge this branch: bzr merge lp:~cemil-azizoglu/mir/egl-native-window-for-PCs
Reviewer Review Type Date Requested Status
Mir CI Bot continuous-integration Needs Fixing
Chris Halse Rogers Disapprove
Kevin DuBois (community) Needs Fixing
Review via email: mp+296344@code.launchpad.net

This proposal supersedes a proposal from 2016-06-02.

Commit message

Support for egl native window from presentation chains.

Description of the change

Support for egl native window from presentation chains.

To post a comment you must log in.
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:3528
https://mir-jenkins.ubuntu.com/job/mir-ci/1075/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1187/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1237
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1228
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1228
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1197
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1197/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1197
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1197/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1197/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1197/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1197
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1197/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1197/console

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1075/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

Planning note:
 src/client/buffer_semantics.h
is an abstraction that was meant to help with the transition. Hopefully it goes away soon, an "NewBufferSemantics" implementation gets condensed into mcl::BufferVault (this would greatly simplify the code).

Needs fixing:
The code needs some of the fixes in lp:~kdub/mir/fix-1584784 in order to avoid reintroducing that bug.

review: Needs Fixing
Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

mir_presentation_chain_get_egl_native_window

is misleading about what MirPresentationChains are. They are generic buffer queues, and tying them to a specific technology (egl) can be avoided. We should have

MirEGLNativeWindowType mir_create_egl_native_window(MirPresentationChain*, int width, int height, MirPixelFormat pixel_format);

so that its a bit clearer that this more of a helper function to extend the use of MirPresentationChain, as opposed to something that's core to the mir_presentation_chain* generic functions.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

+ virtual EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) = 0;

In the same line of thought, a MirPresentationChain is not a EGLNativeWindowType, rather, an EGLNativeWindowType can be created using a MirPresentationChain.

This is internal, so can be changed easily so that the EGLNativeWindowType can take the PresentationChain in its constructor. (so its probably non blocking, but is something that needs a cleanup once the buffer_semantics.h header gets cleaned up, as mentioned above)

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal

Also, I think that MirBufferStream shouldn't go away. It fits a need that the clients have (as well as being used extensively in the wild).

Made some design drawings:
A) How things are in current design:
https://docs.google.com/drawings/d/1U03QrxQwPFYVfryC_-xOb64D3GRYIkJCAyw8LEWbbIk

B) how things would be with mir_presentation_chain_get_egl_native_window_type(...):
https://docs.google.com/drawings/d/1cX54j6Wv7TRuWLCXRuUyni9RgyuljWGEAlalDirwAys

C) How things would be with mir_create_egl_native_window_type(...):
https://docs.google.com/drawings/d/1yze9GbDb4pbGyQM7pXPDWXqrToW9Ko3gaAtWt9DeV_Q

A) and C) keep the MirPresentationChain just a thin wrapper around the RPC (which is useful for building future technologies). IMO, A) is a bit better because we only have one way of supporting EGL.

Revision history for this message
Kevin DuBois (kdub) wrote : Posted in a previous version of this proposal
Revision history for this message
Cemil Azizoglu (cemil-azizoglu) wrote :

@kdub, I've changed the name to mir_create_egl_native_window_type and rebased it with lp:~kdub/mir/fix-1584784 as prereq.

I'd rather not invest more time into the internal refactoring for now. I have a feeling we'll go back and clean this up with the MirRenderable idea that we discussed over email.

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote : Posted in a previous version of this proposal

FAILED: Continuous integration, rev:3530
https://mir-jenkins.ubuntu.com/job/mir-ci/1078/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1190/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1240
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1231
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1231
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1200
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1200/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1200
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1200/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1200/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1200/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1200
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1200/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1200
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1200/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1078/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3530
https://mir-jenkins.ubuntu.com/job/mir-ci/1079/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1191/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1241
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1232
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1232
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1201
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1201/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1201
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1201/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1201/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1201/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1201
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1201/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1201
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1201/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1079/rebuild

review: Needs Fixing (continuous-integration)
Revision history for this message
Kevin DuBois (kdub) wrote :

re, refactorings:
If we're pressed for time, I suppose that we can do the refactorings, later, but IMO, delaying a bit to avoid establishing this relationship :
+class PresentationChain : public MirPresentationChain, public EGLNativeSurface
internally is worth it.

The external bit (which is the hard part to change), is resolved IMO with the client API name change, thanks.

considerations:
eglflash_nbs could be renamed eglflash_presentation_chain (nbs won't have much permanent context, especially for mir 'outsiders'). We could also have a switch in eglapp that would switch between the two modes (and give a lot more ways to use the new code)

needs fixings:
src/client/buffer_semantics.h
+namespace
+{
anonymous namespace in header. The code should also be moved to a .cpp file.

The header also seems like we're overexposing some classes when they're not needed elsewhere... ExchangeSemantics doesn't seem like its needed anywhere in the new code. <optional> We could also hide the interface by just exposing the SubmitSemantics class, and then wrapping in buffer_stream.cpp

tests/unit-tests/client/stub_client_platform.h
should be in tests/include/mir/test/doubles (or tests/include/mir_test_framework). The namespace should match where it lives instead of being anonymous.
Also, we already have mtf::StubClientPlatform, maybe making that more accessible to the test is the way to go.

 * Extract an MirEGLNativeWindowType object from a given presentation chain.
needs an update to
"Create a MirEGLNativeWindowType object from a given MirPresentationChain"

review: Needs Fixing
Revision history for this message
Chris Halse Rogers (raof) wrote :

So, as I've mentioned before, I think that both of these approaches are incorrect; EGL clients shouldn't know that the EGL implementation is using a MirPresentationChain or a MirBufferQueue.

We've got this on the agenda for the sprint next week, so I think we should not introduce extra client API that we'll probably immediately deprecate.

review: Disapprove
3531. By Cemil Azizoglu

Separate ServerBufferSemantics interfaces

Revision history for this message
Mir CI Bot (mir-ci-bot) wrote :

FAILED: Continuous integration, rev:3531
https://mir-jenkins.ubuntu.com/job/mir-ci/1080/
Executed test runs:
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-mir/1196/console
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-0-fetch/1246
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=vivid+overlay/1237
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-1-sourcepkg/release=xenial/1237
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1206
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=clang,platform=mesa,release=vivid+overlay/1206/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1206
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=amd64,compiler=gcc,platform=mesa,release=xenial/1206/artifact/output/*zip*/output.zip
    FAILURE: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1206/console
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=cross-armhf,compiler=gcc,platform=android,release=vivid+overlay/1206/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1206
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=android,release=vivid+overlay/1206/artifact/output/*zip*/output.zip
    SUCCESS: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1206
        deb: https://mir-jenkins.ubuntu.com/job/build-2-binpkg-mir/arch=i386,compiler=gcc,platform=mesa,release=xenial/1206/artifact/output/*zip*/output.zip

Click here to trigger a rebuild:
https://mir-jenkins.ubuntu.com/job/mir-ci/1080/rebuild

review: Needs Fixing (continuous-integration)

Unmerged revisions

3531. By Cemil Azizoglu

Separate ServerBufferSemantics interfaces

3530. By Cemil Azizoglu

s/mir_presentation_chain_get_egl_native_window/mir_create_egl_native_window

3529. By Cemil Azizoglu

merge with lp:~kdub/mir/fix-1584784

3528. By Cemil Azizoglu

Do away with extraneous printfs

3527. By Cemil Azizoglu

Revert x-compile script

3526. By Cemil Azizoglu

EGLNativeWindowType support for presentation chains

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'playground/CMakeLists.txt'
2--- playground/CMakeLists.txt 2016-05-03 06:55:25 +0000
3+++ playground/CMakeLists.txt 2016-06-03 01:46:54 +0000
4@@ -28,3 +28,13 @@
5 mirclient
6 m
7 )
8+
9+mir_add_wrapped_executable(mir_demo_client_eglflash_nbs
10+ eglflash_nbs.c
11+)
12+
13+target_link_libraries(mir_demo_client_eglflash_nbs
14+ mirclient
15+ ${EGL_LIBRARIES}
16+ ${GLESv2_LIBRARIES}
17+)
18
19=== added file 'playground/eglflash_nbs.c'
20--- playground/eglflash_nbs.c 1970-01-01 00:00:00 +0000
21+++ playground/eglflash_nbs.c 2016-06-03 01:46:54 +0000
22@@ -0,0 +1,155 @@
23+/*
24+ * Trivial GL demo; flashes the screen with nbs.
25+ *
26+ * Copyright © 2016 Canonical Ltd.
27+ *
28+ * This program is free software: you can redistribute it and/or modify
29+ * it under the terms of the GNU General Public License version 3 as
30+ * published by the Free Software Foundation.
31+ *
32+ * This program is distributed in the hope that it will be useful,
33+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
34+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35+ * GNU General Public License for more details.
36+ *
37+ * You should have received a copy of the GNU General Public License
38+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
39+ *
40+ * Author: Cemil Azizoglu <cemil.azizoglu@canonical.com>
41+ */
42+
43+#include <mir_toolkit/mir_client_library.h>
44+#include <mir_toolkit/mir_presentation_chain.h>
45+#include <mir_toolkit/mir_buffer.h>
46+
47+#include <stdio.h>
48+#include <string.h>
49+#include <unistd.h>
50+#include <EGL/egl.h>
51+#include <GLES2/gl2.h>
52+#include <pthread.h>
53+
54+typedef struct Color
55+{
56+ GLfloat r, g, b, a;
57+} Color;
58+
59+#define CHECK(_cond, _err) \
60+ if (!(_cond)) \
61+ { \
62+ printf("%s\n", (_err)); \
63+ return -1; \
64+ }
65+
66+int main(int argc, char *argv[])
67+{
68+ (void) argc;
69+ (void) argv;
70+ unsigned int num_frames = 0;
71+ const char* appname = "eglnbsdemo";
72+ int width = 100;
73+ int height = 100;
74+ EGLDisplay egldisplay;
75+ EGLSurface eglsurface;
76+ EGLint ctxattribs[] =
77+ {
78+ EGL_CONTEXT_CLIENT_VERSION, 2,
79+ EGL_NONE
80+ };
81+ EGLConfig eglconfig;
82+ EGLint neglconfigs;
83+ EGLContext eglctx;
84+ EGLBoolean ok;
85+ MirConnection* connection = NULL;
86+ MirSurface* surface = NULL;
87+ MirPresentationChain* chain = NULL;
88+
89+ connection = mir_connect_sync(NULL, appname);
90+ CHECK(mir_connection_is_valid(connection), "Can't get connection");
91+
92+ egldisplay = eglGetDisplay(
93+ mir_connection_get_egl_native_display(connection));
94+ CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay");
95+
96+ ok = eglInitialize(egldisplay, NULL, NULL);
97+ CHECK(ok, "Can't eglInitialize");
98+
99+ const EGLint attribs[] =
100+ {
101+ EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
102+ EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
103+ EGL_RED_SIZE, 8,
104+ EGL_GREEN_SIZE, 8,
105+ EGL_BLUE_SIZE, 8,
106+ EGL_ALPHA_SIZE, 8,
107+ EGL_NONE
108+ };
109+
110+ ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs);
111+ CHECK(ok, "Could not eglChooseConfig");
112+ CHECK(neglconfigs > 0, "No EGL config available");
113+
114+ MirPixelFormat pixel_format =
115+ mir_connection_get_egl_pixel_format(connection, egldisplay, eglconfig);
116+
117+ printf("Mir chose pixel format %d.\n", pixel_format);
118+
119+ MirSurfaceSpec *spec =
120+ mir_connection_create_spec_for_normal_surface(connection, width, height, pixel_format);
121+
122+ CHECK(spec, "Can't create a surface spec");
123+
124+ mir_surface_spec_set_name(spec, appname);
125+
126+ chain = mir_connection_create_presentation_chain_sync(connection);
127+ CHECK(mir_presentation_chain_is_valid(chain), "Can't create presentation chain");
128+
129+ mir_surface_spec_add_presentation_chain(
130+ spec, width, height, 0, 0, chain);
131+
132+ surface = mir_surface_create_sync(spec);
133+
134+ mir_surface_spec_release(spec);
135+
136+ eglsurface = eglCreateWindowSurface(egldisplay, eglconfig,
137+ (EGLNativeWindowType)mir_create_egl_native_window(chain, width, height, pixel_format), NULL);
138+
139+ CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
140+
141+ eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
142+ ctxattribs);
143+ CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed");
144+
145+ ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx);
146+ CHECK(ok, "Can't eglMakeCurrent");
147+
148+ Color red = {1.0f, 0.0f, 0.0f, 1.0f};
149+ Color green = {0.0f, 1.0f, 0.0f, 1.0f};
150+ Color blue = {0.0f, 0.0f, 1.0f, 1.0f};
151+
152+ do
153+ {
154+ glClearColor(red.r, red.g, red.b, red.a);
155+ glClear(GL_COLOR_BUFFER_BIT);
156+ eglSwapBuffers(egldisplay, eglsurface);
157+ sleep(1);
158+
159+ glClearColor(green.r, green.g, green.b, green.a);
160+ glClear(GL_COLOR_BUFFER_BIT);
161+ eglSwapBuffers(egldisplay, eglsurface);
162+ sleep(1);
163+
164+ glClearColor(blue.r, blue.g, blue.b, blue.a);
165+ glClear(GL_COLOR_BUFFER_BIT);
166+ eglSwapBuffers(egldisplay, eglsurface);
167+ sleep(1);
168+ } while (num_frames++ < 3);
169+
170+ eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
171+ eglTerminate(egldisplay);
172+ mir_presentation_chain_release(chain);
173+ mir_surface_release_sync(surface);
174+ mir_connection_release(connection);
175+
176+ return 0;
177+}
178
179=== modified file 'src/client/CMakeLists.txt'
180--- src/client/CMakeLists.txt 2016-06-02 05:33:50 +0000
181+++ src/client/CMakeLists.txt 2016-06-03 01:46:54 +0000
182@@ -88,6 +88,8 @@
183 mir_error.cpp
184 mir_error.h
185 mir_error_api.cpp
186+ exchange_semantics.cpp
187+ new_buffer_semantics.cpp
188 ${MIR_CLIENT_SOURCES}
189 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h
190 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_display_configuration.h
191
192=== added file 'src/client/buffer_semantics.h'
193--- src/client/buffer_semantics.h 1970-01-01 00:00:00 +0000
194+++ src/client/buffer_semantics.h 2016-06-03 01:46:54 +0000
195@@ -0,0 +1,410 @@
196+/*
197+ * Copyright © 2016 Canonical Ltd.
198+ *
199+ * This program is free software: you can redistribute it and/or modify
200+ * it under the terms of the GNU Lesser General Public License version 3 as
201+ * published by the Free Software Foundation.
202+ *
203+ * This program is distributed in the hope that it will be useful,
204+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
205+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
206+ * GNU Lesser General Public License for more details.
207+ *
208+ * You should have received a copy of the GNU Lesser General Public License
209+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
210+ *
211+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
212+ */
213+
214+#include "buffer_stream.h"
215+#include "buffer.h"
216+#include "buffer_factory.h"
217+#include "make_protobuf_object.h"
218+#include "mir_connection.h"
219+#include "perf_report.h"
220+#include "logging/perf_report.h"
221+#include "rpc/mir_display_server.h"
222+#include "mir_protobuf.pb.h"
223+#include "buffer_vault.h"
224+#include "protobuf_to_native_buffer.h"
225+#include "buffer.h"
226+#include "connection_surface_map.h"
227+
228+#include "mir/log.h"
229+#include "mir/client_platform.h"
230+#include "mir/frontend/client_constants.h"
231+#include "mir_toolkit/mir_native_buffer.h"
232+
233+#include <boost/throw_exception.hpp>
234+#include <boost/exception/diagnostic_information.hpp>
235+
236+#include <stdexcept>
237+
238+namespace mcl = mir::client;
239+namespace mclr = mir::client::rpc;
240+namespace mf = mir::frontend;
241+namespace mp = mir::protobuf;
242+namespace geom = mir::geometry;
243+
244+namespace mir
245+{
246+namespace client
247+{
248+//An internal interface useful in transitioning buffer exchange semantics based on
249+//the BufferStream response provided by the server
250+struct ServerBufferSemantics
251+{
252+ virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0;
253+ virtual void set_buffer_cache_size(unsigned int) = 0;
254+ virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0;
255+ virtual uint32_t current_buffer_id() = 0;
256+ virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
257+ virtual void lost_connection() = 0;
258+ virtual void set_size(geom::Size) = 0;
259+ virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0;
260+ virtual void set_interval(int interval) = 0;
261+ virtual geom::Size size() const = 0;
262+ virtual ~ServerBufferSemantics() = default;
263+ ServerBufferSemantics() = default;
264+ ServerBufferSemantics(ServerBufferSemantics const&) = delete;
265+ ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
266+};
267+}
268+}
269+
270+namespace
271+{
272+
273+struct ExchangeSemantics : mcl::ServerBufferSemantics
274+{
275+ ExchangeSemantics(
276+ mir::protobuf::DisplayServer& server,
277+ std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers,
278+ mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
279+ wrapped{factory, max_buffers},
280+ display_server(server),
281+ size_(first_size)
282+ {
283+ wrapped.deposit_package(
284+ mcl::protobuf_to_native_buffer(first_buffer),
285+ first_buffer.buffer_id(), first_size, first_pf);
286+ }
287+
288+ void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override
289+ {
290+ std::unique_lock<std::mutex> lock(mutex);
291+ if (size.is_set())
292+ size_ = size.value();
293+
294+ if (on_incoming_buffer)
295+ {
296+ wrapped.deposit_package(
297+ mcl::protobuf_to_native_buffer(buffer),
298+ buffer.buffer_id(), size_, pf);
299+ if (on_incoming_buffer)
300+ {
301+ on_incoming_buffer();
302+ next_buffer_wait_handle.result_received();
303+ on_incoming_buffer = std::function<void()>{};
304+ }
305+ }
306+ else
307+ {
308+ incoming_buffers.push(buffer);
309+ }
310+ }
311+
312+ void set_buffer_cache_size(unsigned int sz) override
313+ {
314+ std::unique_lock<std::mutex> lock(mutex);
315+ wrapped.set_max_buffers(sz);
316+ }
317+ std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
318+ {
319+ std::unique_lock<std::mutex> lock(mutex);
320+ return wrapped.current_buffer();
321+ }
322+ uint32_t current_buffer_id() override
323+ {
324+ std::unique_lock<std::mutex> lock(mutex);
325+ if (incoming_buffers.size())
326+ return incoming_buffers.front().buffer_id();
327+ return wrapped.current_buffer_id();
328+ }
329+
330+ MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override
331+ {
332+ std::unique_lock<std::mutex> lock(mutex);
333+ if (server_connection_lost)
334+ BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
335+ //always submit what we have, whether we have a buffer, or will have to wait for an async reply
336+ auto request = mcl::make_protobuf_object<mp::BufferRequest>();
337+ request->mutable_id()->set_value(stream_id);
338+ request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
339+ lock.unlock();
340+
341+ display_server.submit_buffer(request.get(), protobuf_void.get(),
342+ google::protobuf::NewCallback(google::protobuf::DoNothing));
343+
344+ lock.lock();
345+ if (server_connection_lost)
346+ BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
347+ if (incoming_buffers.empty())
348+ {
349+ next_buffer_wait_handle.expect_result();
350+ on_incoming_buffer = done;
351+ }
352+ else
353+ {
354+ wrapped.deposit_package(
355+ mcl::protobuf_to_native_buffer(incoming_buffers.front()),
356+ incoming_buffers.front().buffer_id(), size_, pf);
357+ incoming_buffers.pop();
358+ done();
359+ }
360+ return &next_buffer_wait_handle;
361+ }
362+
363+ void lost_connection() override
364+ {
365+ std::unique_lock<std::mutex> lock(mutex);
366+ server_connection_lost = true;
367+ if (on_incoming_buffer)
368+ {
369+ on_incoming_buffer();
370+ on_incoming_buffer = std::function<void()>{};
371+ }
372+ if (next_buffer_wait_handle.is_pending())
373+ next_buffer_wait_handle.result_received();
374+
375+ while (!incoming_buffers.empty())
376+ {
377+ auto b = incoming_buffers.front();
378+ for (auto i = 0; i < b.fd_size(); i++)
379+ close(b.fd(i));
380+ incoming_buffers.pop();
381+ }
382+ }
383+
384+ void set_size(geom::Size) override
385+ {
386+ }
387+
388+ geom::Size size() const override
389+ {
390+ std::unique_lock<std::mutex> lk(mutex);
391+ return size_;
392+ }
393+
394+ void on_scale_set(float scale)
395+ {
396+ std::unique_lock<decltype(mutex)> lock(mutex);
397+ scale_ = scale;
398+ scale_wait_handle.result_received();
399+ }
400+
401+ MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override
402+ {
403+ mp::StreamConfiguration configuration;
404+ configuration.mutable_id()->set_value(stream_id.as_value());
405+ configuration.set_scale(scale);
406+ scale_wait_handle.expect_result();
407+
408+ display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
409+ google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
410+ return &scale_wait_handle;
411+ }
412+
413+ void set_interval(int) override
414+ {
415+ }
416+
417+ std::mutex mutable mutex;
418+ mcl::ClientBufferDepository wrapped;
419+ mir::protobuf::DisplayServer& display_server;
420+ std::function<void()> on_incoming_buffer;
421+ std::queue<mir::protobuf::Buffer> incoming_buffers;
422+ std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()};
423+ MirWaitHandle next_buffer_wait_handle;
424+ bool server_connection_lost {false};
425+ MirWaitHandle scale_wait_handle;
426+ float scale_;
427+ geom::Size size_;
428+};
429+
430+class Requests : public mcl::ServerBufferRequests
431+{
432+public:
433+ Requests(mclr::DisplayServer& server, int stream_id) :
434+ server(server),
435+ stream_id(stream_id)
436+ {
437+ }
438+
439+ void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override
440+ {
441+ mp::BufferAllocation request;
442+ request.mutable_id()->set_value(stream_id);
443+ auto buf_params = request.add_buffer_requests();
444+ buf_params->set_width(size.width.as_int());
445+ buf_params->set_height(size.height.as_int());
446+ buf_params->set_pixel_format(format);
447+ buf_params->set_buffer_usage(usage);
448+
449+ //note, NewCallback will trigger on exception, deleting this object there
450+ auto protobuf_void = new mp::Void;
451+ server.allocate_buffers(&request, protobuf_void,
452+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
453+ }
454+
455+ void free_buffer(int buffer_id) override
456+ {
457+ mp::BufferRelease request;
458+ request.mutable_id()->set_value(stream_id);
459+ request.add_buffers()->set_buffer_id(buffer_id);
460+
461+ //note, NewCallback will trigger on exception, deleting this object there
462+ auto protobuf_void = new mp::Void;
463+ server.release_buffers(&request, protobuf_void,
464+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
465+ }
466+
467+ void submit_buffer(mcl::Buffer& buffer) override
468+ {
469+ mp::BufferRequest request;
470+ request.mutable_id()->set_value(stream_id);
471+ request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
472+
473+ //note, NewCallback will trigger on exception, deleting this object there
474+ auto protobuf_void = new mp::Void;
475+ server.submit_buffer(&request, protobuf_void,
476+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
477+ }
478+
479+ static void ignore_response(mp::Void* void_response)
480+ {
481+ delete void_response;
482+ }
483+
484+private:
485+ mclr::DisplayServer& server;
486+ mp::Void protobuf_void;
487+ int stream_id;
488+};
489+
490+struct NewBufferSemantics : mcl::ServerBufferSemantics
491+{
492+ NewBufferSemantics(
493+ std::shared_ptr<mcl::ClientBufferFactory> const& factory,
494+ std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
495+ std::shared_ptr<mcl::ServerBufferRequests> const& requests,
496+ std::weak_ptr<mcl::SurfaceMap> const& surface_map,
497+ geom::Size size, MirPixelFormat format, int usage,
498+ unsigned int initial_nbuffers) :
499+ vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
500+ current(nullptr),
501+ future(vault.withdraw()),
502+ size_(size)
503+ {
504+ }
505+
506+ void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override
507+ {
508+ }
509+
510+ void advance_current_buffer(std::unique_lock<std::mutex>& lk)
511+ {
512+ lk.unlock();
513+ auto c = future.get();
514+ lk.lock();
515+ current = c;
516+ }
517+
518+ std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
519+ {
520+ std::unique_lock<std::mutex> lk(mutex);
521+ if (!current)
522+ advance_current_buffer(lk);
523+ return current->client_buffer();
524+ }
525+
526+ uint32_t current_buffer_id() override
527+ {
528+ std::unique_lock<std::mutex> lk(mutex);
529+ if (!current)
530+ advance_current_buffer(lk);
531+ return current->rpc_id();
532+ }
533+
534+ MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override
535+ {
536+ std::unique_lock<std::mutex> lk(mutex);
537+ if (!current)
538+ advance_current_buffer(lk);
539+ auto c = current;
540+ current = nullptr;
541+ lk.unlock();
542+
543+ vault.deposit(c);
544+ auto wh = vault.wire_transfer_outbound(c, done);
545+ auto f = vault.withdraw();
546+ lk.lock();
547+ future = std::move(f);
548+ return wh;
549+ }
550+
551+ void set_size(geom::Size size) override
552+ {
553+ {
554+ std::unique_lock<std::mutex> lk(mutex);
555+ size_ = size;
556+ }
557+ vault.set_size(size);
558+ }
559+
560+ geom::Size size() const override
561+ {
562+ std::unique_lock<std::mutex> lk(mutex);
563+ return size_;
564+ }
565+
566+ void lost_connection() override
567+ {
568+ vault.disconnected();
569+ }
570+
571+ void set_buffer_cache_size(unsigned int) override
572+ {
573+ }
574+
575+ MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override
576+ {
577+ scale_wait_handle.expect_result();
578+ scale_wait_handle.result_received();
579+ vault.set_scale(scale);
580+ return &scale_wait_handle;
581+ }
582+
583+ void set_interval(int interval) override
584+ {
585+ std::unique_lock<decltype(mutex)> lk(mutex);
586+ interval = std::max(0, std::min(1, interval));
587+ if (current_swap_interval == interval)
588+ return;
589+ if (interval == 0)
590+ vault.increase_buffer_count();
591+ else
592+ vault.decrease_buffer_count();
593+ current_swap_interval = interval;
594+ }
595+
596+ mcl::BufferVault vault;
597+ std::mutex mutable mutex;
598+ std::shared_ptr<mcl::Buffer> current{nullptr};
599+ mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future;
600+ MirWaitHandle scale_wait_handle;
601+ int current_swap_interval = 1;
602+ geom::Size size_;
603+};
604+
605+}
606
607=== modified file 'src/client/buffer_stream.cpp'
608--- src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000
609+++ src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000
610@@ -37,6 +37,9 @@
611 #include "mir/frontend/client_constants.h"
612 #include "mir_toolkit/mir_native_buffer.h"
613
614+#include "exchange_semantics.h"
615+#include "new_buffer_semantics.h"
616+
617 #include <boost/throw_exception.hpp>
618 #include <boost/exception/diagnostic_information.hpp>
619
620@@ -51,369 +54,6 @@
621
622 namespace gp = google::protobuf;
623
624-namespace mir
625-{
626-namespace client
627-{
628-//An internal interface useful in transitioning buffer exchange semantics based on
629-//the BufferStream response provided by the server
630-struct ServerBufferSemantics
631-{
632- virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0;
633- virtual void set_buffer_cache_size(unsigned int) = 0;
634- virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0;
635- virtual uint32_t current_buffer_id() = 0;
636- virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
637- virtual void lost_connection() = 0;
638- virtual void set_size(geom::Size) = 0;
639- virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0;
640- virtual void set_interval(int interval) = 0;
641- virtual geom::Size size() const = 0;
642- virtual ~ServerBufferSemantics() = default;
643- ServerBufferSemantics() = default;
644- ServerBufferSemantics(ServerBufferSemantics const&) = delete;
645- ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
646-};
647-}
648-}
649-
650-namespace
651-{
652-
653-struct ExchangeSemantics : mcl::ServerBufferSemantics
654-{
655- ExchangeSemantics(
656- mir::protobuf::DisplayServer& server,
657- std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers,
658- mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
659- wrapped{factory, max_buffers},
660- display_server(server),
661- size_(first_size)
662- {
663- wrapped.deposit_package(
664- mcl::protobuf_to_native_buffer(first_buffer),
665- first_buffer.buffer_id(), first_size, first_pf);
666- }
667-
668- void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override
669- {
670- std::unique_lock<std::mutex> lock(mutex);
671- if (size.is_set())
672- size_ = size.value();
673-
674- if (on_incoming_buffer)
675- {
676- wrapped.deposit_package(
677- mcl::protobuf_to_native_buffer(buffer),
678- buffer.buffer_id(), size_, pf);
679- if (on_incoming_buffer)
680- {
681- on_incoming_buffer();
682- next_buffer_wait_handle.result_received();
683- on_incoming_buffer = std::function<void()>{};
684- }
685- }
686- else
687- {
688- incoming_buffers.push(buffer);
689- }
690- }
691-
692- void set_buffer_cache_size(unsigned int sz) override
693- {
694- std::unique_lock<std::mutex> lock(mutex);
695- wrapped.set_max_buffers(sz);
696- }
697- std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
698- {
699- std::unique_lock<std::mutex> lock(mutex);
700- return wrapped.current_buffer();
701- }
702- uint32_t current_buffer_id() override
703- {
704- std::unique_lock<std::mutex> lock(mutex);
705- if (incoming_buffers.size())
706- return incoming_buffers.front().buffer_id();
707- return wrapped.current_buffer_id();
708- }
709-
710- MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override
711- {
712- std::unique_lock<std::mutex> lock(mutex);
713- if (server_connection_lost)
714- BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
715- //always submit what we have, whether we have a buffer, or will have to wait for an async reply
716- auto request = mcl::make_protobuf_object<mp::BufferRequest>();
717- request->mutable_id()->set_value(stream_id);
718- request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
719- lock.unlock();
720-
721- display_server.submit_buffer(request.get(), protobuf_void.get(),
722- google::protobuf::NewCallback(google::protobuf::DoNothing));
723-
724- lock.lock();
725- if (server_connection_lost)
726- BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
727- if (incoming_buffers.empty())
728- {
729- next_buffer_wait_handle.expect_result();
730- on_incoming_buffer = done;
731- }
732- else
733- {
734- wrapped.deposit_package(
735- mcl::protobuf_to_native_buffer(incoming_buffers.front()),
736- incoming_buffers.front().buffer_id(), size_, pf);
737- incoming_buffers.pop();
738- done();
739- }
740- return &next_buffer_wait_handle;
741- }
742-
743- void lost_connection() override
744- {
745- std::unique_lock<std::mutex> lock(mutex);
746- server_connection_lost = true;
747- if (on_incoming_buffer)
748- {
749- on_incoming_buffer();
750- on_incoming_buffer = std::function<void()>{};
751- }
752- if (next_buffer_wait_handle.is_pending())
753- next_buffer_wait_handle.result_received();
754-
755- while (!incoming_buffers.empty())
756- {
757- auto b = incoming_buffers.front();
758- for (auto i = 0; i < b.fd_size(); i++)
759- close(b.fd(i));
760- incoming_buffers.pop();
761- }
762- }
763-
764- void set_size(geom::Size) override
765- {
766- }
767-
768- geom::Size size() const override
769- {
770- std::unique_lock<std::mutex> lk(mutex);
771- return size_;
772- }
773-
774- void on_scale_set(float scale)
775- {
776- std::unique_lock<decltype(mutex)> lock(mutex);
777- scale_ = scale;
778- scale_wait_handle.result_received();
779- }
780-
781- MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override
782- {
783- mp::StreamConfiguration configuration;
784- configuration.mutable_id()->set_value(stream_id.as_value());
785- configuration.set_scale(scale);
786- scale_wait_handle.expect_result();
787-
788- display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
789- google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
790- return &scale_wait_handle;
791- }
792-
793- void set_interval(int) override
794- {
795- }
796-
797- std::mutex mutable mutex;
798- mcl::ClientBufferDepository wrapped;
799- mir::protobuf::DisplayServer& display_server;
800- std::function<void()> on_incoming_buffer;
801- std::queue<mir::protobuf::Buffer> incoming_buffers;
802- std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()};
803- MirWaitHandle next_buffer_wait_handle;
804- bool server_connection_lost {false};
805- MirWaitHandle scale_wait_handle;
806- float scale_;
807- geom::Size size_;
808-};
809-
810-class Requests : public mcl::ServerBufferRequests
811-{
812-public:
813- Requests(mclr::DisplayServer& server, int stream_id) :
814- server(server),
815- stream_id(stream_id)
816- {
817- }
818-
819- void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override
820- {
821- mp::BufferAllocation request;
822- request.mutable_id()->set_value(stream_id);
823- auto buf_params = request.add_buffer_requests();
824- buf_params->set_width(size.width.as_int());
825- buf_params->set_height(size.height.as_int());
826- buf_params->set_pixel_format(format);
827- buf_params->set_buffer_usage(usage);
828-
829- //note, NewCallback will trigger on exception, deleting this object there
830- auto protobuf_void = new mp::Void;
831- server.allocate_buffers(&request, protobuf_void,
832- google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
833- }
834-
835- void free_buffer(int buffer_id) override
836- {
837- mp::BufferRelease request;
838- request.mutable_id()->set_value(stream_id);
839- request.add_buffers()->set_buffer_id(buffer_id);
840-
841- //note, NewCallback will trigger on exception, deleting this object there
842- auto protobuf_void = new mp::Void;
843- server.release_buffers(&request, protobuf_void,
844- google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
845- }
846-
847- void submit_buffer(mcl::Buffer& buffer) override
848- {
849- mp::BufferRequest request;
850- request.mutable_id()->set_value(stream_id);
851- request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
852-
853- //note, NewCallback will trigger on exception, deleting this object there
854- auto protobuf_void = new mp::Void;
855- server.submit_buffer(&request, protobuf_void,
856- google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
857- }
858-
859- static void ignore_response(mp::Void* void_response)
860- {
861- delete void_response;
862- }
863-
864-private:
865- mclr::DisplayServer& server;
866- mp::Void protobuf_void;
867- int stream_id;
868-};
869-
870-struct NewBufferSemantics : mcl::ServerBufferSemantics
871-{
872- NewBufferSemantics(
873- std::shared_ptr<mcl::ClientBufferFactory> const& factory,
874- std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
875- std::shared_ptr<mcl::ServerBufferRequests> const& requests,
876- std::weak_ptr<mcl::SurfaceMap> const& surface_map,
877- geom::Size size, MirPixelFormat format, int usage,
878- unsigned int initial_nbuffers) :
879- vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
880- current(nullptr),
881- future(vault.withdraw()),
882- size_(size)
883- {
884- }
885-
886- void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override
887- {
888- }
889-
890- void advance_current_buffer(std::unique_lock<std::mutex>& lk)
891- {
892- lk.unlock();
893- auto c = future.get();
894- lk.lock();
895- current = c;
896- }
897-
898- std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
899- {
900- std::unique_lock<std::mutex> lk(mutex);
901- if (!current)
902- advance_current_buffer(lk);
903- return current->client_buffer();
904- }
905-
906- uint32_t current_buffer_id() override
907- {
908- std::unique_lock<std::mutex> lk(mutex);
909- if (!current)
910- advance_current_buffer(lk);
911- return current->rpc_id();
912- }
913-
914- MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override
915- {
916- std::unique_lock<std::mutex> lk(mutex);
917- if (!current)
918- advance_current_buffer(lk);
919- auto c = current;
920- current = nullptr;
921- lk.unlock();
922-
923- vault.deposit(c);
924- auto wh = vault.wire_transfer_outbound(c, done);
925- auto f = vault.withdraw();
926- lk.lock();
927- future = std::move(f);
928- return wh;
929- }
930-
931- void set_size(geom::Size size) override
932- {
933- {
934- std::unique_lock<std::mutex> lk(mutex);
935- size_ = size;
936- }
937- vault.set_size(size);
938- }
939-
940- geom::Size size() const override
941- {
942- std::unique_lock<std::mutex> lk(mutex);
943- return size_;
944- }
945-
946- void lost_connection() override
947- {
948- vault.disconnected();
949- }
950-
951- void set_buffer_cache_size(unsigned int) override
952- {
953- }
954-
955- MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override
956- {
957- scale_wait_handle.expect_result();
958- scale_wait_handle.result_received();
959- vault.set_scale(scale);
960- return &scale_wait_handle;
961- }
962-
963- void set_interval(int interval) override
964- {
965- std::unique_lock<decltype(mutex)> lk(mutex);
966- interval = std::max(0, std::min(1, interval));
967- if (current_swap_interval == interval)
968- return;
969- if (interval == 0)
970- vault.increase_buffer_count();
971- else
972- vault.decrease_buffer_count();
973- current_swap_interval = interval;
974- }
975-
976- mcl::BufferVault vault;
977- std::mutex mutable mutex;
978- std::shared_ptr<mcl::Buffer> current{nullptr};
979- mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future;
980- MirWaitHandle scale_wait_handle;
981- int current_swap_interval = 1;
982- geom::Size size_;
983-};
984-
985-}
986-
987 mcl::BufferStream::BufferStream(
988 MirConnection* connection,
989 std::shared_ptr<MirWaitHandle> creation_wait_handle,
990
991=== modified file 'src/client/buffer_stream.h'
992--- src/client/buffer_stream.h 2016-06-02 05:33:50 +0000
993+++ src/client/buffer_stream.h 2016-06-03 01:46:54 +0000
994@@ -24,6 +24,7 @@
995 #include "mir/client_buffer.h"
996 #include "client_buffer_stream.h"
997 #include "client_buffer_depository.h"
998+#include "server_buffer_semantics.h"
999 #include "mir/geometry/size.h"
1000
1001 #include "mir_toolkit/client_types.h"
1002@@ -66,8 +67,6 @@
1003 class ClientPlatform;
1004 class PerfReport;
1005 struct MemoryRegion;
1006-class SurfaceMap;
1007-class ServerBufferSemantics;
1008 class BufferStream : public EGLNativeSurface, public ClientBufferStream
1009 {
1010 public:
1011
1012=== modified file 'src/client/error_chain.cpp'
1013--- src/client/error_chain.cpp 2016-06-02 05:33:50 +0000
1014+++ src/client/error_chain.cpp 2016-06-03 01:46:54 +0000
1015@@ -51,3 +51,8 @@
1016 {
1017 BOOST_THROW_EXCEPTION(std::logic_error("Cannot submit: invalid MirPresentationChain"));
1018 }
1019+
1020+EGLNativeWindowType mcl::ErrorChain::egl_native_window(geom::Size, MirPixelFormat)
1021+{
1022+ BOOST_THROW_EXCEPTION(std::logic_error("Cannot get native window: invalid MirPresentationChain"));
1023+}
1024
1025=== modified file 'src/client/error_chain.h'
1026--- src/client/error_chain.h 2016-06-02 05:33:50 +0000
1027+++ src/client/error_chain.h 2016-06-03 01:46:54 +0000
1028@@ -38,6 +38,7 @@
1029 MirConnection* connection() const override;
1030 int rpc_id() const override;
1031 char const* error_msg() const override;
1032+ EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override;
1033 private:
1034 MirConnection* const connection_;
1035 int const stream_id;
1036
1037=== added file 'src/client/exchange_semantics.cpp'
1038--- src/client/exchange_semantics.cpp 1970-01-01 00:00:00 +0000
1039+++ src/client/exchange_semantics.cpp 2016-06-03 01:46:54 +0000
1040@@ -0,0 +1,173 @@
1041+/*
1042+ * Copyright © 2016 Canonical Ltd.
1043+ *
1044+ * This program is free software: you can redistribute it and/or modify
1045+ * it under the terms of the GNU Lesser General Public License version 3 as
1046+ * published by the Free Software Foundation.
1047+ *
1048+ * This program is distributed in the hope that it will be useful,
1049+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1050+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1051+ * GNU Lesser General Public License for more details.
1052+ *
1053+ * You should have received a copy of the GNU Lesser General Public License
1054+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1055+ *
1056+ * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
1057+ */
1058+
1059+#include "exchange_semantics.h"
1060+#include "buffer.h"
1061+#include "protobuf_to_native_buffer.h"
1062+#include "make_protobuf_object.h"
1063+
1064+#include <boost/throw_exception.hpp>
1065+
1066+namespace mcl = mir::client;
1067+namespace mf = mir::frontend;
1068+namespace mp = mir::protobuf;
1069+namespace geom = mir::geometry;
1070+
1071+mcl::ExchangeSemantics::ExchangeSemantics(
1072+ mp::DisplayServer& server,
1073+ std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers,
1074+ mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
1075+ wrapped{factory, max_buffers},
1076+ display_server(server),
1077+ size_(first_size)
1078+{
1079+ wrapped.deposit_package(
1080+ mcl::protobuf_to_native_buffer(first_buffer),
1081+ first_buffer.buffer_id(), first_size, first_pf);
1082+}
1083+
1084+void mcl::ExchangeSemantics::deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf)
1085+{
1086+ std::unique_lock<std::mutex> lock(mutex);
1087+ if (size.is_set())
1088+ size_ = size.value();
1089+
1090+ if (on_incoming_buffer)
1091+ {
1092+ wrapped.deposit_package(
1093+ mcl::protobuf_to_native_buffer(buffer),
1094+ buffer.buffer_id(), size_, pf);
1095+ if (on_incoming_buffer)
1096+ {
1097+ on_incoming_buffer();
1098+ next_buffer_wait_handle.result_received();
1099+ on_incoming_buffer = std::function<void()>{};
1100+ }
1101+ }
1102+ else
1103+ {
1104+ incoming_buffers.push(buffer);
1105+ }
1106+}
1107+
1108+void mcl::ExchangeSemantics::set_buffer_cache_size(unsigned int sz)
1109+{
1110+ std::unique_lock<std::mutex> lock(mutex);
1111+ wrapped.set_max_buffers(sz);
1112+}
1113+
1114+std::shared_ptr<mir::client::ClientBuffer> mcl::ExchangeSemantics::current_buffer()
1115+{
1116+ std::unique_lock<std::mutex> lock(mutex);
1117+ return wrapped.current_buffer();
1118+}
1119+
1120+uint32_t mcl::ExchangeSemantics::current_buffer_id()
1121+{
1122+ std::unique_lock<std::mutex> lock(mutex);
1123+ if (incoming_buffers.size())
1124+ return incoming_buffers.front().buffer_id();
1125+ return wrapped.current_buffer_id();
1126+}
1127+
1128+MirWaitHandle* mcl::ExchangeSemantics::submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id)
1129+{
1130+ std::unique_lock<std::mutex> lock(mutex);
1131+ if (server_connection_lost)
1132+ BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
1133+ //always submit what we have, whether we have a buffer, or will have to wait for an async reply
1134+ auto request = mcl::make_protobuf_object<mp::BufferRequest>();
1135+ request->mutable_id()->set_value(stream_id);
1136+ request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
1137+ lock.unlock();
1138+
1139+ display_server.submit_buffer(request.get(), protobuf_void.get(),
1140+ google::protobuf::NewCallback(google::protobuf::DoNothing));
1141+
1142+ lock.lock();
1143+ if (server_connection_lost)
1144+ BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
1145+ if (incoming_buffers.empty())
1146+ {
1147+ next_buffer_wait_handle.expect_result();
1148+ on_incoming_buffer = done;
1149+ }
1150+ else
1151+ {
1152+ wrapped.deposit_package(
1153+ mcl::protobuf_to_native_buffer(incoming_buffers.front()),
1154+ incoming_buffers.front().buffer_id(), size_, pf);
1155+ incoming_buffers.pop();
1156+ done();
1157+ }
1158+ return &next_buffer_wait_handle;
1159+}
1160+
1161+void mcl::ExchangeSemantics::lost_connection()
1162+{
1163+ std::unique_lock<std::mutex> lock(mutex);
1164+ server_connection_lost = true;
1165+ if (on_incoming_buffer)
1166+ {
1167+ on_incoming_buffer();
1168+ on_incoming_buffer = std::function<void()>{};
1169+ }
1170+ if (next_buffer_wait_handle.is_pending())
1171+ next_buffer_wait_handle.result_received();
1172+
1173+ while (!incoming_buffers.empty())
1174+ {
1175+ auto b = incoming_buffers.front();
1176+ for (auto i = 0; i < b.fd_size(); i++)
1177+ close(b.fd(i));
1178+ incoming_buffers.pop();
1179+ }
1180+}
1181+
1182+void mcl::ExchangeSemantics::set_size(geom::Size)
1183+{
1184+}
1185+
1186+geom::Size mcl::ExchangeSemantics::size() const
1187+{
1188+ std::unique_lock<std::mutex> lk(mutex);
1189+ return size_;
1190+}
1191+
1192+void mcl::ExchangeSemantics::on_scale_set(float scale)
1193+{
1194+ std::unique_lock<decltype(mutex)> lock(mutex);
1195+ scale_ = scale;
1196+ scale_wait_handle.result_received();
1197+}
1198+
1199+MirWaitHandle* mcl::ExchangeSemantics::set_scale(float scale, mf::BufferStreamId stream_id)
1200+{
1201+ mp::StreamConfiguration configuration;
1202+ configuration.mutable_id()->set_value(stream_id.as_value());
1203+ configuration.set_scale(scale);
1204+ scale_wait_handle.expect_result();
1205+
1206+ display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
1207+ google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
1208+ return &scale_wait_handle;
1209+}
1210+
1211+void mcl::ExchangeSemantics::set_interval(int)
1212+{
1213+}
1214
1215=== added file 'src/client/exchange_semantics.h'
1216--- src/client/exchange_semantics.h 1970-01-01 00:00:00 +0000
1217+++ src/client/exchange_semantics.h 2016-06-03 01:46:54 +0000
1218@@ -0,0 +1,70 @@
1219+/*
1220+ * Copyright © 2016 Canonical Ltd.
1221+ *
1222+ * This program is free software: you can redistribute it and/or modify
1223+ * it under the terms of the GNU Lesser General Public License version 3 as
1224+ * published by the Free Software Foundation.
1225+ *
1226+ * This program is distributed in the hope that it will be useful,
1227+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1228+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1229+ * GNU Lesser General Public License for more details.
1230+ *
1231+ * You should have received a copy of the GNU Lesser General Public License
1232+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1233+ *
1234+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1235+ */
1236+
1237+#ifndef MIR_CLIENT_EXCHANGE_SEMANTICS_H
1238+#define MIR_CLIENT_EXCHANGE_SEMANTICS_H
1239+
1240+#include "server_buffer_semantics.h"
1241+#include <mir/protobuf/display_server.h>
1242+#include "mir/client_buffer_factory.h"
1243+#include "client_buffer_depository.h"
1244+#include "mir_wait_handle.h"
1245+
1246+#include <mutex>
1247+#include <queue>
1248+
1249+namespace mir
1250+{
1251+namespace client
1252+{
1253+
1254+struct ExchangeSemantics : ServerBufferSemantics
1255+{
1256+ ExchangeSemantics(
1257+ protobuf::DisplayServer& server,
1258+ std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers,
1259+ protobuf::Buffer const& first_buffer, geometry::Size first_size, MirPixelFormat first_pf);
1260+ void deposit(protobuf::Buffer const& buffer, optional_value<geometry::Size> size, MirPixelFormat pf) override;
1261+ void set_buffer_cache_size(unsigned int sz) override;
1262+ std::shared_ptr<ClientBuffer> current_buffer() override;
1263+ uint32_t current_buffer_id() override;
1264+ MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override;
1265+ void lost_connection() override;
1266+ void set_size(geometry::Size) override;
1267+ geometry::Size size() const override;
1268+ void set_interval(int) override;
1269+ void on_scale_set(float scale);
1270+ MirWaitHandle* set_scale(float scale, frontend::BufferStreamId stream_id) override;
1271+
1272+ std::mutex mutable mutex;
1273+ ClientBufferDepository wrapped;
1274+ protobuf::DisplayServer& display_server;
1275+ std::function<void()> on_incoming_buffer;
1276+ std::queue<protobuf::Buffer> incoming_buffers;
1277+ std::unique_ptr<protobuf::Void> protobuf_void{std::make_unique<protobuf::Void>()};
1278+ MirWaitHandle next_buffer_wait_handle;
1279+ bool server_connection_lost {false};
1280+ MirWaitHandle scale_wait_handle;
1281+ float scale_;
1282+ geometry::Size size_;
1283+};
1284+
1285+}
1286+}
1287+
1288+#endif /* MIR_CLIENT_EXCHANGE_SEMANTICS_H */
1289
1290=== modified file 'src/client/mir_connection.cpp'
1291--- src/client/mir_connection.cpp 2016-06-02 05:33:50 +0000
1292+++ src/client/mir_connection.cpp 2016-06-03 01:46:54 +0000
1293@@ -1180,7 +1180,7 @@
1294 if (!client_buffer_factory)
1295 client_buffer_factory = platform->create_buffer_factory();
1296 auto chain = std::make_shared<mcl::PresentationChain>(
1297- this, protobuf_bs->id().value(), server, client_buffer_factory, buffer_factory);
1298+ this, protobuf_bs->id().value(), server, platform, client_buffer_factory, buffer_factory, surface_map, nbuffers);
1299
1300 surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), chain);
1301
1302
1303=== modified file 'src/client/mir_presentation_chain.h'
1304--- src/client/mir_presentation_chain.h 2016-03-10 14:30:48 +0000
1305+++ src/client/mir_presentation_chain.h 2016-06-03 01:46:54 +0000
1306@@ -22,6 +22,18 @@
1307 #include "mir/geometry/size.h"
1308 #include "mir_toolkit/mir_presentation_chain.h"
1309
1310+#include <EGL/eglplatform.h>
1311+
1312+//See comment in client_buffer_stream.h
1313+#include <type_traits>
1314+static_assert(
1315+ sizeof(EGLNativeWindowType) == sizeof(void*) &&
1316+ std::is_pod<EGLNativeWindowType>::value,
1317+ "MirPresentationChain requires that EGLNativeWindowType be no-op convertible to void*");
1318+
1319+#undef EGLNativeWindowType
1320+#define EGLNativeWindowType void*
1321+
1322 class MirPresentationChain
1323 {
1324 public:
1325@@ -30,6 +42,7 @@
1326 virtual MirConnection* connection() const = 0;
1327 virtual int rpc_id() const = 0;
1328 virtual char const* error_msg() const = 0;
1329+ virtual EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) = 0;
1330
1331 protected:
1332 MirPresentationChain(MirPresentationChain const&) = delete;
1333
1334=== modified file 'src/client/mir_presentation_chain_api.cpp'
1335--- src/client/mir_presentation_chain_api.cpp 2016-05-03 06:55:25 +0000
1336+++ src/client/mir_presentation_chain_api.cpp 2016-06-03 01:46:54 +0000
1337@@ -124,3 +124,16 @@
1338 {
1339 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
1340 }
1341+
1342+MirEGLNativeWindowType mir_create_egl_native_window(
1343+ MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format)
1344+try
1345+{
1346+ mir::require(presentation_chain && mir_presentation_chain_is_valid(presentation_chain));
1347+ return presentation_chain->egl_native_window(mir::geometry::Size{width, height}, pixel_format);
1348+}
1349+catch (std::exception const& ex)
1350+{
1351+ MIR_LOG_UNCAUGHT_EXCEPTION(ex);
1352+ return nullptr;
1353+}
1354
1355=== added file 'src/client/new_buffer_semantics.cpp'
1356--- src/client/new_buffer_semantics.cpp 1970-01-01 00:00:00 +0000
1357+++ src/client/new_buffer_semantics.cpp 2016-06-03 01:46:54 +0000
1358@@ -0,0 +1,181 @@
1359+/*
1360+ * Copyright © 2016 Canonical Ltd.
1361+ *
1362+ * This program is free software: you can redistribute it and/or modify
1363+ * it under the terms of the GNU Lesser General Public License version 3 as
1364+ * published by the Free Software Foundation.
1365+ *
1366+ * This program is distributed in the hope that it will be useful,
1367+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1368+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1369+ * GNU Lesser General Public License for more details.
1370+ *
1371+ * You should have received a copy of the GNU Lesser General Public License
1372+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1373+ *
1374+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1375+ */
1376+
1377+#include "new_buffer_semantics.h"
1378+#include "buffer.h"
1379+
1380+namespace mcl = mir::client;
1381+namespace mclr = mir::client::rpc;
1382+namespace mf = mir::frontend;
1383+namespace mp = mir::protobuf;
1384+namespace geom = mir::geometry;
1385+
1386+mcl::Requests::Requests(mclr::DisplayServer& server, int stream_id) :
1387+ server(server),
1388+ stream_id(stream_id)
1389+{
1390+}
1391+
1392+void mcl::Requests::allocate_buffer(geom::Size size, MirPixelFormat format, int usage)
1393+{
1394+ mp::BufferAllocation request;
1395+ request.mutable_id()->set_value(stream_id);
1396+ auto buf_params = request.add_buffer_requests();
1397+ buf_params->set_width(size.width.as_int());
1398+ buf_params->set_height(size.height.as_int());
1399+ buf_params->set_pixel_format(format);
1400+ buf_params->set_buffer_usage(usage);
1401+
1402+ //note, NewCallback will trigger on exception, deleting this object there
1403+ auto protobuf_void = new mp::Void;
1404+ server.allocate_buffers(&request, protobuf_void,
1405+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
1406+}
1407+
1408+void mcl::Requests::free_buffer(int buffer_id)
1409+{
1410+ mp::BufferRelease request;
1411+ request.mutable_id()->set_value(stream_id);
1412+ request.add_buffers()->set_buffer_id(buffer_id);
1413+
1414+ //note, NewCallback will trigger on exception, deleting this object there
1415+ auto protobuf_void = new mp::Void;
1416+ server.release_buffers(&request, protobuf_void,
1417+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
1418+}
1419+
1420+void mcl::Requests::submit_buffer(mcl::Buffer& buffer)
1421+{
1422+ mp::BufferRequest request;
1423+ request.mutable_id()->set_value(stream_id);
1424+ request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
1425+
1426+ //note, NewCallback will trigger on exception, deleting this object there
1427+ auto protobuf_void = new mp::Void;
1428+ server.submit_buffer(&request, protobuf_void,
1429+ google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
1430+}
1431+
1432+void mcl::Requests::ignore_response(mp::Void* void_response)
1433+{
1434+ delete void_response;
1435+}
1436+
1437+mcl::NewBufferSemantics::NewBufferSemantics(
1438+ std::shared_ptr<mcl::ClientBufferFactory> const& factory,
1439+ std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
1440+ std::shared_ptr<mcl::ServerBufferRequests> const& requests,
1441+ std::weak_ptr<mcl::SurfaceMap> const& surface_map,
1442+ geom::Size size, MirPixelFormat format, int usage,
1443+ unsigned int initial_nbuffers) :
1444+ vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
1445+ current(nullptr),
1446+ future(vault.withdraw()),
1447+ size_(size)
1448+{
1449+}
1450+
1451+void mcl::NewBufferSemantics::deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat)
1452+{
1453+}
1454+
1455+void mcl::NewBufferSemantics::advance_current_buffer(std::unique_lock<std::mutex>& lk)
1456+{
1457+ lk.unlock();
1458+ auto c = future.get();
1459+ lk.lock();
1460+ current = c;
1461+}
1462+
1463+std::shared_ptr<mir::client::ClientBuffer> mcl::NewBufferSemantics::current_buffer()
1464+{
1465+ std::unique_lock<std::mutex> lk(mutex);
1466+ if (!current)
1467+ advance_current_buffer(lk);
1468+ return current->client_buffer();
1469+}
1470+
1471+uint32_t mcl::NewBufferSemantics::current_buffer_id()
1472+{
1473+ std::unique_lock<std::mutex> lk(mutex);
1474+ if (!current)
1475+ advance_current_buffer(lk);
1476+ return current->rpc_id();
1477+}
1478+
1479+MirWaitHandle* mcl::NewBufferSemantics::submit(std::function<void()> const& done, MirPixelFormat, int)
1480+{
1481+ std::unique_lock<std::mutex> lk(mutex);
1482+ if (!current)
1483+ advance_current_buffer(lk);
1484+ auto c = current;
1485+ current = nullptr;
1486+ lk.unlock();
1487+
1488+ vault.deposit(c);
1489+ auto wh = vault.wire_transfer_outbound(c, done);
1490+ auto f = vault.withdraw();
1491+ lk.lock();
1492+ future = std::move(f);
1493+ return wh;
1494+}
1495+
1496+void mcl::NewBufferSemantics::set_size(geom::Size size)
1497+{
1498+ {
1499+ std::unique_lock<std::mutex> lk(mutex);
1500+ size_ = size;
1501+ }
1502+ vault.set_size(size);
1503+}
1504+
1505+geom::Size mcl::NewBufferSemantics::size() const
1506+{
1507+ std::unique_lock<std::mutex> lk(mutex);
1508+ return size_;
1509+}
1510+
1511+void mcl::NewBufferSemantics::lost_connection()
1512+{
1513+ vault.disconnected();
1514+}
1515+
1516+void mcl::NewBufferSemantics::set_buffer_cache_size(unsigned int)
1517+{
1518+}
1519+
1520+MirWaitHandle* mcl::NewBufferSemantics::set_scale(float scale, mf::BufferStreamId)
1521+{
1522+ scale_wait_handle.expect_result();
1523+ scale_wait_handle.result_received();
1524+ vault.set_scale(scale);
1525+ return &scale_wait_handle;
1526+}
1527+
1528+void mcl::NewBufferSemantics::set_interval(int interval)
1529+{
1530+ std::unique_lock<decltype(mutex)> lk(mutex);
1531+ interval = std::max(0, std::min(1, interval));
1532+ if (current_swap_interval == interval)
1533+ return;
1534+ if (interval == 0)
1535+ vault.increase_buffer_count();
1536+ else
1537+ vault.decrease_buffer_count();
1538+ current_swap_interval = interval;
1539+}
1540
1541=== added file 'src/client/new_buffer_semantics.h'
1542--- src/client/new_buffer_semantics.h 1970-01-01 00:00:00 +0000
1543+++ src/client/new_buffer_semantics.h 2016-06-03 01:46:54 +0000
1544@@ -0,0 +1,79 @@
1545+/*
1546+ * Copyright © 2016 Canonical Ltd.
1547+ *
1548+ * This program is free software: you can redistribute it and/or modify
1549+ * it under the terms of the GNU Lesser General Public License version 3 as
1550+ * published by the Free Software Foundation.
1551+ *
1552+ * This program is distributed in the hope that it will be useful,
1553+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1554+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1555+ * GNU Lesser General Public License for more details.
1556+ *
1557+ * You should have received a copy of the GNU Lesser General Public License
1558+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1559+ *
1560+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1561+ */
1562+
1563+#ifndef MIR_CLIENT_NEW_BUFFER_SEMANTICS_H
1564+#define MIR_CLIENT_NEW_BUFFER_SEMANTICS_H
1565+
1566+#include "server_buffer_semantics.h"
1567+#include "buffer_vault.h"
1568+#include "rpc/mir_display_server.h"
1569+
1570+namespace mir
1571+{
1572+namespace client
1573+{
1574+
1575+class Requests : public ServerBufferRequests
1576+{
1577+public:
1578+ Requests(client::rpc::DisplayServer& server, int stream_id);
1579+ void allocate_buffer(geometry::Size size, MirPixelFormat format, int usage) override;
1580+ void free_buffer(int buffer_id) override;
1581+ void submit_buffer(Buffer& buffer) override;
1582+ static void ignore_response(protobuf::Void* void_response);
1583+
1584+private:
1585+ client::rpc::DisplayServer& server;
1586+ protobuf::Void protobuf_void;
1587+ int stream_id;
1588+};
1589+
1590+struct NewBufferSemantics : ServerBufferSemantics
1591+{
1592+ NewBufferSemantics(
1593+ std::shared_ptr<ClientBufferFactory> const& factory,
1594+ std::shared_ptr<AsyncBufferFactory> const& mirbuffer_factory,
1595+ std::shared_ptr<ServerBufferRequests> const& requests,
1596+ std::weak_ptr<SurfaceMap> const& surface_map,
1597+ geometry::Size size, MirPixelFormat format, int usage,
1598+ unsigned int initial_nbuffers);
1599+ void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) override;
1600+ void advance_current_buffer(std::unique_lock<std::mutex>& lk);
1601+ std::shared_ptr<ClientBuffer> current_buffer() override;
1602+ uint32_t current_buffer_id() override;
1603+ MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override;
1604+ void set_size(geometry::Size size) override;
1605+ geometry::Size size() const override;
1606+ void lost_connection() override;
1607+ void set_buffer_cache_size(unsigned int) override;
1608+ MirWaitHandle* set_scale(float scale, frontend::BufferStreamId) override;
1609+ void set_interval(int interval) override;
1610+
1611+ BufferVault vault;
1612+ std::mutex mutable mutex;
1613+ std::shared_ptr<Buffer> current{nullptr};
1614+ NoTLSFuture<std::shared_ptr<Buffer>> future;
1615+ MirWaitHandle scale_wait_handle;
1616+ int current_swap_interval = 1;
1617+ geometry::Size size_;
1618+};
1619+
1620+}
1621+}
1622+
1623+#endif /* MIR_CLIENT_NEW_BUFFER_SEMANTICS_H */
1624
1625=== modified file 'src/client/presentation_chain.cpp'
1626--- src/client/presentation_chain.cpp 2016-06-02 05:33:50 +0000
1627+++ src/client/presentation_chain.cpp 2016-06-03 01:46:54 +0000
1628@@ -22,6 +22,8 @@
1629 #include "presentation_chain.h"
1630 #include "protobuf_to_native_buffer.h"
1631 #include "buffer_factory.h"
1632+#include "new_buffer_semantics.h"
1633+#include "mir/client_platform.h"
1634 #include <boost/throw_exception.hpp>
1635 #include <algorithm>
1636
1637@@ -34,13 +36,22 @@
1638 MirConnection* connection,
1639 int stream_id,
1640 mir::client::rpc::DisplayServer& server,
1641+ std::shared_ptr<ClientPlatform> const& client_platform,
1642 std::shared_ptr<mcl::ClientBufferFactory> const& native_buffer_factory,
1643- std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory) :
1644- connection_(connection),
1645- stream_id(stream_id),
1646- server(server),
1647- native_buffer_factory(native_buffer_factory),
1648- mir_buffer_factory(mir_buffer_factory)
1649+ std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory,
1650+ std::weak_ptr<SurfaceMap> const& map,
1651+ size_t nbuffers) :
1652+ connection_(connection),
1653+ stream_id(stream_id),
1654+ server(server),
1655+ client_platform(client_platform),
1656+ native_buffer_factory(native_buffer_factory),
1657+ mir_buffer_factory(mir_buffer_factory),
1658+ egl_native_window_(nullptr),
1659+ map(map),
1660+ nbuffers(nbuffers),
1661+ buffer_depository(nullptr),
1662+ egl_native_window_pixel_format(mir_pixel_format_invalid)
1663 {
1664 }
1665
1666@@ -58,6 +69,9 @@
1667
1668 void mcl::PresentationChain::submit_buffer(MirBuffer* mirbuffer)
1669 {
1670+ if (egl_native_window_)
1671+ BOOST_THROW_EXCEPTION(std::runtime_error("Buffers cannot be submitted when chain is in EGL mode"));
1672+
1673 mp::BufferRequest request;
1674 {
1675 auto buffer = reinterpret_cast<mcl::Buffer*>(mirbuffer);
1676@@ -84,3 +98,82 @@
1677 {
1678 return "";
1679 }
1680+
1681+EGLNativeWindowType mcl::PresentationChain::egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format)
1682+{
1683+ std::unique_lock<decltype(mutex)> lock(mutex);
1684+ if (!egl_native_window_)
1685+ {
1686+ egl_native_window_pixel_format = pixel_format;
1687+ buffer_depository = std::make_unique<NewBufferSemantics>(
1688+ native_buffer_factory,
1689+ mir_buffer_factory,
1690+ std::make_shared<Requests>(server, stream_id),
1691+ map,
1692+ size,
1693+ pixel_format,
1694+ mir_buffer_usage_hardware,
1695+ nbuffers);
1696+
1697+ egl_native_window_ = client_platform->create_egl_native_window(this);
1698+ }
1699+
1700+ return static_cast<EGLNativeWindowType>(egl_native_window_.get());
1701+}
1702+
1703+//////////////////////////////
1704+// EGLNativeSurface interface
1705+//////////////////////////////
1706+
1707+namespace
1708+{
1709+ const char * const egl_mode_error = "Chain cannot be used in EGL mode";
1710+}
1711+
1712+MirSurfaceParameters mcl::PresentationChain::get_parameters() const
1713+{
1714+ std::unique_lock<decltype(mutex)> lock(mutex);
1715+
1716+ if (!buffer_depository)
1717+ BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
1718+
1719+ auto size = buffer_depository->size();
1720+
1721+ return MirSurfaceParameters{
1722+ "",
1723+ size.width.as_int(),
1724+ size.height.as_int(),
1725+ egl_native_window_pixel_format,
1726+ mir_buffer_usage_hardware,
1727+ mir_display_output_id_invalid};
1728+}
1729+
1730+std::shared_ptr<mcl::ClientBuffer> mcl::PresentationChain::get_current_buffer()
1731+{
1732+ {
1733+ std::unique_lock<decltype(mutex)> lock(mutex);
1734+ if (!buffer_depository)
1735+ BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
1736+ }
1737+ return buffer_depository->current_buffer();
1738+}
1739+
1740+void mcl::PresentationChain::request_and_wait_for_next_buffer()
1741+{
1742+ {
1743+ std::unique_lock<decltype(mutex)> lock(mutex);
1744+ if (!buffer_depository)
1745+ BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
1746+ }
1747+ buffer_depository->submit([](){}, egl_native_window_pixel_format, 0)->wait_for_all();
1748+}
1749+
1750+void mcl::PresentationChain::request_and_wait_for_configure(MirSurfaceAttrib /*a*/, int /*value*/)
1751+{
1752+ //TODO: implement this function
1753+}
1754+
1755+void mcl::PresentationChain::set_buffer_cache_size(unsigned int)
1756+{
1757+ //TODO: implement this function
1758+}
1759
1760=== modified file 'src/client/presentation_chain.h'
1761--- src/client/presentation_chain.h 2016-06-02 05:33:50 +0000
1762+++ src/client/presentation_chain.h 2016-06-03 01:46:54 +0000
1763@@ -22,8 +22,10 @@
1764 #include "mir_presentation_chain.h"
1765 #include "mir/geometry/size.h"
1766 #include "mir_toolkit/mir_presentation_chain.h"
1767+#include "mir/egl_native_surface.h"
1768 #include "mir_protobuf.pb.h"
1769 #include "buffer.h"
1770+#include "server_buffer_semantics.h"
1771 #include <mutex>
1772 #include <memory>
1773
1774@@ -34,34 +36,59 @@
1775 class ClientBufferFactory;
1776 class ClientBuffer;
1777 class AsyncBufferFactory;
1778+class ClientPlatform;
1779+class SurfaceMap;
1780+
1781 namespace rpc
1782 {
1783 class DisplayServer;
1784 }
1785
1786-class PresentationChain : public MirPresentationChain
1787+class PresentationChain : public MirPresentationChain, public EGLNativeSurface
1788 {
1789 public:
1790 PresentationChain(
1791 MirConnection* connection,
1792 int rpc_id,
1793 rpc::DisplayServer& server,
1794+ std::shared_ptr<ClientPlatform> const& client_platform,
1795 std::shared_ptr<ClientBufferFactory> const& native_buffer_factory,
1796- std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory);
1797+ std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory,
1798+ std::weak_ptr<SurfaceMap> const& map,
1799+ size_t nbuffers);
1800+
1801 void submit_buffer(MirBuffer* buffer) override;
1802 MirConnection* connection() const override;
1803 int rpc_id() const override;
1804 char const* error_msg() const override;
1805+ EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override;
1806+
1807+ // EGLNativeSurface interface
1808+ std::shared_ptr<ClientBuffer> get_current_buffer() override;
1809+ MirSurfaceParameters get_parameters() const override;
1810+ void request_and_wait_for_next_buffer() override;
1811+ void request_and_wait_for_configure(MirSurfaceAttrib a, int value) override;
1812+ void set_buffer_cache_size(unsigned int) override;
1813+
1814+protected:
1815+ PresentationChain(PresentationChain const&) = delete;
1816+ PresentationChain& operator=(PresentationChain const&) = delete;
1817+
1818 private:
1819-
1820 MirConnection* const connection_;
1821 int const stream_id;
1822 rpc::DisplayServer& server;
1823+ std::shared_ptr<ClientPlatform> const client_platform;
1824 std::shared_ptr<ClientBufferFactory> const native_buffer_factory;
1825 std::shared_ptr<AsyncBufferFactory> const mir_buffer_factory;
1826+ std::shared_ptr<void> egl_native_window_;
1827+ std::weak_ptr<SurfaceMap> const map;
1828+ size_t nbuffers;
1829
1830- std::mutex mutex;
1831+ mutable std::mutex mutex;
1832 std::vector<std::unique_ptr<Buffer>> buffers;
1833+ std::unique_ptr<ServerBufferSemantics> buffer_depository;
1834+ MirPixelFormat egl_native_window_pixel_format;
1835 };
1836 }
1837 }
1838
1839=== added file 'src/client/server_buffer_semantics.h'
1840--- src/client/server_buffer_semantics.h 1970-01-01 00:00:00 +0000
1841+++ src/client/server_buffer_semantics.h 2016-06-03 01:46:54 +0000
1842@@ -0,0 +1,59 @@
1843+/*
1844+ * Copyright © 2016 Canonical Ltd.
1845+ *
1846+ * This program is free software: you can redistribute it and/or modify
1847+ * it under the terms of the GNU Lesser General Public License version 3 as
1848+ * published by the Free Software Foundation.
1849+ *
1850+ * This program is distributed in the hope that it will be useful,
1851+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1852+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1853+ * GNU Lesser General Public License for more details.
1854+ *
1855+ * You should have received a copy of the GNU Lesser General Public License
1856+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1857+ *
1858+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1859+ */
1860+
1861+#ifndef MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H
1862+#define MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H
1863+
1864+#include "mir/optional_value.h"
1865+#include "mir/frontend/buffer_stream_id.h"
1866+#include "mir/geometry/size.h"
1867+#include "mir_toolkit/common.h"
1868+#include "mir/client_buffer.h"
1869+#include "mir_protobuf.pb.h"
1870+
1871+#include <memory>
1872+
1873+namespace mir
1874+{
1875+namespace client
1876+{
1877+
1878+//An internal interface useful in transitioning buffer exchange semantics based on
1879+//the BufferStream response provided by the server
1880+struct ServerBufferSemantics
1881+{
1882+ virtual void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) = 0;
1883+ virtual void set_buffer_cache_size(unsigned int) = 0;
1884+ virtual std::shared_ptr<ClientBuffer> current_buffer() = 0;
1885+ virtual uint32_t current_buffer_id() = 0;
1886+ virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
1887+ virtual void lost_connection() = 0;
1888+ virtual void set_size(geometry::Size) = 0;
1889+ virtual MirWaitHandle* set_scale(float, frontend::BufferStreamId) = 0;
1890+ virtual void set_interval(int interval) = 0;
1891+ virtual geometry::Size size() const = 0;
1892+ virtual ~ServerBufferSemantics() = default;
1893+ ServerBufferSemantics() = default;
1894+ ServerBufferSemantics(ServerBufferSemantics const&) = delete;
1895+ ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
1896+};
1897+
1898+}
1899+}
1900+
1901+#endif /* MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H */
1902
1903=== modified file 'src/client/symbols.map'
1904--- src/client/symbols.map 2016-06-02 05:33:50 +0000
1905+++ src/client/symbols.map 2016-06-03 01:46:54 +0000
1906@@ -370,6 +370,7 @@
1907 mir_connection_create_presentation_chain_sync;
1908 mir_presentation_chain_is_valid;
1909 mir_presentation_chain_get_error_message;
1910+ mir_create_egl_native_window;
1911 mir_connection_create_presentation_chain;
1912 mir_connection_allocate_buffer;
1913 mir_presentation_chain_submit_buffer;
1914
1915=== modified file 'src/include/client/mir_toolkit/mir_presentation_chain.h'
1916--- src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-02 05:33:50 +0000
1917+++ src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-03 01:46:54 +0000
1918@@ -29,6 +29,23 @@
1919 #endif
1920
1921 /**
1922+ * Extract an MirEGLNativeWindowType object from a given presentation chain.
1923+ * MirEGLNativeWindowType object that can be used in eglCreateWindowSurface()
1924+ * as native window. After this function is called, buffer management
1925+ * (allocation/deallocation/submission) of this presentation chain is done
1926+ * internally - clients should refrain from managing their buffers.
1927+ *
1928+ * \param [in] presentation_chain The presentation chain
1929+ * \param [in] width Native window width
1930+ * \param [in] height Native window height
1931+ * \param [in] pixel format Pixel format of native window
1932+ * \return MirEGLNativeWindowType object that can be used
1933+ * in eglCreateWindowSurface() as native window.
1934+ */
1935+MirEGLNativeWindowType mir_create_egl_native_window(
1936+ MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format);
1937+
1938+/**
1939 * Test for a valid presentation chain
1940 *
1941 * \param [in] presentation_chain The presentation chain
1942
1943=== added file 'tests/unit-tests/client/stub_client_platform.h'
1944--- tests/unit-tests/client/stub_client_platform.h 1970-01-01 00:00:00 +0000
1945+++ tests/unit-tests/client/stub_client_platform.h 2016-06-03 01:46:54 +0000
1946@@ -0,0 +1,79 @@
1947+/*
1948+ * Copyright © 2016 Canonical Ltd.
1949+ *
1950+ * This program is free software: you can redistribute it and/or modify it
1951+ * under the terms of the GNU General Public License version 3,
1952+ * as published by the Free Software Foundation.
1953+ *
1954+ * This program is distributed in the hope that it will be useful,
1955+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1956+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1957+ * GNU General Public License for more details.
1958+ *
1959+ * You should have received a copy of the GNU General Public License
1960+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1961+ *
1962+ * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
1963+ */
1964+
1965+#ifndef STUB_CLIENT_PLATFORM_H_
1966+#define STUB_CLIENT_PLATFORM_H_
1967+
1968+#include "mir/client_platform.h"
1969+
1970+namespace
1971+{
1972+
1973+struct StubClientPlatform : public mir::client::ClientPlatform
1974+{
1975+ StubClientPlatform(
1976+ std::shared_ptr<mir::client::ClientBufferFactory> const& bf)
1977+ : buffer_factory(bf)
1978+ {
1979+ }
1980+
1981+ MirPlatformType platform_type() const override
1982+ {
1983+ return MirPlatformType();
1984+ }
1985+
1986+ void populate(MirPlatformPackage& /* package */) const override
1987+ {
1988+ }
1989+
1990+ std::shared_ptr<void> create_egl_native_window(mir::client::EGLNativeSurface * /* surface */) override
1991+ {
1992+ return mir::test::fake_shared(egl_native_window);
1993+ }
1994+
1995+ std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override
1996+ {
1997+ return nullptr;
1998+ }
1999+
2000+ MirNativeBuffer* convert_native_buffer(mir::graphics::NativeBuffer*) const override
2001+ {
2002+ return nullptr;
2003+ }
2004+
2005+ std::shared_ptr<mir::client::ClientBufferFactory> create_buffer_factory() override
2006+ {
2007+ return buffer_factory;
2008+ }
2009+
2010+ MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */)
2011+ {
2012+ return nullptr;
2013+ }
2014+
2015+ MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override
2016+ {
2017+ return mir_pixel_format_invalid;
2018+ }
2019+
2020+ static EGLNativeWindowType egl_native_window;
2021+ std::shared_ptr<mir::client::ClientBufferFactory> const buffer_factory;
2022+};
2023+
2024+}
2025+#endif /* STUB_CLIENT_PLATFORM_H_ */
2026
2027=== modified file 'tests/unit-tests/client/test_client_buffer_stream.cpp'
2028--- tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000
2029+++ tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000
2030@@ -35,6 +35,8 @@
2031
2032 #include "mir_toolkit/mir_client_library.h"
2033
2034+#include "stub_client_platform.h"
2035+
2036 #include <future>
2037 #include <atomic>
2038
2039@@ -57,49 +59,6 @@
2040 arg1->set_error(message);
2041 }
2042
2043-struct StubClientPlatform : public mcl::ClientPlatform
2044-{
2045- StubClientPlatform(
2046- std::shared_ptr<mcl::ClientBufferFactory> const& bf)
2047- : buffer_factory(bf)
2048- {
2049- }
2050- MirPlatformType platform_type() const override
2051- {
2052- return MirPlatformType();
2053- }
2054- void populate(MirPlatformPackage& /* package */) const override
2055- {
2056- }
2057- std::shared_ptr<void> create_egl_native_window(mcl::EGLNativeSurface * /* surface */) override
2058- {
2059- return mt::fake_shared(egl_native_window);
2060- }
2061- std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override
2062- {
2063- return nullptr;
2064- }
2065- MirNativeBuffer* convert_native_buffer(mg::NativeBuffer*) const override
2066- {
2067- return nullptr;
2068- }
2069-
2070- std::shared_ptr<mcl::ClientBufferFactory> create_buffer_factory() override
2071- {
2072- return buffer_factory;
2073- }
2074- MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */)
2075- {
2076- return nullptr;
2077- }
2078- MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override
2079- {
2080- return mir_pixel_format_invalid;
2081- }
2082- static EGLNativeWindowType egl_native_window;
2083- std::shared_ptr<mcl::ClientBufferFactory> const buffer_factory;
2084-};
2085-
2086 struct MockPerfReport : public mcl::PerfReport
2087 {
2088 MOCK_METHOD1(name_surface, void(char const*));
2089
2090=== modified file 'tests/unit-tests/client/test_connection_resource_map.cpp'
2091--- tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-02 05:33:50 +0000
2092+++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-03 01:46:54 +0000
2093@@ -42,7 +42,7 @@
2094 std::make_shared<mcl::Buffer>(buffer_cb, nullptr, 0, nullptr, nullptr, mir_buffer_usage_software) };
2095 mtd::MockProtobufServer mock_server;
2096 std::shared_ptr<mcl::PresentationChain> chain{ std::make_shared<mcl::PresentationChain>(
2097- nullptr, 0, mock_server, nullptr, nullptr) };
2098+ nullptr, 0, mock_server, nullptr, nullptr, nullptr, std::shared_ptr<mcl::SurfaceMap>(nullptr), 0) };
2099
2100 mf::SurfaceId const surface_id{43};
2101 mf::BufferStreamId const stream_id{43};
2102
2103=== modified file 'tests/unit-tests/client/test_presentation_chain.cpp'
2104--- tests/unit-tests/client/test_presentation_chain.cpp 2016-06-02 05:33:50 +0000
2105+++ tests/unit-tests/client/test_presentation_chain.cpp 2016-06-03 01:46:54 +0000
2106@@ -21,13 +21,18 @@
2107 #include "mir/test/doubles/mock_client_buffer.h"
2108 #include "mir/test/fake_shared.h"
2109 #include "src/client/presentation_chain.h"
2110+#include "src/client/connection_surface_map.h"
2111 #include "src/client/buffer_factory.h"
2112 #include "mir/client_buffer_factory.h"
2113+#include "stub_client_platform.h"
2114
2115 #include <mutex>
2116 #include <condition_variable>
2117 #include <gtest/gtest.h>
2118+
2119 using namespace testing;
2120+
2121+namespace mt = mir::test;
2122 namespace mtd = mir::test::doubles;
2123 namespace geom = mir::geometry;
2124 namespace mcl = mir::client;
2125@@ -50,11 +55,15 @@
2126 geom::Size size {100, 200};
2127 MirPixelFormat format = mir_pixel_format_abgr_8888;
2128 MirBufferUsage usage = mir_buffer_usage_software;
2129- mtd::MockProtobufServer mock_server;
2130+ NiceMock<mtd::MockProtobufServer> mock_server;
2131 int buffer_id {4312};
2132 mp::Buffer ipc_buf;
2133 std::shared_ptr<mtd::StubClientBuffer> client_buffer = std::make_shared<mtd::StubClientBuffer>(
2134 std::make_shared<MirBufferPackage>(), size, format);
2135+ std::shared_ptr<mcl::ConnectionSurfaceMap> map{std::make_shared<mcl::ConnectionSurfaceMap>()};
2136+ mtd::StubClientBufferFactory stub_factory;
2137+ std::shared_ptr<mcl::BufferFactory> factory{std::make_shared<mcl::BufferFactory>()};
2138+ size_t nbuffers{3};
2139 };
2140
2141 MATCHER_P(BufferRequestMatches, val, "")
2142@@ -65,6 +74,9 @@
2143 arg->buffer().buffer_id() == val.buffer().buffer_id());
2144 }
2145
2146+EGLNativeWindowType StubClientPlatform::egl_native_window{
2147+ reinterpret_cast<EGLNativeWindowType>(&StubClientPlatform::egl_native_window)};
2148+
2149 void buffer_callback(MirBuffer*, void*)
2150 {
2151 }
2152@@ -75,8 +87,11 @@
2153 {
2154 mcl::PresentationChain chain(
2155 connection, rpc_id, mock_server,
2156+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2157 std::make_shared<mtd::StubClientBufferFactory>(),
2158- std::make_shared<mcl::BufferFactory>());
2159+ factory,
2160+ map,
2161+ nbuffers);
2162 EXPECT_THAT(chain.connection(), Eq(connection));
2163 }
2164
2165@@ -84,8 +99,11 @@
2166 {
2167 mcl::PresentationChain chain(
2168 connection, rpc_id, mock_server,
2169+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2170 std::make_shared<mtd::StubClientBufferFactory>(),
2171- std::make_shared<mcl::BufferFactory>());
2172+ factory,
2173+ map,
2174+ nbuffers);
2175 EXPECT_THAT(chain.rpc_id(), Eq(rpc_id));
2176 }
2177
2178@@ -101,8 +119,11 @@
2179 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
2180 mcl::PresentationChain chain(
2181 connection, rpc_id, mock_server,
2182+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2183 std::make_shared<mtd::StubClientBufferFactory>(),
2184- std::make_shared<mcl::BufferFactory>());
2185+ factory,
2186+ map,
2187+ nbuffers);
2188
2189 buffer.received();
2190 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
2191@@ -116,8 +137,11 @@
2192 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
2193 mcl::PresentationChain chain(
2194 connection, rpc_id, mock_server,
2195+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2196 std::make_shared<mtd::StubClientBufferFactory>(),
2197- std::make_shared<mcl::BufferFactory>());
2198+ factory,
2199+ map,
2200+ nbuffers);
2201
2202 buffer.received();
2203 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
2204@@ -126,3 +150,81 @@
2205 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
2206 }, std::logic_error);
2207 }
2208+
2209+TEST_F(PresentationChain, gets_egl_native_window)
2210+{
2211+ int const width = 73;
2212+ int const height = 32;
2213+ MirPixelFormat const format = mir_pixel_format_argb_8888;
2214+
2215+ mcl::PresentationChain chain(
2216+ connection, rpc_id, mock_server,
2217+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2218+ std::make_shared<mtd::StubClientBufferFactory>(),
2219+ factory,
2220+ map,
2221+ nbuffers);
2222+
2223+ EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format));
2224+}
2225+
2226+TEST_F(PresentationChain, returns_correct_parameters)
2227+{
2228+ int const width = 73;
2229+ int const height = 32;
2230+ MirPixelFormat const format = mir_pixel_format_argb_8888;
2231+ MirBufferUsage const usage = mir_buffer_usage_hardware;
2232+ MirSurfaceParameters params;
2233+
2234+ mcl::PresentationChain chain(
2235+ connection, rpc_id, mock_server,
2236+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2237+ std::make_shared<mtd::StubClientBufferFactory>(),
2238+ factory,
2239+ map,
2240+ nbuffers);
2241+ chain.egl_native_window(geom::Size{width, height}, format);
2242+
2243+ EXPECT_NO_THROW(params = chain.get_parameters());
2244+
2245+ EXPECT_STREQ("", params.name);
2246+ EXPECT_EQ(width, params.width);
2247+ EXPECT_EQ(height, params.height);
2248+ EXPECT_EQ(format, params.pixel_format);
2249+ EXPECT_EQ(usage, params.buffer_usage);
2250+}
2251+
2252+TEST_F(PresentationChain, EGLNativeSurface_functions_throw_when_egl_native_window_not_called)
2253+{
2254+ mcl::PresentationChain chain(
2255+ connection, rpc_id, mock_server,
2256+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2257+ std::make_shared<mtd::StubClientBufferFactory>(),
2258+ factory,
2259+ map,
2260+ nbuffers);
2261+
2262+ ASSERT_THROW(chain.get_parameters(), std::runtime_error);
2263+}
2264+
2265+TEST_F(PresentationChain, submission_throws_in_EGL_mode)
2266+{
2267+ int const width = 73;
2268+ int const height = 32;
2269+ MirPixelFormat const format = mir_pixel_format_argb_8888;
2270+
2271+ mcl::PresentationChain chain(
2272+ connection, rpc_id, mock_server,
2273+ std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
2274+ std::make_shared<mtd::StubClientBufferFactory>(),
2275+ factory,
2276+ map,
2277+ nbuffers);
2278+
2279+ EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format));
2280+
2281+ mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
2282+ buffer.received();
2283+
2284+ ASSERT_THROW(chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)), std::runtime_error);
2285+}

Subscribers

People subscribed via source and target branches