| // | |
| // Copyright 2015 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. | |
| // | |
| // IndexDataManagerPerfTest: | |
| // Performance test for index buffer management. | |
| // | |
| #include "ANGLEPerfTest.h" | |
| #include "common/unsafe_buffers.h" | |
| #include <gmock/gmock.h> | |
| #include "angle_unittests_utils.h" | |
| #include "libANGLE/renderer/d3d/BufferD3D.h" | |
| #include "libANGLE/renderer/d3d/IndexBuffer.h" | |
| #include "libANGLE/renderer/d3d/IndexDataManager.h" | |
| using namespace testing; | |
| namespace | |
| { | |
| constexpr unsigned int kIterationsPerStep = 100; | |
| class MockIndexBuffer : public rx::IndexBuffer | |
| { | |
| public: | |
| MockIndexBuffer(unsigned int bufferSize, gl::DrawElementsType indexType) | |
| : mBufferSize(bufferSize), mIndexType(indexType) | |
| {} | |
| MOCK_METHOD4(initialize, | |
| angle::Result(const gl::Context *, unsigned int, gl::DrawElementsType, bool)); | |
| MOCK_METHOD4(mapBuffer, | |
| angle::Result(const gl::Context *, unsigned int, unsigned int, void **)); | |
| MOCK_METHOD1(unmapBuffer, angle::Result(const gl::Context *)); | |
| MOCK_METHOD1(discard, angle::Result(const gl::Context *)); | |
| MOCK_METHOD3(setSize, angle::Result(const gl::Context *, unsigned int, gl::DrawElementsType)); | |
| // inlined for speed | |
| gl::DrawElementsType getIndexType() const override { return mIndexType; } | |
| unsigned int getBufferSize() const override { return mBufferSize; } | |
| private: | |
| unsigned int mBufferSize; | |
| gl::DrawElementsType mIndexType; | |
| }; | |
| class MockBufferFactoryD3D : public rx::BufferFactoryD3D | |
| { | |
| public: | |
| MockBufferFactoryD3D(unsigned int bufferSize, gl::DrawElementsType indexType) | |
| : mBufferSize(bufferSize), mIndexType(indexType) | |
| {} | |
| MOCK_METHOD0(createVertexBuffer, rx::VertexBuffer *()); | |
| MOCK_CONST_METHOD1(getVertexConversionType, rx::VertexConversionType(angle::FormatID)); | |
| MOCK_CONST_METHOD1(getVertexComponentType, GLenum(angle::FormatID)); | |
| MOCK_CONST_METHOD7(getVertexSpaceRequired, | |
| angle::Result(const gl::Context *, | |
| const gl::VertexAttribute &, | |
| const gl::VertexBinding &, | |
| size_t, | |
| GLsizei, | |
| uint64_t, | |
| unsigned int *)); | |
| // Dependency injection | |
| rx::IndexBuffer *createIndexBuffer() override | |
| { | |
| return new MockIndexBuffer(mBufferSize, mIndexType); | |
| } | |
| private: | |
| unsigned int mBufferSize; | |
| gl::DrawElementsType mIndexType; | |
| }; | |
| class MockBufferD3D : public rx::BufferD3D | |
| { | |
| public: | |
| MockBufferD3D(rx::BufferFactoryD3D *factory) : BufferD3D(mockState, factory), mData() {} | |
| // BufferImpl | |
| angle::Result setData(const gl::Context *context, | |
| gl::BufferBinding target, | |
| const void *data, | |
| size_t size, | |
| gl::BufferUsage, | |
| rx::BufferFeedback *feedback, | |
| gl::ZeroFillRequired zeroFillRequired) override | |
| { | |
| mData.resize(size); | |
| if (data && size > 0) | |
| { | |
| ANGLE_UNSAFE_TODO(memcpy(&mData[0], data, size)); | |
| } | |
| return angle::Result::Continue; | |
| } | |
| MOCK_METHOD6(setSubData, | |
| angle::Result(const gl::Context *, | |
| gl::BufferBinding, | |
| const void *, | |
| size_t, | |
| size_t, | |
| rx::BufferFeedback *)); | |
| MOCK_METHOD6(copySubData, | |
| angle::Result(const gl::Context *, | |
| BufferImpl *, | |
| GLintptr, | |
| GLintptr, | |
| GLsizeiptr, | |
| rx::BufferFeedback *)); | |
| MOCK_METHOD4(map, | |
| angle::Result(const gl::Context *context, GLenum, void **, rx::BufferFeedback *)); | |
| MOCK_METHOD6(mapRange, | |
| angle::Result(const gl::Context *, | |
| size_t, | |
| size_t, | |
| GLbitfield, | |
| void **, | |
| rx::BufferFeedback *)); | |
| MOCK_METHOD3(unmap, | |
| angle::Result(const gl::Context *context, GLboolean *, rx::BufferFeedback *)); | |
| // BufferD3D | |
| MOCK_METHOD2(markTransformFeedbackUsage, | |
| angle::Result(const gl::Context *, rx::BufferFeedback *)); | |
| // inlined for speed | |
| bool supportsDirectBinding() const override { return false; } | |
| size_t getSize() const override { return mData.size(); } | |
| angle::Result getData(const gl::Context *context, const uint8_t **outData) override | |
| { | |
| *outData = &mData[0]; | |
| return angle::Result::Continue; | |
| } | |
| private: | |
| gl::BufferState mockState; | |
| std::vector<uint8_t> mData; | |
| }; | |
| class MockGLFactoryD3D : public rx::MockGLFactory | |
| { | |
| public: | |
| MockGLFactoryD3D(MockBufferFactoryD3D *bufferFactory) : mBufferFactory(bufferFactory) {} | |
| rx::BufferImpl *createBuffer(const gl::BufferState &state) override | |
| { | |
| MockBufferD3D *mockBufferD3D = new MockBufferD3D(mBufferFactory); | |
| rx::BufferFeedback feedback; | |
| EXPECT_CALL(*mBufferFactory, createVertexBuffer()) | |
| .WillOnce(Return(nullptr)) | |
| .RetiresOnSaturation(); | |
| mockBufferD3D->initializeStaticData(nullptr, &feedback); | |
| return mockBufferD3D; | |
| } | |
| MockBufferFactoryD3D *mBufferFactory; | |
| }; | |
| class IndexDataManagerPerfTest : public ANGLEPerfTest | |
| { | |
| public: | |
| IndexDataManagerPerfTest(); | |
| void step() override; | |
| rx::IndexDataManager mIndexDataManager; | |
| GLsizei mIndexCount; | |
| unsigned int mBufferSize; | |
| MockBufferFactoryD3D mMockBufferFactory; | |
| MockGLFactoryD3D mMockGLFactory; | |
| gl::Buffer mIndexBuffer; | |
| }; | |
| IndexDataManagerPerfTest::IndexDataManagerPerfTest() | |
| : ANGLEPerfTest("IndexDataManager", "", "_run", kIterationsPerStep), | |
| mIndexDataManager(&mMockBufferFactory), | |
| mIndexCount(4000), | |
| mBufferSize(mIndexCount * sizeof(GLushort)), | |
| mMockBufferFactory(mBufferSize, gl::DrawElementsType::UnsignedShort), | |
| mMockGLFactory(&mMockBufferFactory), | |
| mIndexBuffer(&mMockGLFactory, {1}) | |
| { | |
| std::vector<GLushort> indexData(mIndexCount); | |
| for (GLsizei index = 0; index < mIndexCount; ++index) | |
| { | |
| indexData[index] = static_cast<GLushort>(index); | |
| } | |
| EXPECT_EQ( | |
| angle::Result::Continue, | |
| mIndexBuffer.bufferData(nullptr, gl::BufferBinding::Array, &indexData[0], | |
| indexData.size() * sizeof(GLushort), gl::BufferUsage::StaticDraw)); | |
| } | |
| void IndexDataManagerPerfTest::step() | |
| { | |
| rx::TranslatedIndexData translatedIndexData; | |
| gl::IndexRange indexRange; | |
| for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration) | |
| { | |
| (void)mIndexBuffer.getIndexRange(nullptr, gl::DrawElementsType::UnsignedShort, 0, | |
| mIndexCount, false, &indexRange); | |
| (void)mIndexDataManager.prepareIndexData(nullptr, gl::DrawElementsType::UnsignedShort, | |
| gl::DrawElementsType::UnsignedShort, mIndexCount, | |
| &mIndexBuffer, nullptr, &translatedIndexData); | |
| } | |
| } | |
| TEST_F(IndexDataManagerPerfTest, Run) | |
| { | |
| run(); | |
| } | |
| } // anonymous namespace |