Skip to content

Commit

Permalink
Lose context on OOM
Browse files Browse the repository at this point in the history
I believe this is what we do in practice with command buffers (i.e.
ContextCreationAttribs::lose_context_when_out_of_memory is true for
display and raster).

I was not able to trigger GL_OUT_OF_MEMORY on a variety of devices
(N5X, Pixel3, S10E). Android LMKD always killed GPU process first.

Bug: 1093997
Change-Id: I849125e155310239e6450db5aea99eaed7c536f2
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2242255
Commit-Queue: Jonathan Backer <backer@chromium.org>
Reviewed-by: kylechar <kylechar@chromium.org>
Cr-Commit-Position: refs/heads/master@{#782544}
  • Loading branch information
Jonathan Backer authored and Commit Bot committed Jun 25, 2020
1 parent dcaffa2 commit 645ca14
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 15 deletions.
4 changes: 4 additions & 0 deletions gpu/command_buffer/service/raster_decoder_unittest_base.cc
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,14 @@ void RasterDecoderTestBase::InitDecoder(const InitState& init) {
gpu::ContextResult::kSuccess);

EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true));
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
if (context_->HasRobustness()) {
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(GL_NO_ERROR));
}

decoder_->MakeCurrent();
decoder_->BeginDecoding();

Expand Down
31 changes: 23 additions & 8 deletions gpu/command_buffer/service/raster_decoder_unittest_context_lost.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,13 @@ class RasterDecoderOOMTest : public RasterDecoderManualInitTest {
if (context_->HasRobustness()) {
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(reset_status));
EXPECT_CALL(*gl_, GetError()).WillRepeatedly(Return(GL_CONTEXT_LOST_KHR));
} else {
EXPECT_CALL(*gl_, GetError()).WillRepeatedly(Return(GL_NO_ERROR));
}

// glGetError merges driver error state with decoder error state. Return
// GL_NO_ERROR from mock driver and GL_OUT_OF_MEMORY from decoder.
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_NO_ERROR))
.RetiresOnSaturation();
// RasterDecoder::HandleGetError merges driver error state with decoder
// error state. Return GL_OUT_OF_MEMORY from decoder.
GetDecoder()->SetOOMErrorForTest();

cmds::GetError cmd;
Expand Down Expand Up @@ -112,9 +112,9 @@ class RasterDecoderLostContextTest : public RasterDecoderManualInitTest {

void DoGetErrorWithContextLost(GLenum reset_status) {
DCHECK(context_->HasExtension("GL_KHR_robustness"));
EXPECT_CALL(*gl_, GetError())
.WillOnce(Return(GL_CONTEXT_LOST_KHR))
.RetiresOnSaturation();
// Once context loss has occurred, driver will always return
// GL_CONTEXT_LOST_KHR.
EXPECT_CALL(*gl_, GetError()).WillRepeatedly(Return(GL_CONTEXT_LOST_KHR));
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(reset_status));
cmds::GetError cmd;
Expand Down Expand Up @@ -147,6 +147,20 @@ TEST_P(RasterDecoderLostContextTest, LostFromMakeCurrent) {
ClearCurrentDecoderError();
}

TEST_P(RasterDecoderLostContextTest, LostFromDriverOOM) {
Init(/*has_robustness=*/false);
EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true));
EXPECT_CALL(*gl_, GetError()).WillOnce(Return(GL_OUT_OF_MEMORY));
EXPECT_FALSE(decoder_->WasContextLost());
decoder_->MakeCurrent();
EXPECT_TRUE(decoder_->WasContextLost());
EXPECT_EQ(error::kOutOfMemory, GetContextLostReason());

// We didn't process commands, so we need to clear the decoder error,
// so that we can shut down cleanly.
ClearCurrentDecoderError();
}

TEST_P(RasterDecoderLostContextTest, LostFromMakeCurrentWithRobustness) {
Init(/*has_robustness=*/true); // with robustness
// If we can't make the context current, we cannot query the robustness
Expand Down Expand Up @@ -215,6 +229,7 @@ TEST_P(RasterDecoderLostContextTest, LostFromResetAfterMakeCurrent) {
Init(/*has_robustness=*/true);
InSequence seq;
EXPECT_CALL(*context_, MakeCurrent(surface_.get())).WillOnce(Return(true));
EXPECT_CALL(*gl_, GetError()).WillOnce(Return(GL_CONTEXT_LOST_KHR));
EXPECT_CALL(*gl_, GetGraphicsResetStatusARB())
.WillOnce(Return(GL_GUILTY_CONTEXT_RESET_KHR));
decoder_->MakeCurrent();
Expand Down
36 changes: 29 additions & 7 deletions gpu/command_buffer/service/shared_context_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -671,17 +671,39 @@ bool SharedContextState::CheckResetStatus(bool needs_gl) {
if (device_needs_reset_)
return true;

// Maybe Skia detected VK_ERROR_DEVICE_LOST.
if (gr_context_ && gr_context_->abandoned()) {
LOG(ERROR) << "SharedContextState context lost via Skia.";
device_needs_reset_ = true;
MarkContextLost(error::kUnknown);
return true;
if (gr_context_) {
// Maybe Skia detected VK_ERROR_DEVICE_LOST.
if (gr_context_->abandoned()) {
LOG(ERROR) << "SharedContextState context lost via Skia.";
device_needs_reset_ = true;
MarkContextLost(error::kUnknown);
return true;
}

if (gr_context_->oomed()) {
LOG(ERROR) << "SharedContextState context lost via Skia OOM.";
device_needs_reset_ = true;
MarkContextLost(error::kOutOfMemory);
return true;
}
}

// Not using GL.
if (!GrContextIsGL() && !needs_gl)
return false;

// GL is not initialized.
if (!context_state_)
return false;

GLenum error = context_state_->api()->glGetErrorFn();
if (error == GL_OUT_OF_MEMORY) {
LOG(ERROR) << "SharedContextState lost due to GL_OUT_OF_MEMORY";
MarkContextLost(error::kOutOfMemory);
device_needs_reset_ = true;
return true;
}

// Checking the reset status is expensive on some OS/drivers
// (https://crbug.com/1090232). Rate limit it.
constexpr base::TimeDelta kMinCheckDelay =
Expand Down Expand Up @@ -715,7 +737,7 @@ bool SharedContextState::CheckResetStatus(bool needs_gl) {
break;
}
device_needs_reset_ = true;
return false;
return true;
}

} // namespace gpu

0 comments on commit 645ca14

Please sign in to comment.