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
=== modified file 'playground/CMakeLists.txt'
--- playground/CMakeLists.txt 2016-05-03 06:55:25 +0000
+++ playground/CMakeLists.txt 2016-06-03 01:46:54 +0000
@@ -28,3 +28,13 @@
28 mirclient28 mirclient
29 m29 m
30)30)
31
32mir_add_wrapped_executable(mir_demo_client_eglflash_nbs
33 eglflash_nbs.c
34)
35
36target_link_libraries(mir_demo_client_eglflash_nbs
37 mirclient
38 ${EGL_LIBRARIES}
39 ${GLESv2_LIBRARIES}
40)
3141
=== added file 'playground/eglflash_nbs.c'
--- playground/eglflash_nbs.c 1970-01-01 00:00:00 +0000
+++ playground/eglflash_nbs.c 2016-06-03 01:46:54 +0000
@@ -0,0 +1,155 @@
1/*
2 * Trivial GL demo; flashes the screen with nbs.
3 *
4 * Copyright © 2016 Canonical Ltd.
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 3 as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 * Author: Cemil Azizoglu <cemil.azizoglu@canonical.com>
19 */
20
21#include <mir_toolkit/mir_client_library.h>
22#include <mir_toolkit/mir_presentation_chain.h>
23#include <mir_toolkit/mir_buffer.h>
24
25#include <stdio.h>
26#include <string.h>
27#include <unistd.h>
28#include <EGL/egl.h>
29#include <GLES2/gl2.h>
30#include <pthread.h>
31
32typedef struct Color
33{
34 GLfloat r, g, b, a;
35} Color;
36
37#define CHECK(_cond, _err) \
38 if (!(_cond)) \
39 { \
40 printf("%s\n", (_err)); \
41 return -1; \
42 }
43
44int main(int argc, char *argv[])
45{
46 (void) argc;
47 (void) argv;
48 unsigned int num_frames = 0;
49 const char* appname = "eglnbsdemo";
50 int width = 100;
51 int height = 100;
52 EGLDisplay egldisplay;
53 EGLSurface eglsurface;
54 EGLint ctxattribs[] =
55 {
56 EGL_CONTEXT_CLIENT_VERSION, 2,
57 EGL_NONE
58 };
59 EGLConfig eglconfig;
60 EGLint neglconfigs;
61 EGLContext eglctx;
62 EGLBoolean ok;
63 MirConnection* connection = NULL;
64 MirSurface* surface = NULL;
65 MirPresentationChain* chain = NULL;
66
67 connection = mir_connect_sync(NULL, appname);
68 CHECK(mir_connection_is_valid(connection), "Can't get connection");
69
70 egldisplay = eglGetDisplay(
71 mir_connection_get_egl_native_display(connection));
72 CHECK(egldisplay != EGL_NO_DISPLAY, "Can't eglGetDisplay");
73
74 ok = eglInitialize(egldisplay, NULL, NULL);
75 CHECK(ok, "Can't eglInitialize");
76
77 const EGLint attribs[] =
78 {
79 EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
80 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
81 EGL_RED_SIZE, 8,
82 EGL_GREEN_SIZE, 8,
83 EGL_BLUE_SIZE, 8,
84 EGL_ALPHA_SIZE, 8,
85 EGL_NONE
86 };
87
88 ok = eglChooseConfig(egldisplay, attribs, &eglconfig, 1, &neglconfigs);
89 CHECK(ok, "Could not eglChooseConfig");
90 CHECK(neglconfigs > 0, "No EGL config available");
91
92 MirPixelFormat pixel_format =
93 mir_connection_get_egl_pixel_format(connection, egldisplay, eglconfig);
94
95 printf("Mir chose pixel format %d.\n", pixel_format);
96
97 MirSurfaceSpec *spec =
98 mir_connection_create_spec_for_normal_surface(connection, width, height, pixel_format);
99
100 CHECK(spec, "Can't create a surface spec");
101
102 mir_surface_spec_set_name(spec, appname);
103
104 chain = mir_connection_create_presentation_chain_sync(connection);
105 CHECK(mir_presentation_chain_is_valid(chain), "Can't create presentation chain");
106
107 mir_surface_spec_add_presentation_chain(
108 spec, width, height, 0, 0, chain);
109
110 surface = mir_surface_create_sync(spec);
111
112 mir_surface_spec_release(spec);
113
114 eglsurface = eglCreateWindowSurface(egldisplay, eglconfig,
115 (EGLNativeWindowType)mir_create_egl_native_window(chain, width, height, pixel_format), NULL);
116
117 CHECK(eglsurface != EGL_NO_SURFACE, "eglCreateWindowSurface failed");
118
119 eglctx = eglCreateContext(egldisplay, eglconfig, EGL_NO_CONTEXT,
120 ctxattribs);
121 CHECK(eglctx != EGL_NO_CONTEXT, "eglCreateContext failed");
122
123 ok = eglMakeCurrent(egldisplay, eglsurface, eglsurface, eglctx);
124 CHECK(ok, "Can't eglMakeCurrent");
125
126 Color red = {1.0f, 0.0f, 0.0f, 1.0f};
127 Color green = {0.0f, 1.0f, 0.0f, 1.0f};
128 Color blue = {0.0f, 0.0f, 1.0f, 1.0f};
129
130 do
131 {
132 glClearColor(red.r, red.g, red.b, red.a);
133 glClear(GL_COLOR_BUFFER_BIT);
134 eglSwapBuffers(egldisplay, eglsurface);
135 sleep(1);
136
137 glClearColor(green.r, green.g, green.b, green.a);
138 glClear(GL_COLOR_BUFFER_BIT);
139 eglSwapBuffers(egldisplay, eglsurface);
140 sleep(1);
141
142 glClearColor(blue.r, blue.g, blue.b, blue.a);
143 glClear(GL_COLOR_BUFFER_BIT);
144 eglSwapBuffers(egldisplay, eglsurface);
145 sleep(1);
146 } while (num_frames++ < 3);
147
148 eglMakeCurrent(egldisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
149 eglTerminate(egldisplay);
150 mir_presentation_chain_release(chain);
151 mir_surface_release_sync(surface);
152 mir_connection_release(connection);
153
154 return 0;
155}
0156
=== modified file 'src/client/CMakeLists.txt'
--- src/client/CMakeLists.txt 2016-06-02 05:33:50 +0000
+++ src/client/CMakeLists.txt 2016-06-03 01:46:54 +0000
@@ -88,6 +88,8 @@
88 mir_error.cpp88 mir_error.cpp
89 mir_error.h89 mir_error.h
90 mir_error_api.cpp90 mir_error_api.cpp
91 exchange_semantics.cpp
92 new_buffer_semantics.cpp
91 ${MIR_CLIENT_SOURCES}93 ${MIR_CLIENT_SOURCES}
92 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h94 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/events/surface_output_event.h
93 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_display_configuration.h95 ${CMAKE_SOURCE_DIR}/include/client/mir_toolkit/mir_display_configuration.h
9496
=== added file 'src/client/buffer_semantics.h'
--- src/client/buffer_semantics.h 1970-01-01 00:00:00 +0000
+++ src/client/buffer_semantics.h 2016-06-03 01:46:54 +0000
@@ -0,0 +1,410 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#include "buffer_stream.h"
20#include "buffer.h"
21#include "buffer_factory.h"
22#include "make_protobuf_object.h"
23#include "mir_connection.h"
24#include "perf_report.h"
25#include "logging/perf_report.h"
26#include "rpc/mir_display_server.h"
27#include "mir_protobuf.pb.h"
28#include "buffer_vault.h"
29#include "protobuf_to_native_buffer.h"
30#include "buffer.h"
31#include "connection_surface_map.h"
32
33#include "mir/log.h"
34#include "mir/client_platform.h"
35#include "mir/frontend/client_constants.h"
36#include "mir_toolkit/mir_native_buffer.h"
37
38#include <boost/throw_exception.hpp>
39#include <boost/exception/diagnostic_information.hpp>
40
41#include <stdexcept>
42
43namespace mcl = mir::client;
44namespace mclr = mir::client::rpc;
45namespace mf = mir::frontend;
46namespace mp = mir::protobuf;
47namespace geom = mir::geometry;
48
49namespace mir
50{
51namespace client
52{
53//An internal interface useful in transitioning buffer exchange semantics based on
54//the BufferStream response provided by the server
55struct ServerBufferSemantics
56{
57 virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0;
58 virtual void set_buffer_cache_size(unsigned int) = 0;
59 virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0;
60 virtual uint32_t current_buffer_id() = 0;
61 virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
62 virtual void lost_connection() = 0;
63 virtual void set_size(geom::Size) = 0;
64 virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0;
65 virtual void set_interval(int interval) = 0;
66 virtual geom::Size size() const = 0;
67 virtual ~ServerBufferSemantics() = default;
68 ServerBufferSemantics() = default;
69 ServerBufferSemantics(ServerBufferSemantics const&) = delete;
70 ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
71};
72}
73}
74
75namespace
76{
77
78struct ExchangeSemantics : mcl::ServerBufferSemantics
79{
80 ExchangeSemantics(
81 mir::protobuf::DisplayServer& server,
82 std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers,
83 mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
84 wrapped{factory, max_buffers},
85 display_server(server),
86 size_(first_size)
87 {
88 wrapped.deposit_package(
89 mcl::protobuf_to_native_buffer(first_buffer),
90 first_buffer.buffer_id(), first_size, first_pf);
91 }
92
93 void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override
94 {
95 std::unique_lock<std::mutex> lock(mutex);
96 if (size.is_set())
97 size_ = size.value();
98
99 if (on_incoming_buffer)
100 {
101 wrapped.deposit_package(
102 mcl::protobuf_to_native_buffer(buffer),
103 buffer.buffer_id(), size_, pf);
104 if (on_incoming_buffer)
105 {
106 on_incoming_buffer();
107 next_buffer_wait_handle.result_received();
108 on_incoming_buffer = std::function<void()>{};
109 }
110 }
111 else
112 {
113 incoming_buffers.push(buffer);
114 }
115 }
116
117 void set_buffer_cache_size(unsigned int sz) override
118 {
119 std::unique_lock<std::mutex> lock(mutex);
120 wrapped.set_max_buffers(sz);
121 }
122 std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
123 {
124 std::unique_lock<std::mutex> lock(mutex);
125 return wrapped.current_buffer();
126 }
127 uint32_t current_buffer_id() override
128 {
129 std::unique_lock<std::mutex> lock(mutex);
130 if (incoming_buffers.size())
131 return incoming_buffers.front().buffer_id();
132 return wrapped.current_buffer_id();
133 }
134
135 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override
136 {
137 std::unique_lock<std::mutex> lock(mutex);
138 if (server_connection_lost)
139 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
140 //always submit what we have, whether we have a buffer, or will have to wait for an async reply
141 auto request = mcl::make_protobuf_object<mp::BufferRequest>();
142 request->mutable_id()->set_value(stream_id);
143 request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
144 lock.unlock();
145
146 display_server.submit_buffer(request.get(), protobuf_void.get(),
147 google::protobuf::NewCallback(google::protobuf::DoNothing));
148
149 lock.lock();
150 if (server_connection_lost)
151 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
152 if (incoming_buffers.empty())
153 {
154 next_buffer_wait_handle.expect_result();
155 on_incoming_buffer = done;
156 }
157 else
158 {
159 wrapped.deposit_package(
160 mcl::protobuf_to_native_buffer(incoming_buffers.front()),
161 incoming_buffers.front().buffer_id(), size_, pf);
162 incoming_buffers.pop();
163 done();
164 }
165 return &next_buffer_wait_handle;
166 }
167
168 void lost_connection() override
169 {
170 std::unique_lock<std::mutex> lock(mutex);
171 server_connection_lost = true;
172 if (on_incoming_buffer)
173 {
174 on_incoming_buffer();
175 on_incoming_buffer = std::function<void()>{};
176 }
177 if (next_buffer_wait_handle.is_pending())
178 next_buffer_wait_handle.result_received();
179
180 while (!incoming_buffers.empty())
181 {
182 auto b = incoming_buffers.front();
183 for (auto i = 0; i < b.fd_size(); i++)
184 close(b.fd(i));
185 incoming_buffers.pop();
186 }
187 }
188
189 void set_size(geom::Size) override
190 {
191 }
192
193 geom::Size size() const override
194 {
195 std::unique_lock<std::mutex> lk(mutex);
196 return size_;
197 }
198
199 void on_scale_set(float scale)
200 {
201 std::unique_lock<decltype(mutex)> lock(mutex);
202 scale_ = scale;
203 scale_wait_handle.result_received();
204 }
205
206 MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override
207 {
208 mp::StreamConfiguration configuration;
209 configuration.mutable_id()->set_value(stream_id.as_value());
210 configuration.set_scale(scale);
211 scale_wait_handle.expect_result();
212
213 display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
214 google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
215 return &scale_wait_handle;
216 }
217
218 void set_interval(int) override
219 {
220 }
221
222 std::mutex mutable mutex;
223 mcl::ClientBufferDepository wrapped;
224 mir::protobuf::DisplayServer& display_server;
225 std::function<void()> on_incoming_buffer;
226 std::queue<mir::protobuf::Buffer> incoming_buffers;
227 std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()};
228 MirWaitHandle next_buffer_wait_handle;
229 bool server_connection_lost {false};
230 MirWaitHandle scale_wait_handle;
231 float scale_;
232 geom::Size size_;
233};
234
235class Requests : public mcl::ServerBufferRequests
236{
237public:
238 Requests(mclr::DisplayServer& server, int stream_id) :
239 server(server),
240 stream_id(stream_id)
241 {
242 }
243
244 void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override
245 {
246 mp::BufferAllocation request;
247 request.mutable_id()->set_value(stream_id);
248 auto buf_params = request.add_buffer_requests();
249 buf_params->set_width(size.width.as_int());
250 buf_params->set_height(size.height.as_int());
251 buf_params->set_pixel_format(format);
252 buf_params->set_buffer_usage(usage);
253
254 //note, NewCallback will trigger on exception, deleting this object there
255 auto protobuf_void = new mp::Void;
256 server.allocate_buffers(&request, protobuf_void,
257 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
258 }
259
260 void free_buffer(int buffer_id) override
261 {
262 mp::BufferRelease request;
263 request.mutable_id()->set_value(stream_id);
264 request.add_buffers()->set_buffer_id(buffer_id);
265
266 //note, NewCallback will trigger on exception, deleting this object there
267 auto protobuf_void = new mp::Void;
268 server.release_buffers(&request, protobuf_void,
269 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
270 }
271
272 void submit_buffer(mcl::Buffer& buffer) override
273 {
274 mp::BufferRequest request;
275 request.mutable_id()->set_value(stream_id);
276 request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
277
278 //note, NewCallback will trigger on exception, deleting this object there
279 auto protobuf_void = new mp::Void;
280 server.submit_buffer(&request, protobuf_void,
281 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
282 }
283
284 static void ignore_response(mp::Void* void_response)
285 {
286 delete void_response;
287 }
288
289private:
290 mclr::DisplayServer& server;
291 mp::Void protobuf_void;
292 int stream_id;
293};
294
295struct NewBufferSemantics : mcl::ServerBufferSemantics
296{
297 NewBufferSemantics(
298 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
299 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
300 std::shared_ptr<mcl::ServerBufferRequests> const& requests,
301 std::weak_ptr<mcl::SurfaceMap> const& surface_map,
302 geom::Size size, MirPixelFormat format, int usage,
303 unsigned int initial_nbuffers) :
304 vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
305 current(nullptr),
306 future(vault.withdraw()),
307 size_(size)
308 {
309 }
310
311 void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override
312 {
313 }
314
315 void advance_current_buffer(std::unique_lock<std::mutex>& lk)
316 {
317 lk.unlock();
318 auto c = future.get();
319 lk.lock();
320 current = c;
321 }
322
323 std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
324 {
325 std::unique_lock<std::mutex> lk(mutex);
326 if (!current)
327 advance_current_buffer(lk);
328 return current->client_buffer();
329 }
330
331 uint32_t current_buffer_id() override
332 {
333 std::unique_lock<std::mutex> lk(mutex);
334 if (!current)
335 advance_current_buffer(lk);
336 return current->rpc_id();
337 }
338
339 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override
340 {
341 std::unique_lock<std::mutex> lk(mutex);
342 if (!current)
343 advance_current_buffer(lk);
344 auto c = current;
345 current = nullptr;
346 lk.unlock();
347
348 vault.deposit(c);
349 auto wh = vault.wire_transfer_outbound(c, done);
350 auto f = vault.withdraw();
351 lk.lock();
352 future = std::move(f);
353 return wh;
354 }
355
356 void set_size(geom::Size size) override
357 {
358 {
359 std::unique_lock<std::mutex> lk(mutex);
360 size_ = size;
361 }
362 vault.set_size(size);
363 }
364
365 geom::Size size() const override
366 {
367 std::unique_lock<std::mutex> lk(mutex);
368 return size_;
369 }
370
371 void lost_connection() override
372 {
373 vault.disconnected();
374 }
375
376 void set_buffer_cache_size(unsigned int) override
377 {
378 }
379
380 MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override
381 {
382 scale_wait_handle.expect_result();
383 scale_wait_handle.result_received();
384 vault.set_scale(scale);
385 return &scale_wait_handle;
386 }
387
388 void set_interval(int interval) override
389 {
390 std::unique_lock<decltype(mutex)> lk(mutex);
391 interval = std::max(0, std::min(1, interval));
392 if (current_swap_interval == interval)
393 return;
394 if (interval == 0)
395 vault.increase_buffer_count();
396 else
397 vault.decrease_buffer_count();
398 current_swap_interval = interval;
399 }
400
401 mcl::BufferVault vault;
402 std::mutex mutable mutex;
403 std::shared_ptr<mcl::Buffer> current{nullptr};
404 mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future;
405 MirWaitHandle scale_wait_handle;
406 int current_swap_interval = 1;
407 geom::Size size_;
408};
409
410}
0411
=== modified file 'src/client/buffer_stream.cpp'
--- src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000
+++ src/client/buffer_stream.cpp 2016-06-03 01:46:54 +0000
@@ -37,6 +37,9 @@
37#include "mir/frontend/client_constants.h"37#include "mir/frontend/client_constants.h"
38#include "mir_toolkit/mir_native_buffer.h"38#include "mir_toolkit/mir_native_buffer.h"
3939
40#include "exchange_semantics.h"
41#include "new_buffer_semantics.h"
42
40#include <boost/throw_exception.hpp>43#include <boost/throw_exception.hpp>
41#include <boost/exception/diagnostic_information.hpp>44#include <boost/exception/diagnostic_information.hpp>
4245
@@ -51,369 +54,6 @@
5154
52namespace gp = google::protobuf;55namespace gp = google::protobuf;
5356
54namespace mir
55{
56namespace client
57{
58//An internal interface useful in transitioning buffer exchange semantics based on
59//the BufferStream response provided by the server
60struct ServerBufferSemantics
61{
62 virtual void deposit(protobuf::Buffer const&, mir::optional_value<geometry::Size>, MirPixelFormat) = 0;
63 virtual void set_buffer_cache_size(unsigned int) = 0;
64 virtual std::shared_ptr<mir::client::ClientBuffer> current_buffer() = 0;
65 virtual uint32_t current_buffer_id() = 0;
66 virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
67 virtual void lost_connection() = 0;
68 virtual void set_size(geom::Size) = 0;
69 virtual MirWaitHandle* set_scale(float, mf::BufferStreamId) = 0;
70 virtual void set_interval(int interval) = 0;
71 virtual geom::Size size() const = 0;
72 virtual ~ServerBufferSemantics() = default;
73 ServerBufferSemantics() = default;
74 ServerBufferSemantics(ServerBufferSemantics const&) = delete;
75 ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
76};
77}
78}
79
80namespace
81{
82
83struct ExchangeSemantics : mcl::ServerBufferSemantics
84{
85 ExchangeSemantics(
86 mir::protobuf::DisplayServer& server,
87 std::shared_ptr<mcl::ClientBufferFactory> const& factory, int max_buffers,
88 mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
89 wrapped{factory, max_buffers},
90 display_server(server),
91 size_(first_size)
92 {
93 wrapped.deposit_package(
94 mcl::protobuf_to_native_buffer(first_buffer),
95 first_buffer.buffer_id(), first_size, first_pf);
96 }
97
98 void deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf) override
99 {
100 std::unique_lock<std::mutex> lock(mutex);
101 if (size.is_set())
102 size_ = size.value();
103
104 if (on_incoming_buffer)
105 {
106 wrapped.deposit_package(
107 mcl::protobuf_to_native_buffer(buffer),
108 buffer.buffer_id(), size_, pf);
109 if (on_incoming_buffer)
110 {
111 on_incoming_buffer();
112 next_buffer_wait_handle.result_received();
113 on_incoming_buffer = std::function<void()>{};
114 }
115 }
116 else
117 {
118 incoming_buffers.push(buffer);
119 }
120 }
121
122 void set_buffer_cache_size(unsigned int sz) override
123 {
124 std::unique_lock<std::mutex> lock(mutex);
125 wrapped.set_max_buffers(sz);
126 }
127 std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
128 {
129 std::unique_lock<std::mutex> lock(mutex);
130 return wrapped.current_buffer();
131 }
132 uint32_t current_buffer_id() override
133 {
134 std::unique_lock<std::mutex> lock(mutex);
135 if (incoming_buffers.size())
136 return incoming_buffers.front().buffer_id();
137 return wrapped.current_buffer_id();
138 }
139
140 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override
141 {
142 std::unique_lock<std::mutex> lock(mutex);
143 if (server_connection_lost)
144 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
145 //always submit what we have, whether we have a buffer, or will have to wait for an async reply
146 auto request = mcl::make_protobuf_object<mp::BufferRequest>();
147 request->mutable_id()->set_value(stream_id);
148 request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
149 lock.unlock();
150
151 display_server.submit_buffer(request.get(), protobuf_void.get(),
152 google::protobuf::NewCallback(google::protobuf::DoNothing));
153
154 lock.lock();
155 if (server_connection_lost)
156 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
157 if (incoming_buffers.empty())
158 {
159 next_buffer_wait_handle.expect_result();
160 on_incoming_buffer = done;
161 }
162 else
163 {
164 wrapped.deposit_package(
165 mcl::protobuf_to_native_buffer(incoming_buffers.front()),
166 incoming_buffers.front().buffer_id(), size_, pf);
167 incoming_buffers.pop();
168 done();
169 }
170 return &next_buffer_wait_handle;
171 }
172
173 void lost_connection() override
174 {
175 std::unique_lock<std::mutex> lock(mutex);
176 server_connection_lost = true;
177 if (on_incoming_buffer)
178 {
179 on_incoming_buffer();
180 on_incoming_buffer = std::function<void()>{};
181 }
182 if (next_buffer_wait_handle.is_pending())
183 next_buffer_wait_handle.result_received();
184
185 while (!incoming_buffers.empty())
186 {
187 auto b = incoming_buffers.front();
188 for (auto i = 0; i < b.fd_size(); i++)
189 close(b.fd(i));
190 incoming_buffers.pop();
191 }
192 }
193
194 void set_size(geom::Size) override
195 {
196 }
197
198 geom::Size size() const override
199 {
200 std::unique_lock<std::mutex> lk(mutex);
201 return size_;
202 }
203
204 void on_scale_set(float scale)
205 {
206 std::unique_lock<decltype(mutex)> lock(mutex);
207 scale_ = scale;
208 scale_wait_handle.result_received();
209 }
210
211 MirWaitHandle* set_scale(float scale, mf::BufferStreamId stream_id) override
212 {
213 mp::StreamConfiguration configuration;
214 configuration.mutable_id()->set_value(stream_id.as_value());
215 configuration.set_scale(scale);
216 scale_wait_handle.expect_result();
217
218 display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
219 google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
220 return &scale_wait_handle;
221 }
222
223 void set_interval(int) override
224 {
225 }
226
227 std::mutex mutable mutex;
228 mcl::ClientBufferDepository wrapped;
229 mir::protobuf::DisplayServer& display_server;
230 std::function<void()> on_incoming_buffer;
231 std::queue<mir::protobuf::Buffer> incoming_buffers;
232 std::unique_ptr<mir::protobuf::Void> protobuf_void{std::make_unique<mp::Void>()};
233 MirWaitHandle next_buffer_wait_handle;
234 bool server_connection_lost {false};
235 MirWaitHandle scale_wait_handle;
236 float scale_;
237 geom::Size size_;
238};
239
240class Requests : public mcl::ServerBufferRequests
241{
242public:
243 Requests(mclr::DisplayServer& server, int stream_id) :
244 server(server),
245 stream_id(stream_id)
246 {
247 }
248
249 void allocate_buffer(geom::Size size, MirPixelFormat format, int usage) override
250 {
251 mp::BufferAllocation request;
252 request.mutable_id()->set_value(stream_id);
253 auto buf_params = request.add_buffer_requests();
254 buf_params->set_width(size.width.as_int());
255 buf_params->set_height(size.height.as_int());
256 buf_params->set_pixel_format(format);
257 buf_params->set_buffer_usage(usage);
258
259 //note, NewCallback will trigger on exception, deleting this object there
260 auto protobuf_void = new mp::Void;
261 server.allocate_buffers(&request, protobuf_void,
262 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
263 }
264
265 void free_buffer(int buffer_id) override
266 {
267 mp::BufferRelease request;
268 request.mutable_id()->set_value(stream_id);
269 request.add_buffers()->set_buffer_id(buffer_id);
270
271 //note, NewCallback will trigger on exception, deleting this object there
272 auto protobuf_void = new mp::Void;
273 server.release_buffers(&request, protobuf_void,
274 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
275 }
276
277 void submit_buffer(mcl::Buffer& buffer) override
278 {
279 mp::BufferRequest request;
280 request.mutable_id()->set_value(stream_id);
281 request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
282
283 //note, NewCallback will trigger on exception, deleting this object there
284 auto protobuf_void = new mp::Void;
285 server.submit_buffer(&request, protobuf_void,
286 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
287 }
288
289 static void ignore_response(mp::Void* void_response)
290 {
291 delete void_response;
292 }
293
294private:
295 mclr::DisplayServer& server;
296 mp::Void protobuf_void;
297 int stream_id;
298};
299
300struct NewBufferSemantics : mcl::ServerBufferSemantics
301{
302 NewBufferSemantics(
303 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
304 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
305 std::shared_ptr<mcl::ServerBufferRequests> const& requests,
306 std::weak_ptr<mcl::SurfaceMap> const& surface_map,
307 geom::Size size, MirPixelFormat format, int usage,
308 unsigned int initial_nbuffers) :
309 vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
310 current(nullptr),
311 future(vault.withdraw()),
312 size_(size)
313 {
314 }
315
316 void deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat) override
317 {
318 }
319
320 void advance_current_buffer(std::unique_lock<std::mutex>& lk)
321 {
322 lk.unlock();
323 auto c = future.get();
324 lk.lock();
325 current = c;
326 }
327
328 std::shared_ptr<mir::client::ClientBuffer> current_buffer() override
329 {
330 std::unique_lock<std::mutex> lk(mutex);
331 if (!current)
332 advance_current_buffer(lk);
333 return current->client_buffer();
334 }
335
336 uint32_t current_buffer_id() override
337 {
338 std::unique_lock<std::mutex> lk(mutex);
339 if (!current)
340 advance_current_buffer(lk);
341 return current->rpc_id();
342 }
343
344 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override
345 {
346 std::unique_lock<std::mutex> lk(mutex);
347 if (!current)
348 advance_current_buffer(lk);
349 auto c = current;
350 current = nullptr;
351 lk.unlock();
352
353 vault.deposit(c);
354 auto wh = vault.wire_transfer_outbound(c, done);
355 auto f = vault.withdraw();
356 lk.lock();
357 future = std::move(f);
358 return wh;
359 }
360
361 void set_size(geom::Size size) override
362 {
363 {
364 std::unique_lock<std::mutex> lk(mutex);
365 size_ = size;
366 }
367 vault.set_size(size);
368 }
369
370 geom::Size size() const override
371 {
372 std::unique_lock<std::mutex> lk(mutex);
373 return size_;
374 }
375
376 void lost_connection() override
377 {
378 vault.disconnected();
379 }
380
381 void set_buffer_cache_size(unsigned int) override
382 {
383 }
384
385 MirWaitHandle* set_scale(float scale, mf::BufferStreamId) override
386 {
387 scale_wait_handle.expect_result();
388 scale_wait_handle.result_received();
389 vault.set_scale(scale);
390 return &scale_wait_handle;
391 }
392
393 void set_interval(int interval) override
394 {
395 std::unique_lock<decltype(mutex)> lk(mutex);
396 interval = std::max(0, std::min(1, interval));
397 if (current_swap_interval == interval)
398 return;
399 if (interval == 0)
400 vault.increase_buffer_count();
401 else
402 vault.decrease_buffer_count();
403 current_swap_interval = interval;
404 }
405
406 mcl::BufferVault vault;
407 std::mutex mutable mutex;
408 std::shared_ptr<mcl::Buffer> current{nullptr};
409 mir::client::NoTLSFuture<std::shared_ptr<mcl::Buffer>> future;
410 MirWaitHandle scale_wait_handle;
411 int current_swap_interval = 1;
412 geom::Size size_;
413};
414
415}
416
417mcl::BufferStream::BufferStream(57mcl::BufferStream::BufferStream(
418 MirConnection* connection,58 MirConnection* connection,
419 std::shared_ptr<MirWaitHandle> creation_wait_handle,59 std::shared_ptr<MirWaitHandle> creation_wait_handle,
42060
=== modified file 'src/client/buffer_stream.h'
--- src/client/buffer_stream.h 2016-06-02 05:33:50 +0000
+++ src/client/buffer_stream.h 2016-06-03 01:46:54 +0000
@@ -24,6 +24,7 @@
24#include "mir/client_buffer.h"24#include "mir/client_buffer.h"
25#include "client_buffer_stream.h"25#include "client_buffer_stream.h"
26#include "client_buffer_depository.h"26#include "client_buffer_depository.h"
27#include "server_buffer_semantics.h"
27#include "mir/geometry/size.h"28#include "mir/geometry/size.h"
2829
29#include "mir_toolkit/client_types.h"30#include "mir_toolkit/client_types.h"
@@ -66,8 +67,6 @@
66class ClientPlatform;67class ClientPlatform;
67class PerfReport;68class PerfReport;
68struct MemoryRegion;69struct MemoryRegion;
69class SurfaceMap;
70class ServerBufferSemantics;
71class BufferStream : public EGLNativeSurface, public ClientBufferStream70class BufferStream : public EGLNativeSurface, public ClientBufferStream
72{71{
73public:72public:
7473
=== modified file 'src/client/error_chain.cpp'
--- src/client/error_chain.cpp 2016-06-02 05:33:50 +0000
+++ src/client/error_chain.cpp 2016-06-03 01:46:54 +0000
@@ -51,3 +51,8 @@
51{51{
52 BOOST_THROW_EXCEPTION(std::logic_error("Cannot submit: invalid MirPresentationChain"));52 BOOST_THROW_EXCEPTION(std::logic_error("Cannot submit: invalid MirPresentationChain"));
53}53}
54
55EGLNativeWindowType mcl::ErrorChain::egl_native_window(geom::Size, MirPixelFormat)
56{
57 BOOST_THROW_EXCEPTION(std::logic_error("Cannot get native window: invalid MirPresentationChain"));
58}
5459
=== modified file 'src/client/error_chain.h'
--- src/client/error_chain.h 2016-06-02 05:33:50 +0000
+++ src/client/error_chain.h 2016-06-03 01:46:54 +0000
@@ -38,6 +38,7 @@
38 MirConnection* connection() const override;38 MirConnection* connection() const override;
39 int rpc_id() const override;39 int rpc_id() const override;
40 char const* error_msg() const override;40 char const* error_msg() const override;
41 EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override;
41private:42private:
42 MirConnection* const connection_;43 MirConnection* const connection_;
43 int const stream_id;44 int const stream_id;
4445
=== added file 'src/client/exchange_semantics.cpp'
--- src/client/exchange_semantics.cpp 1970-01-01 00:00:00 +0000
+++ src/client/exchange_semantics.cpp 2016-06-03 01:46:54 +0000
@@ -0,0 +1,173 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Cemil Azizoglu <cemil.azizoglu@canonical.com>
17 */
18
19#include "exchange_semantics.h"
20#include "buffer.h"
21#include "protobuf_to_native_buffer.h"
22#include "make_protobuf_object.h"
23
24#include <boost/throw_exception.hpp>
25
26namespace mcl = mir::client;
27namespace mf = mir::frontend;
28namespace mp = mir::protobuf;
29namespace geom = mir::geometry;
30
31mcl::ExchangeSemantics::ExchangeSemantics(
32 mp::DisplayServer& server,
33 std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers,
34 mp::Buffer const& first_buffer, geom::Size first_size, MirPixelFormat first_pf) :
35 wrapped{factory, max_buffers},
36 display_server(server),
37 size_(first_size)
38{
39 wrapped.deposit_package(
40 mcl::protobuf_to_native_buffer(first_buffer),
41 first_buffer.buffer_id(), first_size, first_pf);
42}
43
44void mcl::ExchangeSemantics::deposit(mp::Buffer const& buffer, mir::optional_value<geom::Size> size, MirPixelFormat pf)
45{
46 std::unique_lock<std::mutex> lock(mutex);
47 if (size.is_set())
48 size_ = size.value();
49
50 if (on_incoming_buffer)
51 {
52 wrapped.deposit_package(
53 mcl::protobuf_to_native_buffer(buffer),
54 buffer.buffer_id(), size_, pf);
55 if (on_incoming_buffer)
56 {
57 on_incoming_buffer();
58 next_buffer_wait_handle.result_received();
59 on_incoming_buffer = std::function<void()>{};
60 }
61 }
62 else
63 {
64 incoming_buffers.push(buffer);
65 }
66}
67
68void mcl::ExchangeSemantics::set_buffer_cache_size(unsigned int sz)
69{
70 std::unique_lock<std::mutex> lock(mutex);
71 wrapped.set_max_buffers(sz);
72}
73
74std::shared_ptr<mir::client::ClientBuffer> mcl::ExchangeSemantics::current_buffer()
75{
76 std::unique_lock<std::mutex> lock(mutex);
77 return wrapped.current_buffer();
78}
79
80uint32_t mcl::ExchangeSemantics::current_buffer_id()
81{
82 std::unique_lock<std::mutex> lock(mutex);
83 if (incoming_buffers.size())
84 return incoming_buffers.front().buffer_id();
85 return wrapped.current_buffer_id();
86}
87
88MirWaitHandle* mcl::ExchangeSemantics::submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id)
89{
90 std::unique_lock<std::mutex> lock(mutex);
91 if (server_connection_lost)
92 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
93 //always submit what we have, whether we have a buffer, or will have to wait for an async reply
94 auto request = mcl::make_protobuf_object<mp::BufferRequest>();
95 request->mutable_id()->set_value(stream_id);
96 request->mutable_buffer()->set_buffer_id(wrapped.current_buffer_id());
97 lock.unlock();
98
99 display_server.submit_buffer(request.get(), protobuf_void.get(),
100 google::protobuf::NewCallback(google::protobuf::DoNothing));
101
102 lock.lock();
103 if (server_connection_lost)
104 BOOST_THROW_EXCEPTION(std::runtime_error("disconnected: no new buffers"));
105 if (incoming_buffers.empty())
106 {
107 next_buffer_wait_handle.expect_result();
108 on_incoming_buffer = done;
109 }
110 else
111 {
112 wrapped.deposit_package(
113 mcl::protobuf_to_native_buffer(incoming_buffers.front()),
114 incoming_buffers.front().buffer_id(), size_, pf);
115 incoming_buffers.pop();
116 done();
117 }
118 return &next_buffer_wait_handle;
119}
120
121void mcl::ExchangeSemantics::lost_connection()
122{
123 std::unique_lock<std::mutex> lock(mutex);
124 server_connection_lost = true;
125 if (on_incoming_buffer)
126 {
127 on_incoming_buffer();
128 on_incoming_buffer = std::function<void()>{};
129 }
130 if (next_buffer_wait_handle.is_pending())
131 next_buffer_wait_handle.result_received();
132
133 while (!incoming_buffers.empty())
134 {
135 auto b = incoming_buffers.front();
136 for (auto i = 0; i < b.fd_size(); i++)
137 close(b.fd(i));
138 incoming_buffers.pop();
139 }
140}
141
142void mcl::ExchangeSemantics::set_size(geom::Size)
143{
144}
145
146geom::Size mcl::ExchangeSemantics::size() const
147{
148 std::unique_lock<std::mutex> lk(mutex);
149 return size_;
150}
151
152void mcl::ExchangeSemantics::on_scale_set(float scale)
153{
154 std::unique_lock<decltype(mutex)> lock(mutex);
155 scale_ = scale;
156 scale_wait_handle.result_received();
157}
158
159MirWaitHandle* mcl::ExchangeSemantics::set_scale(float scale, mf::BufferStreamId stream_id)
160{
161 mp::StreamConfiguration configuration;
162 configuration.mutable_id()->set_value(stream_id.as_value());
163 configuration.set_scale(scale);
164 scale_wait_handle.expect_result();
165
166 display_server.configure_buffer_stream(&configuration, protobuf_void.get(),
167 google::protobuf::NewCallback(this, &ExchangeSemantics::on_scale_set, scale));
168 return &scale_wait_handle;
169}
170
171void mcl::ExchangeSemantics::set_interval(int)
172{
173}
0174
=== added file 'src/client/exchange_semantics.h'
--- src/client/exchange_semantics.h 1970-01-01 00:00:00 +0000
+++ src/client/exchange_semantics.h 2016-06-03 01:46:54 +0000
@@ -0,0 +1,70 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_EXCHANGE_SEMANTICS_H
20#define MIR_CLIENT_EXCHANGE_SEMANTICS_H
21
22#include "server_buffer_semantics.h"
23#include <mir/protobuf/display_server.h>
24#include "mir/client_buffer_factory.h"
25#include "client_buffer_depository.h"
26#include "mir_wait_handle.h"
27
28#include <mutex>
29#include <queue>
30
31namespace mir
32{
33namespace client
34{
35
36struct ExchangeSemantics : ServerBufferSemantics
37{
38 ExchangeSemantics(
39 protobuf::DisplayServer& server,
40 std::shared_ptr<ClientBufferFactory> const& factory, int max_buffers,
41 protobuf::Buffer const& first_buffer, geometry::Size first_size, MirPixelFormat first_pf);
42 void deposit(protobuf::Buffer const& buffer, optional_value<geometry::Size> size, MirPixelFormat pf) override;
43 void set_buffer_cache_size(unsigned int sz) override;
44 std::shared_ptr<ClientBuffer> current_buffer() override;
45 uint32_t current_buffer_id() override;
46 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat pf, int stream_id) override;
47 void lost_connection() override;
48 void set_size(geometry::Size) override;
49 geometry::Size size() const override;
50 void set_interval(int) override;
51 void on_scale_set(float scale);
52 MirWaitHandle* set_scale(float scale, frontend::BufferStreamId stream_id) override;
53
54 std::mutex mutable mutex;
55 ClientBufferDepository wrapped;
56 protobuf::DisplayServer& display_server;
57 std::function<void()> on_incoming_buffer;
58 std::queue<protobuf::Buffer> incoming_buffers;
59 std::unique_ptr<protobuf::Void> protobuf_void{std::make_unique<protobuf::Void>()};
60 MirWaitHandle next_buffer_wait_handle;
61 bool server_connection_lost {false};
62 MirWaitHandle scale_wait_handle;
63 float scale_;
64 geometry::Size size_;
65};
66
67}
68}
69
70#endif /* MIR_CLIENT_EXCHANGE_SEMANTICS_H */
071
=== modified file 'src/client/mir_connection.cpp'
--- src/client/mir_connection.cpp 2016-06-02 05:33:50 +0000
+++ src/client/mir_connection.cpp 2016-06-03 01:46:54 +0000
@@ -1180,7 +1180,7 @@
1180 if (!client_buffer_factory)1180 if (!client_buffer_factory)
1181 client_buffer_factory = platform->create_buffer_factory();1181 client_buffer_factory = platform->create_buffer_factory();
1182 auto chain = std::make_shared<mcl::PresentationChain>(1182 auto chain = std::make_shared<mcl::PresentationChain>(
1183 this, protobuf_bs->id().value(), server, client_buffer_factory, buffer_factory);1183 this, protobuf_bs->id().value(), server, platform, client_buffer_factory, buffer_factory, surface_map, nbuffers);
11841184
1185 surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), chain);1185 surface_map->insert(mf::BufferStreamId(protobuf_bs->id().value()), chain);
11861186
11871187
=== modified file 'src/client/mir_presentation_chain.h'
--- src/client/mir_presentation_chain.h 2016-03-10 14:30:48 +0000
+++ src/client/mir_presentation_chain.h 2016-06-03 01:46:54 +0000
@@ -22,6 +22,18 @@
22#include "mir/geometry/size.h"22#include "mir/geometry/size.h"
23#include "mir_toolkit/mir_presentation_chain.h"23#include "mir_toolkit/mir_presentation_chain.h"
2424
25#include <EGL/eglplatform.h>
26
27//See comment in client_buffer_stream.h
28#include <type_traits>
29static_assert(
30 sizeof(EGLNativeWindowType) == sizeof(void*) &&
31 std::is_pod<EGLNativeWindowType>::value,
32 "MirPresentationChain requires that EGLNativeWindowType be no-op convertible to void*");
33
34#undef EGLNativeWindowType
35#define EGLNativeWindowType void*
36
25class MirPresentationChain37class MirPresentationChain
26{38{
27public:39public:
@@ -30,6 +42,7 @@
30 virtual MirConnection* connection() const = 0;42 virtual MirConnection* connection() const = 0;
31 virtual int rpc_id() const = 0;43 virtual int rpc_id() const = 0;
32 virtual char const* error_msg() const = 0;44 virtual char const* error_msg() const = 0;
45 virtual EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) = 0;
3346
34protected:47protected:
35 MirPresentationChain(MirPresentationChain const&) = delete;48 MirPresentationChain(MirPresentationChain const&) = delete;
3649
=== modified file 'src/client/mir_presentation_chain_api.cpp'
--- src/client/mir_presentation_chain_api.cpp 2016-05-03 06:55:25 +0000
+++ src/client/mir_presentation_chain_api.cpp 2016-06-03 01:46:54 +0000
@@ -124,3 +124,16 @@
124{124{
125 MIR_LOG_UNCAUGHT_EXCEPTION(ex);125 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
126}126}
127
128MirEGLNativeWindowType mir_create_egl_native_window(
129 MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format)
130try
131{
132 mir::require(presentation_chain && mir_presentation_chain_is_valid(presentation_chain));
133 return presentation_chain->egl_native_window(mir::geometry::Size{width, height}, pixel_format);
134}
135catch (std::exception const& ex)
136{
137 MIR_LOG_UNCAUGHT_EXCEPTION(ex);
138 return nullptr;
139}
127140
=== added file 'src/client/new_buffer_semantics.cpp'
--- src/client/new_buffer_semantics.cpp 1970-01-01 00:00:00 +0000
+++ src/client/new_buffer_semantics.cpp 2016-06-03 01:46:54 +0000
@@ -0,0 +1,181 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#include "new_buffer_semantics.h"
20#include "buffer.h"
21
22namespace mcl = mir::client;
23namespace mclr = mir::client::rpc;
24namespace mf = mir::frontend;
25namespace mp = mir::protobuf;
26namespace geom = mir::geometry;
27
28mcl::Requests::Requests(mclr::DisplayServer& server, int stream_id) :
29 server(server),
30 stream_id(stream_id)
31{
32}
33
34void mcl::Requests::allocate_buffer(geom::Size size, MirPixelFormat format, int usage)
35{
36 mp::BufferAllocation request;
37 request.mutable_id()->set_value(stream_id);
38 auto buf_params = request.add_buffer_requests();
39 buf_params->set_width(size.width.as_int());
40 buf_params->set_height(size.height.as_int());
41 buf_params->set_pixel_format(format);
42 buf_params->set_buffer_usage(usage);
43
44 //note, NewCallback will trigger on exception, deleting this object there
45 auto protobuf_void = new mp::Void;
46 server.allocate_buffers(&request, protobuf_void,
47 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
48}
49
50void mcl::Requests::free_buffer(int buffer_id)
51{
52 mp::BufferRelease request;
53 request.mutable_id()->set_value(stream_id);
54 request.add_buffers()->set_buffer_id(buffer_id);
55
56 //note, NewCallback will trigger on exception, deleting this object there
57 auto protobuf_void = new mp::Void;
58 server.release_buffers(&request, protobuf_void,
59 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
60}
61
62void mcl::Requests::submit_buffer(mcl::Buffer& buffer)
63{
64 mp::BufferRequest request;
65 request.mutable_id()->set_value(stream_id);
66 request.mutable_buffer()->set_buffer_id(buffer.rpc_id());
67
68 //note, NewCallback will trigger on exception, deleting this object there
69 auto protobuf_void = new mp::Void;
70 server.submit_buffer(&request, protobuf_void,
71 google::protobuf::NewCallback(Requests::ignore_response, protobuf_void));
72}
73
74void mcl::Requests::ignore_response(mp::Void* void_response)
75{
76 delete void_response;
77}
78
79mcl::NewBufferSemantics::NewBufferSemantics(
80 std::shared_ptr<mcl::ClientBufferFactory> const& factory,
81 std::shared_ptr<mcl::AsyncBufferFactory> const& mirbuffer_factory,
82 std::shared_ptr<mcl::ServerBufferRequests> const& requests,
83 std::weak_ptr<mcl::SurfaceMap> const& surface_map,
84 geom::Size size, MirPixelFormat format, int usage,
85 unsigned int initial_nbuffers) :
86 vault(factory, mirbuffer_factory, requests, surface_map, size, format, usage, initial_nbuffers),
87 current(nullptr),
88 future(vault.withdraw()),
89 size_(size)
90{
91}
92
93void mcl::NewBufferSemantics::deposit(mp::Buffer const&, mir::optional_value<geom::Size>, MirPixelFormat)
94{
95}
96
97void mcl::NewBufferSemantics::advance_current_buffer(std::unique_lock<std::mutex>& lk)
98{
99 lk.unlock();
100 auto c = future.get();
101 lk.lock();
102 current = c;
103}
104
105std::shared_ptr<mir::client::ClientBuffer> mcl::NewBufferSemantics::current_buffer()
106{
107 std::unique_lock<std::mutex> lk(mutex);
108 if (!current)
109 advance_current_buffer(lk);
110 return current->client_buffer();
111}
112
113uint32_t mcl::NewBufferSemantics::current_buffer_id()
114{
115 std::unique_lock<std::mutex> lk(mutex);
116 if (!current)
117 advance_current_buffer(lk);
118 return current->rpc_id();
119}
120
121MirWaitHandle* mcl::NewBufferSemantics::submit(std::function<void()> const& done, MirPixelFormat, int)
122{
123 std::unique_lock<std::mutex> lk(mutex);
124 if (!current)
125 advance_current_buffer(lk);
126 auto c = current;
127 current = nullptr;
128 lk.unlock();
129
130 vault.deposit(c);
131 auto wh = vault.wire_transfer_outbound(c, done);
132 auto f = vault.withdraw();
133 lk.lock();
134 future = std::move(f);
135 return wh;
136}
137
138void mcl::NewBufferSemantics::set_size(geom::Size size)
139{
140 {
141 std::unique_lock<std::mutex> lk(mutex);
142 size_ = size;
143 }
144 vault.set_size(size);
145}
146
147geom::Size mcl::NewBufferSemantics::size() const
148{
149 std::unique_lock<std::mutex> lk(mutex);
150 return size_;
151}
152
153void mcl::NewBufferSemantics::lost_connection()
154{
155 vault.disconnected();
156}
157
158void mcl::NewBufferSemantics::set_buffer_cache_size(unsigned int)
159{
160}
161
162MirWaitHandle* mcl::NewBufferSemantics::set_scale(float scale, mf::BufferStreamId)
163{
164 scale_wait_handle.expect_result();
165 scale_wait_handle.result_received();
166 vault.set_scale(scale);
167 return &scale_wait_handle;
168}
169
170void mcl::NewBufferSemantics::set_interval(int interval)
171{
172 std::unique_lock<decltype(mutex)> lk(mutex);
173 interval = std::max(0, std::min(1, interval));
174 if (current_swap_interval == interval)
175 return;
176 if (interval == 0)
177 vault.increase_buffer_count();
178 else
179 vault.decrease_buffer_count();
180 current_swap_interval = interval;
181}
0182
=== added file 'src/client/new_buffer_semantics.h'
--- src/client/new_buffer_semantics.h 1970-01-01 00:00:00 +0000
+++ src/client/new_buffer_semantics.h 2016-06-03 01:46:54 +0000
@@ -0,0 +1,79 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_NEW_BUFFER_SEMANTICS_H
20#define MIR_CLIENT_NEW_BUFFER_SEMANTICS_H
21
22#include "server_buffer_semantics.h"
23#include "buffer_vault.h"
24#include "rpc/mir_display_server.h"
25
26namespace mir
27{
28namespace client
29{
30
31class Requests : public ServerBufferRequests
32{
33public:
34 Requests(client::rpc::DisplayServer& server, int stream_id);
35 void allocate_buffer(geometry::Size size, MirPixelFormat format, int usage) override;
36 void free_buffer(int buffer_id) override;
37 void submit_buffer(Buffer& buffer) override;
38 static void ignore_response(protobuf::Void* void_response);
39
40private:
41 client::rpc::DisplayServer& server;
42 protobuf::Void protobuf_void;
43 int stream_id;
44};
45
46struct NewBufferSemantics : ServerBufferSemantics
47{
48 NewBufferSemantics(
49 std::shared_ptr<ClientBufferFactory> const& factory,
50 std::shared_ptr<AsyncBufferFactory> const& mirbuffer_factory,
51 std::shared_ptr<ServerBufferRequests> const& requests,
52 std::weak_ptr<SurfaceMap> const& surface_map,
53 geometry::Size size, MirPixelFormat format, int usage,
54 unsigned int initial_nbuffers);
55 void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) override;
56 void advance_current_buffer(std::unique_lock<std::mutex>& lk);
57 std::shared_ptr<ClientBuffer> current_buffer() override;
58 uint32_t current_buffer_id() override;
59 MirWaitHandle* submit(std::function<void()> const& done, MirPixelFormat, int) override;
60 void set_size(geometry::Size size) override;
61 geometry::Size size() const override;
62 void lost_connection() override;
63 void set_buffer_cache_size(unsigned int) override;
64 MirWaitHandle* set_scale(float scale, frontend::BufferStreamId) override;
65 void set_interval(int interval) override;
66
67 BufferVault vault;
68 std::mutex mutable mutex;
69 std::shared_ptr<Buffer> current{nullptr};
70 NoTLSFuture<std::shared_ptr<Buffer>> future;
71 MirWaitHandle scale_wait_handle;
72 int current_swap_interval = 1;
73 geometry::Size size_;
74};
75
76}
77}
78
79#endif /* MIR_CLIENT_NEW_BUFFER_SEMANTICS_H */
080
=== modified file 'src/client/presentation_chain.cpp'
--- src/client/presentation_chain.cpp 2016-06-02 05:33:50 +0000
+++ src/client/presentation_chain.cpp 2016-06-03 01:46:54 +0000
@@ -22,6 +22,8 @@
22#include "presentation_chain.h"22#include "presentation_chain.h"
23#include "protobuf_to_native_buffer.h"23#include "protobuf_to_native_buffer.h"
24#include "buffer_factory.h"24#include "buffer_factory.h"
25#include "new_buffer_semantics.h"
26#include "mir/client_platform.h"
25#include <boost/throw_exception.hpp>27#include <boost/throw_exception.hpp>
26#include <algorithm>28#include <algorithm>
2729
@@ -34,13 +36,22 @@
34 MirConnection* connection,36 MirConnection* connection,
35 int stream_id,37 int stream_id,
36 mir::client::rpc::DisplayServer& server,38 mir::client::rpc::DisplayServer& server,
39 std::shared_ptr<ClientPlatform> const& client_platform,
37 std::shared_ptr<mcl::ClientBufferFactory> const& native_buffer_factory,40 std::shared_ptr<mcl::ClientBufferFactory> const& native_buffer_factory,
38 std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory) :41 std::shared_ptr<mcl::AsyncBufferFactory> const& mir_buffer_factory,
39 connection_(connection),42 std::weak_ptr<SurfaceMap> const& map,
40 stream_id(stream_id),43 size_t nbuffers) :
41 server(server),44 connection_(connection),
42 native_buffer_factory(native_buffer_factory),45 stream_id(stream_id),
43 mir_buffer_factory(mir_buffer_factory)46 server(server),
47 client_platform(client_platform),
48 native_buffer_factory(native_buffer_factory),
49 mir_buffer_factory(mir_buffer_factory),
50 egl_native_window_(nullptr),
51 map(map),
52 nbuffers(nbuffers),
53 buffer_depository(nullptr),
54 egl_native_window_pixel_format(mir_pixel_format_invalid)
44{55{
45}56}
4657
@@ -58,6 +69,9 @@
5869
59void mcl::PresentationChain::submit_buffer(MirBuffer* mirbuffer)70void mcl::PresentationChain::submit_buffer(MirBuffer* mirbuffer)
60{71{
72 if (egl_native_window_)
73 BOOST_THROW_EXCEPTION(std::runtime_error("Buffers cannot be submitted when chain is in EGL mode"));
74
61 mp::BufferRequest request;75 mp::BufferRequest request;
62 {76 {
63 auto buffer = reinterpret_cast<mcl::Buffer*>(mirbuffer);77 auto buffer = reinterpret_cast<mcl::Buffer*>(mirbuffer);
@@ -84,3 +98,82 @@
84{98{
85 return "";99 return "";
86}100}
101
102EGLNativeWindowType mcl::PresentationChain::egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format)
103{
104 std::unique_lock<decltype(mutex)> lock(mutex);
105 if (!egl_native_window_)
106 {
107 egl_native_window_pixel_format = pixel_format;
108 buffer_depository = std::make_unique<NewBufferSemantics>(
109 native_buffer_factory,
110 mir_buffer_factory,
111 std::make_shared<Requests>(server, stream_id),
112 map,
113 size,
114 pixel_format,
115 mir_buffer_usage_hardware,
116 nbuffers);
117
118 egl_native_window_ = client_platform->create_egl_native_window(this);
119 }
120
121 return static_cast<EGLNativeWindowType>(egl_native_window_.get());
122}
123
124//////////////////////////////
125// EGLNativeSurface interface
126//////////////////////////////
127
128namespace
129{
130 const char * const egl_mode_error = "Chain cannot be used in EGL mode";
131}
132
133MirSurfaceParameters mcl::PresentationChain::get_parameters() const
134{
135 std::unique_lock<decltype(mutex)> lock(mutex);
136
137 if (!buffer_depository)
138 BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
139
140 auto size = buffer_depository->size();
141
142 return MirSurfaceParameters{
143 "",
144 size.width.as_int(),
145 size.height.as_int(),
146 egl_native_window_pixel_format,
147 mir_buffer_usage_hardware,
148 mir_display_output_id_invalid};
149}
150
151std::shared_ptr<mcl::ClientBuffer> mcl::PresentationChain::get_current_buffer()
152{
153 {
154 std::unique_lock<decltype(mutex)> lock(mutex);
155 if (!buffer_depository)
156 BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
157 }
158 return buffer_depository->current_buffer();
159}
160
161void mcl::PresentationChain::request_and_wait_for_next_buffer()
162{
163 {
164 std::unique_lock<decltype(mutex)> lock(mutex);
165 if (!buffer_depository)
166 BOOST_THROW_EXCEPTION(std::runtime_error(egl_mode_error));
167 }
168 buffer_depository->submit([](){}, egl_native_window_pixel_format, 0)->wait_for_all();
169}
170
171void mcl::PresentationChain::request_and_wait_for_configure(MirSurfaceAttrib /*a*/, int /*value*/)
172{
173 //TODO: implement this function
174}
175
176void mcl::PresentationChain::set_buffer_cache_size(unsigned int)
177{
178 //TODO: implement this function
179}
87180
=== modified file 'src/client/presentation_chain.h'
--- src/client/presentation_chain.h 2016-06-02 05:33:50 +0000
+++ src/client/presentation_chain.h 2016-06-03 01:46:54 +0000
@@ -22,8 +22,10 @@
22#include "mir_presentation_chain.h"22#include "mir_presentation_chain.h"
23#include "mir/geometry/size.h"23#include "mir/geometry/size.h"
24#include "mir_toolkit/mir_presentation_chain.h"24#include "mir_toolkit/mir_presentation_chain.h"
25#include "mir/egl_native_surface.h"
25#include "mir_protobuf.pb.h"26#include "mir_protobuf.pb.h"
26#include "buffer.h"27#include "buffer.h"
28#include "server_buffer_semantics.h"
27#include <mutex>29#include <mutex>
28#include <memory>30#include <memory>
2931
@@ -34,34 +36,59 @@
34class ClientBufferFactory;36class ClientBufferFactory;
35class ClientBuffer;37class ClientBuffer;
36class AsyncBufferFactory;38class AsyncBufferFactory;
39class ClientPlatform;
40class SurfaceMap;
41
37namespace rpc42namespace rpc
38{43{
39class DisplayServer;44class DisplayServer;
40}45}
4146
42class PresentationChain : public MirPresentationChain47class PresentationChain : public MirPresentationChain, public EGLNativeSurface
43{48{
44public:49public:
45 PresentationChain(50 PresentationChain(
46 MirConnection* connection,51 MirConnection* connection,
47 int rpc_id,52 int rpc_id,
48 rpc::DisplayServer& server,53 rpc::DisplayServer& server,
54 std::shared_ptr<ClientPlatform> const& client_platform,
49 std::shared_ptr<ClientBufferFactory> const& native_buffer_factory,55 std::shared_ptr<ClientBufferFactory> const& native_buffer_factory,
50 std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory);56 std::shared_ptr<AsyncBufferFactory> const& mir_buffer_factory,
57 std::weak_ptr<SurfaceMap> const& map,
58 size_t nbuffers);
59
51 void submit_buffer(MirBuffer* buffer) override;60 void submit_buffer(MirBuffer* buffer) override;
52 MirConnection* connection() const override;61 MirConnection* connection() const override;
53 int rpc_id() const override;62 int rpc_id() const override;
54 char const* error_msg() const override;63 char const* error_msg() const override;
64 EGLNativeWindowType egl_native_window(mir::geometry::Size size, MirPixelFormat pixel_format) override;
65
66 // EGLNativeSurface interface
67 std::shared_ptr<ClientBuffer> get_current_buffer() override;
68 MirSurfaceParameters get_parameters() const override;
69 void request_and_wait_for_next_buffer() override;
70 void request_and_wait_for_configure(MirSurfaceAttrib a, int value) override;
71 void set_buffer_cache_size(unsigned int) override;
72
73protected:
74 PresentationChain(PresentationChain const&) = delete;
75 PresentationChain& operator=(PresentationChain const&) = delete;
76
55private:77private:
56
57 MirConnection* const connection_;78 MirConnection* const connection_;
58 int const stream_id;79 int const stream_id;
59 rpc::DisplayServer& server;80 rpc::DisplayServer& server;
81 std::shared_ptr<ClientPlatform> const client_platform;
60 std::shared_ptr<ClientBufferFactory> const native_buffer_factory;82 std::shared_ptr<ClientBufferFactory> const native_buffer_factory;
61 std::shared_ptr<AsyncBufferFactory> const mir_buffer_factory;83 std::shared_ptr<AsyncBufferFactory> const mir_buffer_factory;
84 std::shared_ptr<void> egl_native_window_;
85 std::weak_ptr<SurfaceMap> const map;
86 size_t nbuffers;
6287
63 std::mutex mutex;88 mutable std::mutex mutex;
64 std::vector<std::unique_ptr<Buffer>> buffers;89 std::vector<std::unique_ptr<Buffer>> buffers;
90 std::unique_ptr<ServerBufferSemantics> buffer_depository;
91 MirPixelFormat egl_native_window_pixel_format;
65};92};
66}93}
67}94}
6895
=== added file 'src/client/server_buffer_semantics.h'
--- src/client/server_buffer_semantics.h 1970-01-01 00:00:00 +0000
+++ src/client/server_buffer_semantics.h 2016-06-03 01:46:54 +0000
@@ -0,0 +1,59 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 3 as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#ifndef MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H
20#define MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H
21
22#include "mir/optional_value.h"
23#include "mir/frontend/buffer_stream_id.h"
24#include "mir/geometry/size.h"
25#include "mir_toolkit/common.h"
26#include "mir/client_buffer.h"
27#include "mir_protobuf.pb.h"
28
29#include <memory>
30
31namespace mir
32{
33namespace client
34{
35
36//An internal interface useful in transitioning buffer exchange semantics based on
37//the BufferStream response provided by the server
38struct ServerBufferSemantics
39{
40 virtual void deposit(protobuf::Buffer const&, optional_value<geometry::Size>, MirPixelFormat) = 0;
41 virtual void set_buffer_cache_size(unsigned int) = 0;
42 virtual std::shared_ptr<ClientBuffer> current_buffer() = 0;
43 virtual uint32_t current_buffer_id() = 0;
44 virtual MirWaitHandle* submit(std::function<void()> const&, MirPixelFormat, int stream_id) = 0;
45 virtual void lost_connection() = 0;
46 virtual void set_size(geometry::Size) = 0;
47 virtual MirWaitHandle* set_scale(float, frontend::BufferStreamId) = 0;
48 virtual void set_interval(int interval) = 0;
49 virtual geometry::Size size() const = 0;
50 virtual ~ServerBufferSemantics() = default;
51 ServerBufferSemantics() = default;
52 ServerBufferSemantics(ServerBufferSemantics const&) = delete;
53 ServerBufferSemantics& operator=(ServerBufferSemantics const&) = delete;
54};
55
56}
57}
58
59#endif /* MIR_CLIENT_SERVER_BUFFER_SEMANTICS_H */
060
=== modified file 'src/client/symbols.map'
--- src/client/symbols.map 2016-06-02 05:33:50 +0000
+++ src/client/symbols.map 2016-06-03 01:46:54 +0000
@@ -370,6 +370,7 @@
370 mir_connection_create_presentation_chain_sync;370 mir_connection_create_presentation_chain_sync;
371 mir_presentation_chain_is_valid;371 mir_presentation_chain_is_valid;
372 mir_presentation_chain_get_error_message;372 mir_presentation_chain_get_error_message;
373 mir_create_egl_native_window;
373 mir_connection_create_presentation_chain;374 mir_connection_create_presentation_chain;
374 mir_connection_allocate_buffer;375 mir_connection_allocate_buffer;
375 mir_presentation_chain_submit_buffer;376 mir_presentation_chain_submit_buffer;
376377
=== modified file 'src/include/client/mir_toolkit/mir_presentation_chain.h'
--- src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-02 05:33:50 +0000
+++ src/include/client/mir_toolkit/mir_presentation_chain.h 2016-06-03 01:46:54 +0000
@@ -29,6 +29,23 @@
29#endif29#endif
3030
31/**31/**
32 * Extract an MirEGLNativeWindowType object from a given presentation chain.
33 * MirEGLNativeWindowType object that can be used in eglCreateWindowSurface()
34 * as native window. After this function is called, buffer management
35 * (allocation/deallocation/submission) of this presentation chain is done
36 * internally - clients should refrain from managing their buffers.
37 *
38 * \param [in] presentation_chain The presentation chain
39 * \param [in] width Native window width
40 * \param [in] height Native window height
41 * \param [in] pixel format Pixel format of native window
42 * \return MirEGLNativeWindowType object that can be used
43 * in eglCreateWindowSurface() as native window.
44 */
45MirEGLNativeWindowType mir_create_egl_native_window(
46 MirPresentationChain* presentation_chain, int width, int height, MirPixelFormat pixel_format);
47
48/**
32 * Test for a valid presentation chain49 * Test for a valid presentation chain
33 *50 *
34 * \param [in] presentation_chain The presentation chain51 * \param [in] presentation_chain The presentation chain
3552
=== added file 'tests/unit-tests/client/stub_client_platform.h'
--- tests/unit-tests/client/stub_client_platform.h 1970-01-01 00:00:00 +0000
+++ tests/unit-tests/client/stub_client_platform.h 2016-06-03 01:46:54 +0000
@@ -0,0 +1,79 @@
1/*
2 * Copyright © 2016 Canonical Ltd.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License version 3,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authored by: Kevin DuBois <kevin.dubois@canonical.com>
17 */
18
19#ifndef STUB_CLIENT_PLATFORM_H_
20#define STUB_CLIENT_PLATFORM_H_
21
22#include "mir/client_platform.h"
23
24namespace
25{
26
27struct StubClientPlatform : public mir::client::ClientPlatform
28{
29 StubClientPlatform(
30 std::shared_ptr<mir::client::ClientBufferFactory> const& bf)
31 : buffer_factory(bf)
32 {
33 }
34
35 MirPlatformType platform_type() const override
36 {
37 return MirPlatformType();
38 }
39
40 void populate(MirPlatformPackage& /* package */) const override
41 {
42 }
43
44 std::shared_ptr<void> create_egl_native_window(mir::client::EGLNativeSurface * /* surface */) override
45 {
46 return mir::test::fake_shared(egl_native_window);
47 }
48
49 std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override
50 {
51 return nullptr;
52 }
53
54 MirNativeBuffer* convert_native_buffer(mir::graphics::NativeBuffer*) const override
55 {
56 return nullptr;
57 }
58
59 std::shared_ptr<mir::client::ClientBufferFactory> create_buffer_factory() override
60 {
61 return buffer_factory;
62 }
63
64 MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */)
65 {
66 return nullptr;
67 }
68
69 MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override
70 {
71 return mir_pixel_format_invalid;
72 }
73
74 static EGLNativeWindowType egl_native_window;
75 std::shared_ptr<mir::client::ClientBufferFactory> const buffer_factory;
76};
77
78}
79#endif /* STUB_CLIENT_PLATFORM_H_ */
080
=== modified file 'tests/unit-tests/client/test_client_buffer_stream.cpp'
--- tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000
+++ tests/unit-tests/client/test_client_buffer_stream.cpp 2016-06-03 01:46:54 +0000
@@ -35,6 +35,8 @@
3535
36#include "mir_toolkit/mir_client_library.h"36#include "mir_toolkit/mir_client_library.h"
3737
38#include "stub_client_platform.h"
39
38#include <future>40#include <future>
39#include <atomic>41#include <atomic>
4042
@@ -57,49 +59,6 @@
57 arg1->set_error(message);59 arg1->set_error(message);
58}60}
5961
60struct StubClientPlatform : public mcl::ClientPlatform
61{
62 StubClientPlatform(
63 std::shared_ptr<mcl::ClientBufferFactory> const& bf)
64 : buffer_factory(bf)
65 {
66 }
67 MirPlatformType platform_type() const override
68 {
69 return MirPlatformType();
70 }
71 void populate(MirPlatformPackage& /* package */) const override
72 {
73 }
74 std::shared_ptr<void> create_egl_native_window(mcl::EGLNativeSurface * /* surface */) override
75 {
76 return mt::fake_shared(egl_native_window);
77 }
78 std::shared_ptr<EGLNativeDisplayType> create_egl_native_display() override
79 {
80 return nullptr;
81 }
82 MirNativeBuffer* convert_native_buffer(mg::NativeBuffer*) const override
83 {
84 return nullptr;
85 }
86
87 std::shared_ptr<mcl::ClientBufferFactory> create_buffer_factory() override
88 {
89 return buffer_factory;
90 }
91 MirPlatformMessage* platform_operation(MirPlatformMessage const* /* request */)
92 {
93 return nullptr;
94 }
95 MirPixelFormat get_egl_pixel_format(EGLDisplay, EGLConfig) const override
96 {
97 return mir_pixel_format_invalid;
98 }
99 static EGLNativeWindowType egl_native_window;
100 std::shared_ptr<mcl::ClientBufferFactory> const buffer_factory;
101};
102
103struct MockPerfReport : public mcl::PerfReport62struct MockPerfReport : public mcl::PerfReport
104{63{
105 MOCK_METHOD1(name_surface, void(char const*));64 MOCK_METHOD1(name_surface, void(char const*));
10665
=== modified file 'tests/unit-tests/client/test_connection_resource_map.cpp'
--- tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-02 05:33:50 +0000
+++ tests/unit-tests/client/test_connection_resource_map.cpp 2016-06-03 01:46:54 +0000
@@ -42,7 +42,7 @@
42 std::make_shared<mcl::Buffer>(buffer_cb, nullptr, 0, nullptr, nullptr, mir_buffer_usage_software) };42 std::make_shared<mcl::Buffer>(buffer_cb, nullptr, 0, nullptr, nullptr, mir_buffer_usage_software) };
43 mtd::MockProtobufServer mock_server;43 mtd::MockProtobufServer mock_server;
44 std::shared_ptr<mcl::PresentationChain> chain{ std::make_shared<mcl::PresentationChain>(44 std::shared_ptr<mcl::PresentationChain> chain{ std::make_shared<mcl::PresentationChain>(
45 nullptr, 0, mock_server, nullptr, nullptr) };45 nullptr, 0, mock_server, nullptr, nullptr, nullptr, std::shared_ptr<mcl::SurfaceMap>(nullptr), 0) };
4646
47 mf::SurfaceId const surface_id{43};47 mf::SurfaceId const surface_id{43};
48 mf::BufferStreamId const stream_id{43};48 mf::BufferStreamId const stream_id{43};
4949
=== modified file 'tests/unit-tests/client/test_presentation_chain.cpp'
--- tests/unit-tests/client/test_presentation_chain.cpp 2016-06-02 05:33:50 +0000
+++ tests/unit-tests/client/test_presentation_chain.cpp 2016-06-03 01:46:54 +0000
@@ -21,13 +21,18 @@
21#include "mir/test/doubles/mock_client_buffer.h"21#include "mir/test/doubles/mock_client_buffer.h"
22#include "mir/test/fake_shared.h"22#include "mir/test/fake_shared.h"
23#include "src/client/presentation_chain.h"23#include "src/client/presentation_chain.h"
24#include "src/client/connection_surface_map.h"
24#include "src/client/buffer_factory.h"25#include "src/client/buffer_factory.h"
25#include "mir/client_buffer_factory.h"26#include "mir/client_buffer_factory.h"
27#include "stub_client_platform.h"
2628
27#include <mutex>29#include <mutex>
28#include <condition_variable>30#include <condition_variable>
29#include <gtest/gtest.h>31#include <gtest/gtest.h>
32
30using namespace testing;33using namespace testing;
34
35namespace mt = mir::test;
31namespace mtd = mir::test::doubles;36namespace mtd = mir::test::doubles;
32namespace geom = mir::geometry;37namespace geom = mir::geometry;
33namespace mcl = mir::client;38namespace mcl = mir::client;
@@ -50,11 +55,15 @@
50 geom::Size size {100, 200};55 geom::Size size {100, 200};
51 MirPixelFormat format = mir_pixel_format_abgr_8888;56 MirPixelFormat format = mir_pixel_format_abgr_8888;
52 MirBufferUsage usage = mir_buffer_usage_software;57 MirBufferUsage usage = mir_buffer_usage_software;
53 mtd::MockProtobufServer mock_server;58 NiceMock<mtd::MockProtobufServer> mock_server;
54 int buffer_id {4312};59 int buffer_id {4312};
55 mp::Buffer ipc_buf;60 mp::Buffer ipc_buf;
56 std::shared_ptr<mtd::StubClientBuffer> client_buffer = std::make_shared<mtd::StubClientBuffer>(61 std::shared_ptr<mtd::StubClientBuffer> client_buffer = std::make_shared<mtd::StubClientBuffer>(
57 std::make_shared<MirBufferPackage>(), size, format);62 std::make_shared<MirBufferPackage>(), size, format);
63 std::shared_ptr<mcl::ConnectionSurfaceMap> map{std::make_shared<mcl::ConnectionSurfaceMap>()};
64 mtd::StubClientBufferFactory stub_factory;
65 std::shared_ptr<mcl::BufferFactory> factory{std::make_shared<mcl::BufferFactory>()};
66 size_t nbuffers{3};
58};67};
5968
60MATCHER_P(BufferRequestMatches, val, "")69MATCHER_P(BufferRequestMatches, val, "")
@@ -65,6 +74,9 @@
65 arg->buffer().buffer_id() == val.buffer().buffer_id());74 arg->buffer().buffer_id() == val.buffer().buffer_id());
66}75}
6776
77EGLNativeWindowType StubClientPlatform::egl_native_window{
78 reinterpret_cast<EGLNativeWindowType>(&StubClientPlatform::egl_native_window)};
79
68void buffer_callback(MirBuffer*, void*)80void buffer_callback(MirBuffer*, void*)
69{81{
70}82}
@@ -75,8 +87,11 @@
75{87{
76 mcl::PresentationChain chain(88 mcl::PresentationChain chain(
77 connection, rpc_id, mock_server,89 connection, rpc_id, mock_server,
90 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
78 std::make_shared<mtd::StubClientBufferFactory>(),91 std::make_shared<mtd::StubClientBufferFactory>(),
79 std::make_shared<mcl::BufferFactory>());92 factory,
93 map,
94 nbuffers);
80 EXPECT_THAT(chain.connection(), Eq(connection));95 EXPECT_THAT(chain.connection(), Eq(connection));
81}96}
8297
@@ -84,8 +99,11 @@
84{99{
85 mcl::PresentationChain chain(100 mcl::PresentationChain chain(
86 connection, rpc_id, mock_server,101 connection, rpc_id, mock_server,
102 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
87 std::make_shared<mtd::StubClientBufferFactory>(),103 std::make_shared<mtd::StubClientBufferFactory>(),
88 std::make_shared<mcl::BufferFactory>());104 factory,
105 map,
106 nbuffers);
89 EXPECT_THAT(chain.rpc_id(), Eq(rpc_id));107 EXPECT_THAT(chain.rpc_id(), Eq(rpc_id));
90}108}
91109
@@ -101,8 +119,11 @@
101 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);119 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
102 mcl::PresentationChain chain(120 mcl::PresentationChain chain(
103 connection, rpc_id, mock_server,121 connection, rpc_id, mock_server,
122 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
104 std::make_shared<mtd::StubClientBufferFactory>(),123 std::make_shared<mtd::StubClientBufferFactory>(),
105 std::make_shared<mcl::BufferFactory>());124 factory,
125 map,
126 nbuffers);
106127
107 buffer.received();128 buffer.received();
108 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));129 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
@@ -116,8 +137,11 @@
116 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);137 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
117 mcl::PresentationChain chain(138 mcl::PresentationChain chain(
118 connection, rpc_id, mock_server,139 connection, rpc_id, mock_server,
140 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
119 std::make_shared<mtd::StubClientBufferFactory>(),141 std::make_shared<mtd::StubClientBufferFactory>(),
120 std::make_shared<mcl::BufferFactory>());142 factory,
143 map,
144 nbuffers);
121145
122 buffer.received();146 buffer.received();
123 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));147 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
@@ -126,3 +150,81 @@
126 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));150 chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer));
127 }, std::logic_error);151 }, std::logic_error);
128}152}
153
154TEST_F(PresentationChain, gets_egl_native_window)
155{
156 int const width = 73;
157 int const height = 32;
158 MirPixelFormat const format = mir_pixel_format_argb_8888;
159
160 mcl::PresentationChain chain(
161 connection, rpc_id, mock_server,
162 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
163 std::make_shared<mtd::StubClientBufferFactory>(),
164 factory,
165 map,
166 nbuffers);
167
168 EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format));
169}
170
171TEST_F(PresentationChain, returns_correct_parameters)
172{
173 int const width = 73;
174 int const height = 32;
175 MirPixelFormat const format = mir_pixel_format_argb_8888;
176 MirBufferUsage const usage = mir_buffer_usage_hardware;
177 MirSurfaceParameters params;
178
179 mcl::PresentationChain chain(
180 connection, rpc_id, mock_server,
181 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
182 std::make_shared<mtd::StubClientBufferFactory>(),
183 factory,
184 map,
185 nbuffers);
186 chain.egl_native_window(geom::Size{width, height}, format);
187
188 EXPECT_NO_THROW(params = chain.get_parameters());
189
190 EXPECT_STREQ("", params.name);
191 EXPECT_EQ(width, params.width);
192 EXPECT_EQ(height, params.height);
193 EXPECT_EQ(format, params.pixel_format);
194 EXPECT_EQ(usage, params.buffer_usage);
195}
196
197TEST_F(PresentationChain, EGLNativeSurface_functions_throw_when_egl_native_window_not_called)
198{
199 mcl::PresentationChain chain(
200 connection, rpc_id, mock_server,
201 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
202 std::make_shared<mtd::StubClientBufferFactory>(),
203 factory,
204 map,
205 nbuffers);
206
207 ASSERT_THROW(chain.get_parameters(), std::runtime_error);
208}
209
210TEST_F(PresentationChain, submission_throws_in_EGL_mode)
211{
212 int const width = 73;
213 int const height = 32;
214 MirPixelFormat const format = mir_pixel_format_argb_8888;
215
216 mcl::PresentationChain chain(
217 connection, rpc_id, mock_server,
218 std::make_shared<StubClientPlatform>(mt::fake_shared(stub_factory)),
219 std::make_shared<mtd::StubClientBufferFactory>(),
220 factory,
221 map,
222 nbuffers);
223
224 EXPECT_EQ(StubClientPlatform::egl_native_window, chain.egl_native_window(geom::Size{width, height}, format));
225
226 mcl::Buffer buffer(buffer_callback, nullptr, buffer_id, client_buffer, nullptr, mir_buffer_usage_software);
227 buffer.received();
228
229 ASSERT_THROW(chain.submit_buffer(reinterpret_cast<MirBuffer*>(&buffer)), std::runtime_error);
230}

Subscribers

People subscribed via source and target branches