// // Copyright 2014 The ANGLE Project 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 "gmock/gmock.h" #include "gtest/gtest.h" #include "libANGLE/Buffer.h" #include "libANGLE/Caps.h" #include "libANGLE/TransformFeedback.h" #include "libANGLE/renderer/BufferImpl_mock.h" #include "libANGLE/renderer/TransformFeedbackImpl_mock.h" #include "tests/angle_unittests_utils.h" using ::testing::_; using ::testing::get; using ::testing::Return; using ::testing::SetArgumentPointee; namespace { ACTION(CreateMockTransformFeedbackImpl) { return new rx::MockTransformFeedbackImpl(arg0); } class TransformFeedbackTest : public testing::Test { protected: TransformFeedbackTest() : mImpl(nullptr), mFeedback(nullptr) {} void SetUp() override { EXPECT_CALL(mMockFactory, createTransformFeedback(_)) .WillOnce(CreateMockTransformFeedbackImpl()) .RetiresOnSaturation(); // Set a reasonable number of tf attributes mCaps.maxTransformFeedbackSeparateAttributes = 8; mFeedback = new gl::TransformFeedback(&mMockFactory, gl::TransformFeedbackID{1}, mCaps); mFeedback->addRef(); mImpl = rx::GetImplAs(mFeedback); EXPECT_CALL(*mImpl, destructor()); } void TearDown() override { if (mFeedback) { mFeedback->release(nullptr); } // Only needed because the mock is leaked if bugs are present, // which logs an error, but does not cause the test to fail. // Ordinarily mocks are verified when destroyed. testing::Mock::VerifyAndClear(mImpl); } rx::MockGLFactory mMockFactory; rx::MockTransformFeedbackImpl *mImpl; gl::TransformFeedback *mFeedback; gl::Caps mCaps; }; TEST_F(TransformFeedbackTest, SideEffectsOfStartAndStop) { testing::InSequence seq; EXPECT_FALSE(mFeedback->isActive()); EXPECT_CALL(*mImpl, begin(nullptr, gl::PrimitiveMode::Triangles)); EXPECT_EQ(angle::Result::Continue, mFeedback->begin(nullptr, gl::PrimitiveMode::Triangles, nullptr)); EXPECT_TRUE(mFeedback->isActive()); EXPECT_EQ(gl::PrimitiveMode::Triangles, mFeedback->getPrimitiveMode()); EXPECT_CALL(*mImpl, end(nullptr)); EXPECT_EQ(angle::Result::Continue, mFeedback->end(nullptr)); EXPECT_FALSE(mFeedback->isActive()); } TEST_F(TransformFeedbackTest, SideEffectsOfPauseAndResume) { testing::InSequence seq; EXPECT_FALSE(mFeedback->isActive()); EXPECT_CALL(*mImpl, begin(nullptr, gl::PrimitiveMode::Triangles)); EXPECT_EQ(angle::Result::Continue, mFeedback->begin(nullptr, gl::PrimitiveMode::Triangles, nullptr)); EXPECT_FALSE(mFeedback->isPaused()); EXPECT_CALL(*mImpl, pause(nullptr)); EXPECT_EQ(angle::Result::Continue, mFeedback->pause(nullptr)); EXPECT_TRUE(mFeedback->isPaused()); EXPECT_CALL(*mImpl, resume(nullptr)); EXPECT_EQ(angle::Result::Continue, mFeedback->resume(nullptr)); EXPECT_FALSE(mFeedback->isPaused()); EXPECT_CALL(*mImpl, end(nullptr)); EXPECT_EQ(angle::Result::Continue, mFeedback->end(nullptr)); } TEST_F(TransformFeedbackTest, BufferBinding) { rx::MockBufferImpl *bufferImpl = new rx::MockBufferImpl; EXPECT_CALL(*bufferImpl, destructor()).Times(1).RetiresOnSaturation(); rx::MockGLFactory mockGLFactory; EXPECT_CALL(mockGLFactory, createBuffer(_)) .Times(1) .WillOnce(Return(bufferImpl)) .RetiresOnSaturation(); gl::Buffer *buffer = new gl::Buffer(&mockGLFactory, {1}); static const size_t bindIndex = 0; EXPECT_EQ(mFeedback->getIndexedBufferCount(), static_cast(mCaps.maxTransformFeedbackSeparateAttributes)); EXPECT_CALL(*mImpl, bindIndexedBuffer(_, _, _)); EXPECT_EQ(angle::Result::Continue, mFeedback->bindIndexedBuffer(nullptr, bindIndex, buffer, 0, 1)); for (size_t i = 0; i < mFeedback->getIndexedBufferCount(); i++) { if (i == bindIndex) { EXPECT_EQ(mFeedback->getIndexedBuffer(i).get(), buffer); } else { EXPECT_EQ(mFeedback->getIndexedBuffer(i).get(), nullptr); } } // force-release the feedback object to ensure the buffer is released. const size_t releaseCount = mFeedback->getRefCount(); for (size_t count = 0; count < releaseCount; ++count) { mFeedback->release(nullptr); } mFeedback = nullptr; testing::Mock::VerifyAndClear(bufferImpl); } } // anonymous namespace