Chromium Code Reviews| Index: gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc |
| diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..3993f9196fbc7fb103e4e854eda3cbd42c3c0dbf |
| --- /dev/null |
| +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_context_lost.cc |
| @@ -0,0 +1,265 @@ |
| +// Copyright 2015 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "gpu/command_buffer/service/gles2_cmd_decoder.h" |
| + |
| +#include "base/command_line.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "gpu/command_buffer/common/gles2_cmd_format.h" |
| +#include "gpu/command_buffer/common/gles2_cmd_utils.h" |
| +#include "gpu/command_buffer/service/cmd_buffer_engine.h" |
| +#include "gpu/command_buffer/service/context_group.h" |
| +#include "gpu/command_buffer/service/gl_surface_mock.h" |
| +#include "gpu/command_buffer/service/gles2_cmd_decoder_unittest.h" |
| +#include "gpu/command_buffer/service/gpu_switches.h" |
| +#include "gpu/command_buffer/service/mocks.h" |
| +#include "testing/gtest/include/gtest/gtest.h" |
| +#include "ui/gl/gl_mock.h" |
| + |
| +using ::gfx::MockGLInterface; |
| +using ::testing::_; |
| +using ::testing::DoAll; |
| +using ::testing::InSequence; |
| +using ::testing::Invoke; |
| +using ::testing::MatcherCast; |
| +using ::testing::Mock; |
| +using ::testing::Pointee; |
| +using ::testing::Return; |
| +using ::testing::SaveArg; |
| +using ::testing::SetArrayArgument; |
| +using ::testing::SetArgumentPointee; |
| +using ::testing::SetArgPointee; |
| +using ::testing::StrEq; |
| +using ::testing::StrictMock; |
| + |
| +namespace gpu { |
| +namespace gles2 { |
| + |
| +using namespace cmds; |
| + |
| +class GLES2DecoderDrawOOMTest : public GLES2DecoderManualInitTest { |
| + protected: |
| + void Init(bool has_robustness) { |
| + InitState init; |
| + init.lose_context_when_out_of_memory = true; |
| + if (has_robustness) |
| + init.extensions = "GL_ARB_robustness"; |
| + InitDecoder(init); |
| + SetupDefaultProgram(); |
| + } |
| + |
| + void Draw(GLenum reset_status, |
| + error::ContextLostReason expected_other_reason) { |
| + const GLsizei kFakeLargeCount = 0x1234; |
| + SetupTexture(); |
| + if (context_->WasAllocatedUsingRobustnessExtension()) { |
| + EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()) |
| + .WillOnce(Return(reset_status)); |
| + } |
| + AddExpectationsForSimulatedAttrib0WithError(kFakeLargeCount, 0, |
| + GL_OUT_OF_MEMORY); |
| + EXPECT_CALL(*gl_, DrawArrays(_, _, _)).Times(0).RetiresOnSaturation(); |
| + // Other contexts in the group should be lost also. |
| + EXPECT_CALL(*mock_decoder_, MarkContextLost(expected_other_reason)) |
| + .Times(1) |
| + .RetiresOnSaturation(); |
| + DrawArrays cmd; |
| + cmd.Init(GL_TRIANGLES, 0, kFakeLargeCount); |
| + EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd)); |
| + } |
| +}; |
| + |
| +// Test that we lose context. |
| +TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonOOM) { |
| + Init(false); // without robustness |
| + const error::ContextLostReason expected_reason_for_other_contexts = |
| + error::kOutOfMemory; |
| + Draw(GL_NO_ERROR, expected_reason_for_other_contexts); |
| + EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kOutOfMemory, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsNoError) { |
| + Init(true); // with robustness |
| + // If the reset status is NO_ERROR, we should be signaling kOutOfMemory. |
| + const error::ContextLostReason expected_reason_for_other_contexts = |
| + error::kOutOfMemory; |
| + Draw(GL_NO_ERROR, expected_reason_for_other_contexts); |
| + EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kOutOfMemory, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsGuilty) { |
| + Init(true); |
| + // If there was a reset, it should override kOutOfMemory. |
| + const error::ContextLostReason expected_reason_for_other_contexts = |
| + error::kUnknown; |
| + Draw(GL_GUILTY_CONTEXT_RESET_ARB, expected_reason_for_other_contexts); |
| + EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kGuilty, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderDrawOOMTest, ContextLostReasonWhenStatusIsUnknown) { |
| + Init(true); |
| + // If there was a reset, it should override kOutOfMemory. |
| + const error::ContextLostReason expected_reason_for_other_contexts = |
| + error::kUnknown; |
| + Draw(GL_UNKNOWN_CONTEXT_RESET_ARB, expected_reason_for_other_contexts); |
| + EXPECT_EQ(GL_OUT_OF_MEMORY, GetGLError()); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kUnknown, decoder_->GetContextLostReason()); |
| +} |
| + |
| +INSTANTIATE_TEST_CASE_P(Service, GLES2DecoderDrawOOMTest, ::testing::Bool()); |
| + |
| +class GLES2DecoderLostContextTest : public GLES2DecoderManualInitTest { |
| + protected: |
| + void Init(bool has_robustness) { |
| + InitState init; |
| + if (has_robustness) |
| + init.extensions = "GL_ARB_robustness"; |
| + InitDecoder(init); |
| + } |
| + |
| + void InitWithVirtualContextsAndRobustness() { |
| + base::CommandLine command_line(0, NULL); |
| + command_line.AppendSwitchASCII( |
| + switches::kGpuDriverBugWorkarounds, |
| + base::IntToString(USE_VIRTUALIZED_GL_CONTEXTS)); |
| + InitState init; |
| + init.extensions = "GL_ARB_robustness"; |
| + InitDecoderWithCommandLine(init, &command_line); |
| + } |
| + |
| + void DoGetErrorWithContextLost(GLenum reset_status) { |
| + DCHECK(context_->HasExtension("GL_ARB_robustness")); |
| + EXPECT_CALL(*gl_, GetError()) |
| + .WillOnce(Return(GL_CONTEXT_LOST_KHR)) |
|
Ken Russell (switch to Gerrit)
2015/04/24 02:39:41
As you discovered and pointed out offline, the CON
no sievers
2015/04/24 18:52:47
Good point, the test looks a bit wrong that way. I
|
| + .RetiresOnSaturation(); |
| + EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()) |
| + .WillOnce(Return(reset_status)); |
| + cmds::GetError cmd; |
| + cmd.Init(shared_memory_id_, shared_memory_offset_); |
| + EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd)); |
| + EXPECT_EQ(static_cast<GLuint>(GL_NO_ERROR), *GetSharedMemoryAs<GLenum*>()); |
| + } |
| + |
| + void ClearCurrentDecoderError() { |
| + DCHECK(decoder_->WasContextLost()); |
| + EXPECT_CALL(*gl_, GetError()) |
| + .WillOnce(Return(GL_CONTEXT_LOST_KHR)) |
| + .RetiresOnSaturation(); |
| + cmds::GetError cmd; |
| + cmd.Init(shared_memory_id_, shared_memory_offset_); |
| + EXPECT_EQ(error::kLostContext, ExecuteCmd(cmd)); |
| + } |
| +}; |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LostFromMakeCurrent) { |
| + Init(false); // without robustness |
| + EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false)); |
| + decoder_->MakeCurrent(); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kMakeCurrentFailed, decoder_->GetContextLostReason()); |
| + |
| + // We didn't process commands, so we need to clear the decoder error, |
| + // so that we can shut down cleanly. |
| + ClearCurrentDecoderError(); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LostFromMakeCurrentWithRobustness) { |
| + Init(true); // with robustness |
| + // If we can't make the context current, we cannot query the robustness |
| + // extension. |
| + EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()).Times(0); |
| + EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(false)); |
| + decoder_->MakeCurrent(); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_FALSE(decoder_->WasContextLostByRobustnessExtension()); |
| + EXPECT_EQ(error::kMakeCurrentFailed, decoder_->GetContextLostReason()); |
| + |
| + // We didn't process commands, so we need to clear the decoder error, |
| + // so that we can shut down cleanly. |
| + ClearCurrentDecoderError(); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LostFromResetAfterMakeCurrent) { |
| + Init(true); // with robustness |
| + InSequence seq; |
| + EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true)); |
| + EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()) |
| + .WillOnce(Return(GL_GUILTY_CONTEXT_RESET_ARB)); |
| + decoder_->MakeCurrent(); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension()); |
| + EXPECT_EQ(error::kGuilty, decoder_->GetContextLostReason()); |
| + |
| + // We didn't process commands, so we need to clear the decoder error, |
| + // so that we can shut down cleanly. |
| + ClearCurrentDecoderError(); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LoseGuiltyFromGLError) { |
| + Init(true); |
| + // Always expect other contexts to be signaled as 'kUnknown' since we can't |
| + // query their status without making them current. |
| + EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)) |
| + .Times(1); |
| + DoGetErrorWithContextLost(GL_GUILTY_CONTEXT_RESET_ARB); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension()); |
| + EXPECT_EQ(error::kGuilty, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LoseInnocentFromGLError) { |
| + Init(true); |
| + // Always expect other contexts to be signaled as 'kUnknown' since we can't |
| + // query their status without making them current. |
| + EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)) |
| + .Times(1); |
| + DoGetErrorWithContextLost(GL_INNOCENT_CONTEXT_RESET_ARB); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension()); |
| + EXPECT_EQ(error::kInnocent, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LoseVirtualContextWithRobustness) { |
| + InitWithVirtualContextsAndRobustness(); |
| + EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)) |
| + .Times(1); |
| + // Signal guilty.... |
| + DoGetErrorWithContextLost(GL_GUILTY_CONTEXT_RESET_ARB); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_TRUE(decoder_->WasContextLostByRobustnessExtension()); |
| + // ...but make sure we don't pretend, since for virtual contexts we don't |
| + // know if this was really the guilty client. |
| + EXPECT_EQ(error::kUnknown, decoder_->GetContextLostReason()); |
| +} |
| + |
| +TEST_P(GLES2DecoderLostContextTest, LoseGroupFromRobustness) { |
| + // If one context in a group is lost through robustness, |
| + // the other ones should also get lost and query the reset status. |
| + Init(true); |
| + EXPECT_CALL(*mock_decoder_, MarkContextLost(error::kUnknown)) |
| + .Times(1); |
| + // There should be no GL calls, since we might not have a current context. |
| + EXPECT_CALL(*gl_, GetGraphicsResetStatusARB()).Times(0); |
| + LoseContexts(error::kUnknown); |
| + EXPECT_TRUE(decoder_->WasContextLost()); |
| + EXPECT_EQ(error::kUnknown, decoder_->GetContextLostReason()); |
| + |
| + // We didn't process commands, so we need to clear the decoder error, |
| + // so that we can shut down cleanly. |
| + ClearCurrentDecoderError(); |
| +} |
| + |
| +INSTANTIATE_TEST_CASE_P(Service, |
| + GLES2DecoderLostContextTest, |
| + ::testing::Bool()); |
| + |
| +} // namespace gles2 |
| +} // namespace gpu |