diff --git a/gpu/command_buffer/service/transform_feedback_manager.cc b/gpu/command_buffer/service/transform_feedback_manager.cc index 4dc64183727d26..7fe7b1e2cbae1b 100644 --- a/gpu/command_buffer/service/transform_feedback_manager.cc +++ b/gpu/command_buffer/service/transform_feedback_manager.cc @@ -66,7 +66,11 @@ void TransformFeedback::DoBindTransformFeedback( glResumeTransformFeedback(); } if (last_bound_transform_feedback != this) { - if (last_bound_transform_feedback) { + // An active (paused) transform feedback object continues to reference its + // attached buffers in the driver until EndTransformFeedback, so keep + // those buffers' transform feedback binding state until it ends. + if (last_bound_transform_feedback && + !last_bound_transform_feedback->active()) { last_bound_transform_feedback->SetIsBound(false); } SetIsBound(true); diff --git a/gpu/command_buffer/service/transform_feedback_manager_unittest.cc b/gpu/command_buffer/service/transform_feedback_manager_unittest.cc index 406407da90f5be..87c27b163ad04f 100644 --- a/gpu/command_buffer/service/transform_feedback_manager_unittest.cc +++ b/gpu/command_buffer/service/transform_feedback_manager_unittest.cc @@ -4,6 +4,7 @@ #include +#include "gpu/command_buffer/service/buffer_manager.h" #include "gpu/command_buffer/service/gpu_service_test.h" #include "gpu/command_buffer/service/test_helper.h" #include "gpu/command_buffer/service/transform_feedback_manager.h" @@ -11,6 +12,7 @@ #include "ui/gl/gl_mock.h" using ::testing::_; +using ::testing::AnyNumber; namespace gpu { namespace gles2 { @@ -58,5 +60,61 @@ TEST_F(TransformFeedbackManagerTest, LifeTime) { transform_feedback = nullptr; } +TEST_F(TransformFeedbackManagerTest, BufferBindingTrackedWhilePaused) { + const GLuint kBufferClientId = 11; + const GLuint kBufferServiceId = 1011; + const GLuint kClientId2 = 77; + const GLuint kServiceId2 = 1077; + + EXPECT_CALL(*gl_, BindTransformFeedback(_, _)).Times(AnyNumber()); + EXPECT_CALL(*gl_, BindBuffer(_, _)).Times(AnyNumber()); + EXPECT_CALL(*gl_, BindBufferBase(_, _, _)).Times(AnyNumber()); + EXPECT_CALL(*gl_, BeginTransformFeedback(_)).Times(AnyNumber()); + EXPECT_CALL(*gl_, PauseTransformFeedback()).Times(AnyNumber()); + EXPECT_CALL(*gl_, EndTransformFeedback()).Times(AnyNumber()); + EXPECT_CALL(*gl_, DeleteTransformFeedbacks(1, _)).Times(AnyNumber()); + + BufferManager buffer_manager(nullptr, nullptr); + buffer_manager.CreateBuffer(kBufferClientId, kBufferServiceId); + scoped_refptr buffer = buffer_manager.GetBuffer(kBufferClientId); + ASSERT_TRUE(buffer.get()); + + scoped_refptr tf1 = manager_->CreateTransformFeedback( + kTransformFeedbackClientId, kTransformFeedbackServiceId); + scoped_refptr tf2 = + manager_->CreateTransformFeedback(kClientId2, kServiceId2); + + tf1->DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK, nullptr, nullptr); + tf1->DoBindBufferBase(0, buffer.get()); + EXPECT_TRUE(buffer->IsBoundForTransformFeedback()); + + tf1->DoBeginTransformFeedback(GL_POINTS); + tf1->DoPauseTransformFeedback(); + EXPECT_TRUE(buffer->IsBoundForTransformFeedback()); + + // Switching to another transform feedback object while the previous one is + // still active (paused) must not drop the buffer's transform feedback + // binding state, otherwise it could be re-specified before it is resumed. + tf2->DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf1.get(), nullptr); + EXPECT_TRUE(buffer->IsBoundForTransformFeedback()); + + tf1->DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf2.get(), nullptr); + EXPECT_TRUE(buffer->IsBoundForTransformFeedback()); + EXPECT_FALSE(buffer->IsDoubleBoundForTransformFeedback()); + + tf1->DoEndTransformFeedback(); + EXPECT_TRUE(buffer->IsBoundForTransformFeedback()); + + tf2->DoBindTransformFeedback(GL_TRANSFORM_FEEDBACK, tf1.get(), nullptr); + EXPECT_FALSE(buffer->IsBoundForTransformFeedback()); + + manager_->Destroy(); + tf1 = nullptr; + tf2 = nullptr; + buffer = nullptr; + buffer_manager.MarkContextLost(); + buffer_manager.Destroy(); +} + } // namespace gles2 } // namespace gpu