1 //
2 // Copyright 2015 The ANGLE Project Authors. All rights reserved.
3 // Use of this source code is governed by a BSD-style license that can be
4 // found in the LICENSE file.
5 //
6 // IndexDataManagerPerfTest:
7 // Performance test for index buffer management.
8 //
9
10 #include "ANGLEPerfTest.h"
11
12 #include <gmock/gmock.h>
13
14 #include "angle_unittests_utils.h"
15 #include "libANGLE/renderer/d3d/BufferD3D.h"
16 #include "libANGLE/renderer/d3d/IndexBuffer.h"
17 #include "libANGLE/renderer/d3d/IndexDataManager.h"
18
19 using namespace testing;
20
21 namespace
22 {
23 constexpr unsigned int kIterationsPerStep = 100;
24
25 class MockIndexBuffer : public rx::IndexBuffer
26 {
27 public:
MockIndexBuffer(unsigned int bufferSize,gl::DrawElementsType indexType)28 MockIndexBuffer(unsigned int bufferSize, gl::DrawElementsType indexType)
29 : mBufferSize(bufferSize), mIndexType(indexType)
30 {}
31
32 MOCK_METHOD4(initialize,
33 angle::Result(const gl::Context *, unsigned int, gl::DrawElementsType, bool));
34 MOCK_METHOD4(mapBuffer,
35 angle::Result(const gl::Context *, unsigned int, unsigned int, void **));
36 MOCK_METHOD1(unmapBuffer, angle::Result(const gl::Context *));
37 MOCK_METHOD1(discard, angle::Result(const gl::Context *));
38 MOCK_METHOD3(setSize, angle::Result(const gl::Context *, unsigned int, gl::DrawElementsType));
39
40 // inlined for speed
getIndexType() const41 gl::DrawElementsType getIndexType() const override { return mIndexType; }
getBufferSize() const42 unsigned int getBufferSize() const override { return mBufferSize; }
43
44 private:
45 unsigned int mBufferSize;
46 gl::DrawElementsType mIndexType;
47 };
48
49 class MockBufferFactoryD3D : public rx::BufferFactoryD3D
50 {
51 public:
MockBufferFactoryD3D(unsigned int bufferSize,gl::DrawElementsType indexType)52 MockBufferFactoryD3D(unsigned int bufferSize, gl::DrawElementsType indexType)
53 : mBufferSize(bufferSize), mIndexType(indexType)
54 {}
55
56 MOCK_METHOD0(createVertexBuffer, rx::VertexBuffer *());
57 MOCK_CONST_METHOD1(getVertexConversionType, rx::VertexConversionType(angle::FormatID));
58 MOCK_CONST_METHOD1(getVertexComponentType, GLenum(angle::FormatID));
59 MOCK_CONST_METHOD6(getVertexSpaceRequired,
60 angle::Result(const gl::Context *,
61 const gl::VertexAttribute &,
62 const gl::VertexBinding &,
63 size_t,
64 GLsizei,
65 unsigned int *));
66
67 // Dependency injection
createIndexBuffer()68 rx::IndexBuffer *createIndexBuffer() override
69 {
70 return new MockIndexBuffer(mBufferSize, mIndexType);
71 }
72
73 private:
74 unsigned int mBufferSize;
75 gl::DrawElementsType mIndexType;
76 };
77
78 class MockBufferD3D : public rx::BufferD3D
79 {
80 public:
MockBufferD3D(rx::BufferFactoryD3D * factory)81 MockBufferD3D(rx::BufferFactoryD3D *factory) : BufferD3D(mockState, factory), mData() {}
82
83 // BufferImpl
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage)84 angle::Result setData(const gl::Context *context,
85 gl::BufferBinding target,
86 const void *data,
87 size_t size,
88 gl::BufferUsage) override
89 {
90 mData.resize(size);
91 if (data && size > 0)
92 {
93 memcpy(&mData[0], data, size);
94 }
95 return angle::Result::Continue;
96 }
97
98 MOCK_METHOD5(
99 setSubData,
100 angle::Result(const gl::Context *, gl::BufferBinding, const void *, size_t, size_t));
101 MOCK_METHOD5(copySubData,
102 angle::Result(const gl::Context *, BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
103 MOCK_METHOD3(map, angle::Result(const gl::Context *context, GLenum, void **));
104 MOCK_METHOD5(mapRange, angle::Result(const gl::Context *, size_t, size_t, GLbitfield, void **));
105 MOCK_METHOD2(unmap, angle::Result(const gl::Context *context, GLboolean *));
106
107 // BufferD3D
108 MOCK_METHOD1(markTransformFeedbackUsage, angle::Result(const gl::Context *));
109
110 // inlined for speed
supportsDirectBinding() const111 bool supportsDirectBinding() const override { return false; }
getSize() const112 size_t getSize() const override { return mData.size(); }
113
getData(const gl::Context * context,const uint8_t ** outData)114 angle::Result getData(const gl::Context *context, const uint8_t **outData) override
115 {
116 *outData = &mData[0];
117 return angle::Result::Continue;
118 }
119
120 private:
121 gl::BufferState mockState;
122 std::vector<uint8_t> mData;
123 };
124
125 class MockGLFactoryD3D : public rx::MockGLFactory
126 {
127 public:
MockGLFactoryD3D(MockBufferFactoryD3D * bufferFactory)128 MockGLFactoryD3D(MockBufferFactoryD3D *bufferFactory) : mBufferFactory(bufferFactory) {}
129
createBuffer(const gl::BufferState & state)130 rx::BufferImpl *createBuffer(const gl::BufferState &state) override
131 {
132 MockBufferD3D *mockBufferD3D = new MockBufferD3D(mBufferFactory);
133
134 EXPECT_CALL(*mBufferFactory, createVertexBuffer())
135 .WillOnce(Return(nullptr))
136 .RetiresOnSaturation();
137 mockBufferD3D->initializeStaticData(nullptr);
138
139 return mockBufferD3D;
140 }
141
142 MockBufferFactoryD3D *mBufferFactory;
143 };
144
145 class IndexDataManagerPerfTest : public ANGLEPerfTest
146 {
147 public:
148 IndexDataManagerPerfTest();
149
150 void step() override;
151
152 rx::IndexDataManager mIndexDataManager;
153 GLsizei mIndexCount;
154 unsigned int mBufferSize;
155 MockBufferFactoryD3D mMockBufferFactory;
156 MockGLFactoryD3D mMockGLFactory;
157 gl::Buffer mIndexBuffer;
158 };
159
IndexDataManagerPerfTest()160 IndexDataManagerPerfTest::IndexDataManagerPerfTest()
161 : ANGLEPerfTest("IndexDataManager", "", "_run", kIterationsPerStep),
162 mIndexDataManager(&mMockBufferFactory),
163 mIndexCount(4000),
164 mBufferSize(mIndexCount * sizeof(GLushort)),
165 mMockBufferFactory(mBufferSize, gl::DrawElementsType::UnsignedShort),
166 mMockGLFactory(&mMockBufferFactory),
167 mIndexBuffer(&mMockGLFactory, {1})
168 {
169 std::vector<GLushort> indexData(mIndexCount);
170 for (GLsizei index = 0; index < mIndexCount; ++index)
171 {
172 indexData[index] = static_cast<GLushort>(index);
173 }
174 EXPECT_EQ(
175 angle::Result::Continue,
176 mIndexBuffer.bufferData(nullptr, gl::BufferBinding::Array, &indexData[0],
177 indexData.size() * sizeof(GLushort), gl::BufferUsage::StaticDraw));
178 }
179
step()180 void IndexDataManagerPerfTest::step()
181 {
182 rx::TranslatedIndexData translatedIndexData;
183 gl::IndexRange indexRange;
184 for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
185 {
186 (void)mIndexBuffer.getIndexRange(nullptr, gl::DrawElementsType::UnsignedShort, 0,
187 mIndexCount, false, &indexRange);
188 (void)mIndexDataManager.prepareIndexData(nullptr, gl::DrawElementsType::UnsignedShort,
189 gl::DrawElementsType::UnsignedShort, mIndexCount,
190 &mIndexBuffer, nullptr, &translatedIndexData);
191 }
192 }
193
TEST_F(IndexDataManagerPerfTest,Run)194 TEST_F(IndexDataManagerPerfTest, Run)
195 {
196 run();
197 }
198
199 } // anonymous namespace
200