Mir

Merge lp:~kdub/mir/snapshot-error-checking into lp:mir

Proposed by Kevin DuBois
Status: Work in progress
Proposed branch: lp:~kdub/mir/snapshot-error-checking
Merge into: lp:mir
Diff against target: 298 lines (+171/-12)
6 files modified
src/platform/graphics/android/buffer.cpp (+6/-2)
src/server/scene/gl_pixel_buffer.cpp (+31/-8)
src/server/scene/gl_pixel_buffer.h (+1/-1)
src/server/scene/threaded_snapshot_strategy.cpp (+7/-1)
tests/unit-tests/graphics/android/test_buffer_tex_bind.cpp (+19/-0)
tests/unit-tests/scene/test_gl_pixel_buffer.cpp (+107/-0)
To merge this branch: bzr merge lp:~kdub/mir/snapshot-error-checking
Reviewer Review Type Date Requested Status
PS Jenkins bot (community) continuous-integration Approve
Mir development team Pending
Review via email: mp+200595@code.launchpad.net

Commit message

provide the n7 relief from locking up (as in bug 1238695).

This is not a full fix to this problem, as it simply fails nonfatally instead of fatally when we hit the problem that the nexus7 cannot glFramebufferTexture2d with an eglImage (GL_OUT_OF_MEMORY is generated in glEGLTargetTexture2D)

Description of the change

provide the n7 relief from locking up (as in bug 1238695).

This is not a full fix to this problem, as it simply fails nonfatally instead of fatally when we hit the problem that the nexus7 cannot glFramebufferTexture2d with an eglImage (GL_OUT_OF_MEMORY is generated in glEGLTargetTexture2D)

tested with n4 (working as before) and n7 (no screenshots, but unity8 does not go down all the time)

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Unmerged revisions

1317. By Kevin DuBois

cleanup printf

1316. By Kevin DuBois

tests to pass

1315. By Kevin DuBois

more tests to check gl error codes more often

1314. By Kevin DuBois

test to check bad bind

1313. By Kevin DuBois

test to pass

1312. By Kevin DuBois

