| // | |
| // 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<rx::MockTransformFeedbackImpl>(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<GLuint>(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 |