1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h"
6 
7 #include "gpu/command_buffer/common/gles2_cmd_format.h"
8 #include "gpu/command_buffer/service/gl_surface_mock.h"
9 #include "testing/gtest/include/gtest/gtest.h"
10 #include "ui/gl/gl_mock.h"
11 
12 using ::testing::_;
13 using ::testing::InSequence;
14 using ::testing::Pointee;
15 using ::testing::Return;
16 using ::testing::SetArgPointee;
17 
18 namespace gpu {
19 namespace gles2 {
20 
21 class GLES2DecoderDrawOOMTest : public GLES2DecoderManualInitTest {
22  protected:
Init(bool has_robustness)23   void Init(bool has_robustness) {
24     InitState init;
25     init.lose_context_when_out_of_memory = true;
26     if (has_robustness)
27       init.extensions = "GL_ARB_robustness";
28     InitDecoder(init);
29     SetupDefaultProgram();
30   }
31 
Draw(GLenum reset_status,error::ContextLostReason expected_other_reason)32   void Draw(GLenum reset_status,
33             error::ContextLostReason expected_other_reason) {
34     const GLsizei kFakeLargeCount = 0x1234;
35     SetupTexture();
36     if (context_->HasRobustness()) {
37       EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
38           .WillOnce(Return(reset_status));
39     }
40     AddExpectationsForSimulatedAttrib0WithError(kFakeLargeCount, 0,
41                                                 GL_OUT_OF_MEMORY);
42     EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation();
43     // Other contexts in the group should be lost also.
44     EXPECT_CALL(*mock_decoder_, MarkContextLost(expected_other_reason))
45         .Times(1)
46         .RetiresOnSaturation();
47     cmds::DrawArrays cmd;
48     cmd.Init(GL_TRIANGLES, 0, kFakeLargeCount);
49     EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd));
50   }
51 };
52 
53 // Test that we lose context.
TEST_P(GLES2DecoderDrawOOMTest,ContextLostReasonOOM)54 TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonOOM) {
55   Init(false);  // without robustness
56   const error::ContextLostReason expected_reason_for_other_contexts =
57       error::kOutOfMemory;
58   Draw(GL_NO_ERROR, expected_reason_for_other_contexts);
59   EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
60   EXPECT_TRUE(decoder_->WasContextLost());
61   EXPECT_EQ(error::kOutOfMemory, GetContextLostReason());
62 }
63 
TEST_P(GLES2DecoderDrawOOMTest,ContextLostReasonWhenStatusIsNoError)64 TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsNoError) {
65   Init(true);  // with robustness
66   // If the reset status is NO_ERROR, we should be signaling kOutOfMemory.
67   const error::ContextLostReason expected_reason_for_other_contexts =
68       error::kOutOfMemory;
69   Draw(GL_NO_ERROR, expected_reason_for_other_contexts);
70   EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
71   EXPECT_TRUE(decoder_->WasContextLost());
72   EXPECT_EQ(error::kOutOfMemory, GetContextLostReason());
73 }
74 
TEST_P(GLES2DecoderDrawOOMTest,ContextLostReasonWhenStatusIsGuilty)75 TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsGuilty) {
76   Init(true);
77   // If there was a reset, it should override kOutOfMemory.
78   const error::ContextLostReason expected_reason_for_other_contexts =
79       error::kUnknown;
80   Draw(GL_GUILTY_CONTEXT_RESET_ARB, expected_reason_for_other_contexts);
81   EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
82   EXPECT_TRUE(decoder_->WasContextLost());
83   EXPECT_EQ(error::kGuilty, GetContextLostReason());
84 }
85 
TEST_P(GLES2DecoderDrawOOMTest,ContextLostReasonWhenStatusIsUnknown)86 TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsUnknown) {
87   Init(true);
88   // If there was a reset, it should override kOutOfMemory.
89   const error::ContextLostReason expected_reason_for_other_contexts =
90       error::kUnknown;
91   Draw(GL_UNKNOWN_CONTEXT_RESET_ARB, expected_reason_for_other_contexts);
92   EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError());
93   EXPECT_TRUE(decoder_->WasContextLost());
94   EXPECT_EQ(error::kUnknown, GetContextLostReason());
95 }
96 
97 INSTANTIATE_TEST_SUITE_P(Service, GLES2DecoderDrawOOMTest, ::testing::Bool());
98 
99 class GLES2DecoderLostContextTest : public GLES2DecoderManualInitTest {
100  protected:
Init(bool has_robustness)101   void Init(bool has_robustness) {
102     InitState init;
103     init.gl_version = "OpenGL ES 2.0";
104     if (has_robustness)
105       init.extensions = "GL_KHR_robustness";
106     InitDecoder(init);
107   }
108 
DoGetErrorWithContextLost(GLenum reset_status)109   void DoGetErrorWithContextLost(GLenum reset_status) {
110     DCHECK(context_->HasExtension("GL_KHR_robustness"));
111     EXPECT_CALL(*gl_, GetError())
112         .WillOnce(Return(GL_CONTEXT_LOST_KHR))
113         .RetiresOnSaturation();
114     EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
115         .WillOnce(Return(reset_status));
116     cmds::GetError cmd;
117     cmd.Init(shared_memory_id_, shared_memory_offset_);
118     EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd));
119     EXPECT_EQ(static_cast<GLuint>(GL_NO_ERROR), *GetSharedMemoryAs<GLenum*>());
120   }
121 
ClearCurrentDecoderError()122   void ClearCurrentDecoderError() {
123     DCHECK(decoder_->WasContextLost());
124     EXPECT_CALL(*gl_, GetError())
125         .WillOnce(Return(GL_CONTEXT_LOST_KHR))
126         .RetiresOnSaturation();
127     cmds::GetError cmd;
128     cmd.Init(shared_memory_id_, shared_memory_offset_);
129     EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd));
130   }
131 };
132 
TEST_P(GLES2DecoderLostContextTest,LostFromMakeCurrent)133 TEST_P(GLES2DecoderLostContextTest, LostFromMakeCurrent) {
134   Init(false);  // without robustness
135   EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false));
136   // Expect the group to be lost.
137   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)).Times(1);
138   decoder_->MakeCurrent();
139   EXPECT_TRUE(decoder_->WasContextLost());
140   EXPECT_EQ(error::kMakeCurrentFailed, GetContextLostReason());
141 
142   // We didn't process commands, so we need to clear the decoder error,
143   // so that we can shut down cleanly.
144   ClearCurrentDecoderError();
145 }
146 
TEST_P(GLES2DecoderLostContextTest,LostFromMakeCurrentWithRobustness)147 TEST_P(GLES2DecoderLostContextTest, LostFromMakeCurrentWithRobustness) {
148   Init(true);  // with robustness
149   // If we can't make the context current, we cannot query the robustness
150   // extension.
151   EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()).Times(0);
152   EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false));
153   // Expect the group to be lost.
154   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)).Times(1);
155   decoder_->MakeCurrent();
156   EXPECT_TRUE(decoder_->WasContextLost());
157   EXPECT_FALSE(decoder_->WasContextLostByRobustnessExtension());
158   EXPECT_EQ(error::kMakeCurrentFailed, GetContextLostReason());
159 
160   // We didn't process commands, so we need to clear the decoder error,
161   // so that we can shut down cleanly.
162   ClearCurrentDecoderError();
163 }
164 
TEST_P(GLES2DecoderLostContextTest,TextureDestroyAfterLostFromMakeCurrent)165 TEST_P(GLES2DecoderLostContextTest, TextureDestroyAfterLostFromMakeCurrent) {
166   Init(true);
167   // Create a texture and framebuffer, and attach the texture to the
168   // framebuffer.
169   const GLuint kClientTextureId = 4100;
170   const GLuint kServiceTextureId = 4101;
171   EXPECT_CALL(*gl_, GenTextures(_, _))
172       .WillOnce(SetArgPointee<1>(kServiceTextureId))
173       .RetiresOnSaturation();
174   GenHelper<cmds::GenTexturesImmediate>(kClientTextureId);
175   DoBindTexture(GL_TEXTURE_2D, kClientTextureId, kServiceTextureId);
176   DoTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 5, 6, 0, GL_RGBA, GL_UNSIGNED_BYTE,
177                shared_memory_id_, kSharedMemoryOffset);
178   DoBindFramebuffer(GL_FRAMEBUFFER, client_framebuffer_id_,
179                     kServiceFramebufferId);
180   DoFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
181                          kClientTextureId, kServiceTextureId, 0, GL_NO_ERROR);
182 
183   // The texture should never be deleted at the GL level.
184   EXPECT_CALL(*gl_, DeleteTextures(1, Pointee(kServiceTextureId)))
185       .Times(0)
186       .RetiresOnSaturation();
187 
188   DoBindFramebuffer(GL_FRAMEBUFFER, 0, 0);
189   EXPECT_CALL(*gl_, BindTexture(_, 0)).Times(testing::AnyNumber());
190   GenHelper<cmds::DeleteTexturesImmediate>(kClientTextureId);
191 
192   // Force context lost for MakeCurrent().
193   EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false));
194   // Expect the group to be lost.
195   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)).Times(1);
196 
197   decoder_->MakeCurrent();
198   EXPECT_TRUE(decoder_->WasContextLost());
199   EXPECT_EQ(error::kMakeCurrentFailed, GetContextLostReason());
200   ClearCurrentDecoderError();
201 }
202 
TEST_P(GLES2DecoderLostContextTest,QueryDestroyAfterLostFromMakeCurrent)203 TEST_P(GLES2DecoderLostContextTest, QueryDestroyAfterLostFromMakeCurrent) {
204   InitState init;
205   init.extensions = "GL_EXT_occlusion_query_boolean GL_ARB_sync";
206   init.gl_version = "2.0";
207   init.has_alpha = true;
208   init.request_alpha = true;
209   init.bind_generates_resource = true;
210   InitDecoder(init);
211 
212   const GLsync kGlSync = reinterpret_cast<GLsync>(0xdeadbeef);
213   GenHelper<cmds::GenQueriesEXTImmediate>(kNewClientId);
214 
215   cmds::BeginQueryEXT begin_cmd;
216   begin_cmd.Init(GL_COMMANDS_COMPLETED_CHROMIUM, kNewClientId,
217                  shared_memory_id_, kSharedMemoryOffset);
218   EXPECT_EQ(error::kNoError, ExecuteCmd(begin_cmd));
219   EXPECT_EQ(GL_NO_ERROR, GetGLError());
220 
221   QueryManager* query_manager = decoder_->GetQueryManager();
222   ASSERT_TRUE(query_manager != nullptr);
223   QueryManager::Query* query = query_manager->GetQuery(kNewClientId);
224   ASSERT_TRUE(query != nullptr);
225   EXPECT_FALSE(query->IsPending());
226 
227   EXPECT_CALL(*gl_, Flush()).RetiresOnSaturation();
228   EXPECT_CALL(*gl_, FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0))
229       .WillOnce(Return(kGlSync))
230       .RetiresOnSaturation();
231 #if DCHECK_IS_ON()
232   EXPECT_CALL(*gl_, IsSync(kGlSync))
233       .WillOnce(Return(GL_TRUE))
234       .RetiresOnSaturation();
235 #endif
236 
237   cmds::EndQueryEXT end_cmd;
238   end_cmd.Init(GL_COMMANDS_COMPLETED_CHROMIUM, 1);
239   EXPECT_EQ(error::kNoError, ExecuteCmd(end_cmd));
240   EXPECT_EQ(GL_NO_ERROR, GetGLError());
241 
242 #if DCHECK_IS_ON()
243   EXPECT_CALL(*gl_, IsSync(kGlSync)).Times(0).RetiresOnSaturation();
244 #endif
245   EXPECT_CALL(*gl_, DeleteSync(kGlSync)).Times(0).RetiresOnSaturation();
246 
247   // Force context lost for MakeCurrent().
248   EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false));
249   // Expect the group to be lost.
250   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)).Times(1);
251 
252   decoder_->MakeCurrent();
253   EXPECT_TRUE(decoder_->WasContextLost());
254   EXPECT_EQ(error::kMakeCurrentFailed, GetContextLostReason());
255   ClearCurrentDecoderError();
256   ResetDecoder();
257 }
258 
TEST_P(GLES2DecoderLostContextTest,LostFromResetAfterMakeCurrent)259 TEST_P(GLES2DecoderLostContextTest, LostFromResetAfterMakeCurrent) {
260   Init(true);  // with robustness
261   InSequence seq;
262   EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true));
263   EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
264       .WillOnce(Return(GL_GUILTY_CONTEXT_RESET_KHR));
265   // Expect the group to be lost.
266   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)).Times(1);
267   decoder_->MakeCurrent();
268   EXPECT_TRUE(decoder_->WasContextLost());
269   EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension());
270   EXPECT_EQ(error::kGuilty, GetContextLostReason());
271 
272   // We didn't process commands, so we need to clear the decoder error,
273   // so that we can shut down cleanly.
274   ClearCurrentDecoderError();
275 }
276 
TEST_P(GLES2DecoderLostContextTest,LoseGuiltyFromGLError)277 TEST_P(GLES2DecoderLostContextTest, LoseGuiltyFromGLError) {
278   Init(true);
279   // Always expect other contexts to be signaled as 'kUnknown' since we can't
280   // query their status without making them current.
281   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown))
282       .Times(1);
283   DoGetErrorWithContextLost(GL_GUILTY_CONTEXT_RESET_KHR);
284   EXPECT_TRUE(decoder_->WasContextLost());
285   EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension());
286   EXPECT_EQ(error::kGuilty, GetContextLostReason());
287 }
288 
TEST_P(GLES2DecoderLostContextTest,LoseInnocentFromGLError)289 TEST_P(GLES2DecoderLostContextTest, LoseInnocentFromGLError) {
290   Init(true);
291   // Always expect other contexts to be signaled as 'kUnknown' since we can't
292   // query their status without making them current.
293   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown))
294       .Times(1);
295   DoGetErrorWithContextLost(GL_INNOCENT_CONTEXT_RESET_KHR);
296   EXPECT_TRUE(decoder_->WasContextLost());
297   EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension());
298   EXPECT_EQ(error::kInnocent, GetContextLostReason());
299 }
300 
TEST_P(GLES2DecoderLostContextTest,LoseGroupFromRobustness)301 TEST_P(GLES2DecoderLostContextTest, LoseGroupFromRobustness) {
302   // If one context in a group is lost through robustness,
303   // the other ones should also get lost and query the reset status.
304   Init(true);
305   EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown))
306       .Times(1);
307   // There should be no GL calls, since we might not have a current context.
308   EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()).Times(0);
309   LoseContexts(error::kUnknown);
310   EXPECT_TRUE(decoder_->WasContextLost());
311   EXPECT_EQ(error::kUnknown, GetContextLostReason());
312 
313   // We didn't process commands, so we need to clear the decoder error,
314   // so that we can shut down cleanly.
315   ClearCurrentDecoderError();
316 }
317 
318 INSTANTIATE_TEST_SUITE_P(Service,
319                          GLES2DecoderLostContextTest,
320                          ::testing::Bool());
321 
322 }  // namespace gles2
323 }  // namespace gpu
324