add a test to check the driver before taking a SS

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/platform/graphics/android/buffer.cpp'
2--- src/platform/graphics/android/buffer.cpp 2013-12-18 02:19:19 +0000
3+++ src/platform/graphics/android/buffer.cpp 2014-01-06 21:37:02 +0000
4@@ -96,7 +96,7 @@
5 native_buffer->anwb(), image_attrs);
6 if (image == EGL_NO_IMAGE_KHR)
7 {
8- BOOST_THROW_EXCEPTION(std::runtime_error("error binding buffer to texture\n"));
9+ BOOST_THROW_EXCEPTION(std::runtime_error("error creating EGLImage from buffer\n"));
10 }
11 egl_image_map[disp] = image;
12 }
13@@ -105,8 +105,12 @@
14 image = it->second;
15 }
16
17+ glGetError(); //clear error code before checking
18 egl_extensions->glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, image);
19-
20+ if(glGetError() != GL_NO_ERROR)
21+ {
22+ BOOST_THROW_EXCEPTION(std::runtime_error("error binding buffer to texture\n"));
23+ }
24 //TODO: we should make use of the android egl fence extension here to update the fence.
25 // if the extension is not available, we should pass out a token that the user
26 // will have to keep until the completion of the gl draw
27
28=== modified file 'src/server/scene/gl_pixel_buffer.cpp'
29--- src/server/scene/gl_pixel_buffer.cpp 2013-12-18 02:19:19 +0000
30+++ src/server/scene/gl_pixel_buffer.cpp 2014-01-06 21:37:02 +0000
31@@ -71,7 +71,19 @@
32 glDeleteFramebuffers(1, &fbo);
33 }
34
35-void ms::GLPixelBuffer::prepare()
36+void ms::GLPixelBuffer::handle_error()
37+{
38+ unsigned const int green_argb = 0xFF33FF33;
39+ pixels.resize(sizeof(unsigned int));
40+ size_ = geom::Size{1,1};
41+
42+ auto pix = reinterpret_cast<unsigned int*>(pixels.data());
43+ *pix = green_argb;
44+
45+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
46+}
47+
48+void ms::GLPixelBuffer::fill_from(graphics::Buffer& buffer)
49 {
50 gl_context->make_current();
51
52@@ -85,23 +97,34 @@
53 glGenFramebuffers(1, &fbo);
54
55 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
56-}
57
58-void ms::GLPixelBuffer::fill_from(graphics::Buffer& buffer)
59-{
60 auto width = buffer.size().width.as_uint32_t();
61 auto height = buffer.size().height.as_uint32_t();
62
63 pixels.resize(width * height * 4);
64
65- prepare();
66-
67- buffer.bind_to_texture();
68+ try
69+ {
70+ buffer.bind_to_texture();
71+ }
72+ catch (std::runtime_error& e)
73+ {
74+ handle_error();
75+ throw e;
76+ }
77
78 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0);
79
80+ if ((GL_FRAMEBUFFER_COMPLETE != glCheckFramebufferStatus(GL_FRAMEBUFFER)) ||
81+ (GL_NO_ERROR != glGetError()))
82+
83+ {
84+ handle_error();
85+ BOOST_THROW_EXCEPTION(std::runtime_error(
86+ "fbo is incomplete or not supported. cannot take snapshot"));
87+ }
88+
89 /* First try to get pixels as BGRA */
90- glGetError();
91 gl_pixel_format = GL_BGRA_EXT;
92 glReadPixels(0, 0, width, height, gl_pixel_format, GL_UNSIGNED_BYTE, pixels.data());
93
94
95=== modified file 'src/server/scene/gl_pixel_buffer.h'
96--- src/server/scene/gl_pixel_buffer.h 2013-12-18 02:19:19 +0000
97+++ src/server/scene/gl_pixel_buffer.h 2014-01-06 21:37:02 +0000
98@@ -49,7 +49,7 @@
99 geometry::Stride stride() const;
100
101 private:
102- void prepare();
103+ void handle_error();
104 void copy_and_convert_pixel_line(char* src, char* dst);
105
106 std::unique_ptr<graphics::GLContext> const gl_context;
107
108=== modified file 'src/server/scene/threaded_snapshot_strategy.cpp'
109--- src/server/scene/threaded_snapshot_strategy.cpp 2013-12-18 02:19:19 +0000
110+++ src/server/scene/threaded_snapshot_strategy.cpp 2014-01-06 21:37:02 +0000
111@@ -75,7 +75,13 @@
112 wi.surface_buffer_access->with_most_recent_buffer_do(
113 [this](graphics::Buffer& buffer)
114 {
115- pixels->fill_from(buffer);
116+ try
117+ {
118+ pixels->fill_from(buffer);
119+ } catch (...)
120+ {
121+ // todo: log or rethrow
122+ }
123 });
124
125
126
127=== modified file 'tests/unit-tests/graphics/android/test_buffer_tex_bind.cpp'
128--- tests/unit-tests/graphics/android/test_buffer_tex_bind.cpp 2013-12-18 02:19:19 +0000
129+++ tests/unit-tests/graphics/android/test_buffer_tex_bind.cpp 2014-01-06 21:37:02 +0000
130@@ -19,6 +19,7 @@
131 #include "src/platform/graphics/android/buffer.h"
132 #include "mir/graphics/egl_extensions.h"
133 #include "mir_test_doubles/mock_egl.h"
134+#include "mir_test_doubles/mock_gl.h"
135 #include "mir_test_doubles/mock_fence.h"
136 #include "mir_test_doubles/mock_android_native_buffer.h"
137
138@@ -48,6 +49,7 @@
139 MirPixelFormat pf;
140
141 testing::NiceMock<mtd::MockEGL> mock_egl;
142+ testing::NiceMock<mtd::MockGL> mock_gl;
143 std::shared_ptr<mg::EGLExtensions> extensions;
144 std::shared_ptr<mtd::MockAndroidNativeBuffer> mock_native_buffer;
145 };
146@@ -349,3 +351,20 @@
147 mga::Buffer buffer(mock_native_buffer, extensions);
148 buffer.bind_to_texture();
149 }
150+
151+
152+TEST_F(AndroidBufferBinding, error_code_is_checked_after_bind)
153+{
154+ using namespace testing;
155+
156+ EXPECT_CALL(mock_egl, glEGLImageTargetTexture2DOES(_, _))
157+ .Times(1);
158+ EXPECT_CALL(mock_gl, glGetError())
159+ .Times(2)
160+ .WillRepeatedly(Return(GL_OUT_OF_MEMORY));
161+
162+ mga::Buffer buffer(mock_native_buffer, extensions);
163+ EXPECT_THROW({
164+ buffer.bind_to_texture();
165+ }, std::runtime_error);
166+}
167
168=== modified file 'tests/unit-tests/scene/test_gl_pixel_buffer.cpp'
169--- tests/unit-tests/scene/test_gl_pixel_buffer.cpp 2013-12-20 05:06:28 +0000
170+++ tests/unit-tests/scene/test_gl_pixel_buffer.cpp 2014-01-06 21:37:02 +0000
171@@ -110,6 +110,107 @@
172 EXPECT_EQ(geom::Stride(), pixels.stride());
173 }
174
175+/* specifically, the tegra3 based N7 generates an out of memory error when binding to texture */
176+TEST_F(GLPixelBufferTest, abort_on_bad_texture_bind)
177+{
178+ using namespace testing;
179+ GLuint const tex{10};
180+ GLuint const fbo{20};
181+ {
182+ InSequence s;
183+
184+ /* The GL context is made current */
185+ EXPECT_CALL(mock_context, make_current());
186+
187+ /* The texture and framebuffer are prepared */
188+ EXPECT_CALL(mock_gl, glGenTextures(_,_))
189+ .WillOnce(SetArgPointee<1>(tex));
190+ EXPECT_CALL(mock_gl, glBindTexture(_,tex));
191+ EXPECT_CALL(mock_gl, glGenFramebuffers(_,_))
192+ .WillOnce(SetArgPointee<1>(fbo));
193+ EXPECT_CALL(mock_gl, glBindFramebuffer(_,fbo));
194+
195+ EXPECT_CALL(mock_buffer, bind_to_texture())
196+ .Times(1)
197+ .WillOnce(Throw(std::runtime_error("bad bind.\n")));
198+
199+ /* recover default FB */
200+ EXPECT_CALL(mock_gl, glBindFramebuffer(_,0));
201+
202+ /* do not call these if the bind was not okay */
203+ EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,_,_))
204+ .Times(0);
205+ EXPECT_CALL(mock_gl, glReadPixels(_,_,_,_,_,_,_))
206+ .Times(0);
207+ }
208+
209+ ms::GLPixelBuffer pixels{std::move(context)};
210+
211+ geom::Size bkp_size{1,1};
212+ geom::Stride bkp_stride{4};
213+ unsigned int pixel_color = 0xFF33FF33;
214+
215+ EXPECT_THROW({
216+ pixels.fill_from(mock_buffer);
217+ }, std::runtime_error);
218+ auto data = pixels.as_argb_8888();
219+
220+ EXPECT_EQ(bkp_size, pixels.size());
221+ EXPECT_EQ(bkp_stride, pixels.stride());
222+ ASSERT_NE(nullptr, data);
223+ EXPECT_EQ(pixel_color, static_cast<uint32_t const*>(data)[0]);
224+}
225+
226+TEST_F(GLPixelBufferTest, unable_to_bind_fb_results_in_dark_green_pixel)
227+{
228+ using namespace testing;
229+ GLuint const tex{10};
230+ GLuint const fbo{20};
231+ {
232+ InSequence s;
233+
234+ /* The GL context is made current */
235+ EXPECT_CALL(mock_context, make_current());
236+
237+ /* The texture and framebuffer are prepared */
238+ EXPECT_CALL(mock_gl, glGenTextures(_,_))
239+ .WillOnce(SetArgPointee<1>(tex));
240+ EXPECT_CALL(mock_gl, glBindTexture(_,tex));
241+ EXPECT_CALL(mock_gl, glGenFramebuffers(_,_))
242+ .WillOnce(SetArgPointee<1>(fbo));
243+ EXPECT_CALL(mock_gl, glBindFramebuffer(_,fbo));
244+ EXPECT_CALL(mock_buffer, bind_to_texture());
245+ EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,_,_));
246+ EXPECT_CALL(mock_gl, glCheckFramebufferStatus(GL_FRAMEBUFFER))
247+ .Times(1)
248+ .WillOnce(Return(GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT));
249+
250+ /* recover default FB */
251+ EXPECT_CALL(mock_gl, glBindFramebuffer(_,0));
252+
253+ /* do not try to read if the fbo status is not okay */
254+ EXPECT_CALL(mock_gl, glReadPixels(_,_,_,_,_,_,_))
255+ .Times(0);
256+ }
257+
258+ ms::GLPixelBuffer pixels{std::move(context)};
259+
260+ geom::Size bkp_size{1,1};
261+ geom::Stride bkp_stride{4};
262+ unsigned int pixel_color = 0xFF33FF33;
263+
264+ EXPECT_THROW({
265+ pixels.fill_from(mock_buffer);
266+ }, std::runtime_error);
267+ auto data = pixels.as_argb_8888();
268+
269+
270+ EXPECT_EQ(bkp_size, pixels.size());
271+ EXPECT_EQ(bkp_stride, pixels.stride());
272+ ASSERT_NE(nullptr, data);
273+ EXPECT_EQ(pixel_color, static_cast<uint32_t const*>(data)[0]);
274+}
275+
276 TEST_F(GLPixelBufferTest, returns_data_from_bgra_buffer_texture)
277 {
278 using namespace testing;
279@@ -135,6 +236,8 @@
280 /* The buffer texture is read as BGRA */
281 EXPECT_CALL(mock_buffer, bind_to_texture());
282 EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,tex,0));
283+ EXPECT_CALL(mock_gl, glCheckFramebufferStatus(GL_FRAMEBUFFER))
284+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE));
285 EXPECT_CALL(mock_gl, glReadPixels(0, 0, width, height,
286 GL_BGRA_EXT, GL_UNSIGNED_BYTE, _))
287 .WillOnce(FillPixels());
288@@ -184,6 +287,10 @@
289 /* Try to read the FBO as BGRA but fail */
290 EXPECT_CALL(mock_buffer, bind_to_texture());
291 EXPECT_CALL(mock_gl, glFramebufferTexture2D(_,_,_,tex,0));
292+ EXPECT_CALL(mock_gl, glCheckFramebufferStatus(GL_FRAMEBUFFER))
293+ .Times(1)
294+ .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE));
295+
296 EXPECT_CALL(mock_gl, glGetError())
297 .WillOnce(Return(GL_NO_ERROR));
298 EXPECT_CALL(mock_gl, glReadPixels(0, 0, width, height,

Subscribers

People subscribed via source and target branches