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_METHOD7(getVertexSpaceRequired,
60 angle::Result(const gl::Context *,
61 const gl::VertexAttribute &,
62 const gl::VertexBinding &,
63 size_t,
64 GLsizei,
65 GLuint,
66 unsigned int *));
67
68 // Dependency injection
createIndexBuffer()69 rx::IndexBuffer *createIndexBuffer() override
70 {
71 return new MockIndexBuffer(mBufferSize, mIndexType);
72 }
73
74 private:
75 unsigned int mBufferSize;
76 gl::DrawElementsType mIndexType;
77 };
78
79 class MockBufferD3D : public rx::BufferD3D
80 {
81 public:
MockBufferD3D(rx::BufferFactoryD3D * factory)82 MockBufferD3D(rx::BufferFactoryD3D *factory) : BufferD3D(mockState, factory), mData() {}
83
84 // BufferImpl
setData(const gl::Context * context,gl::BufferBinding target,const void * data,size_t size,gl::BufferUsage)85 angle::Result setData(const gl::Context *context,
86 gl::BufferBinding target,
87 const void *data,
88 size_t size,
89 gl::BufferUsage) override
90 {
91 mData.resize(size);
92 if (data && size > 0)
93 {
94 memcpy(&mData[0], data, size);
95 }
96 return angle::Result::Continue;
97 }
98
99 MOCK_METHOD5(
100 setSubData,
101 angle::Result(const gl::Context *, gl::BufferBinding, const void *, size_t, size_t));
102 MOCK_METHOD5(copySubData,
103 angle::Result(const gl::Context *, BufferImpl *, GLintptr, GLintptr, GLsizeiptr));
104 MOCK_METHOD3(map, angle::Result(const gl::Context *context, GLenum, void **));
105 MOCK_METHOD5(mapRange, angle::Result(const gl::Context *, size_t, size_t, GLbitfield, void **));
106 MOCK_METHOD2(unmap, angle::Result(const gl::Context *context, GLboolean *));
107
108 // BufferD3D
109 MOCK_METHOD1(markTransformFeedbackUsage, angle::Result(const gl::Context *));
110
111 // inlined for speed
supportsDirectBinding() const112 bool supportsDirectBinding() const override { return false; }
getSize() const113 size_t getSize() const override { return mData.size(); }
114
getData(const gl::Context * context,const uint8_t ** outData)115 angle::Result getData(const gl::Context *context, const uint8_t **outData) override
116 {
117 *outData = &mData[0];
118 return angle::Result::Continue;
119 }
120
121 private:
122 gl::BufferState mockState;
123 std::vector<uint8_t> mData;
124 };
125
126 class MockGLFactoryD3D : public rx::MockGLFactory
127 {
128 public:
MockGLFactoryD3D(MockBufferFactoryD3D * bufferFactory)129 MockGLFactoryD3D(MockBufferFactoryD3D *bufferFactory) : mBufferFactory(bufferFactory) {}
130
createBuffer(const gl::BufferState & state)131 rx::BufferImpl *createBuffer(const gl::BufferState &state) override
132 {
133 MockBufferD3D *mockBufferD3D = new MockBufferD3D(mBufferFactory);
134
135 EXPECT_CALL(*mBufferFactory, createVertexBuffer())
136 .WillOnce(Return(nullptr))
137 .RetiresOnSaturation();
138 mockBufferD3D->initializeStaticData(nullptr);
139
140 return mockBufferD3D;
141 }
142
143 MockBufferFactoryD3D *mBufferFactory;
144 };
145
146 class IndexDataManagerPerfTest : public ANGLEPerfTest
147 {
148 public:
149 IndexDataManagerPerfTest();
150
151 void step() override;
152
153 rx::IndexDataManager mIndexDataManager;
154 GLsizei mIndexCount;
155 unsigned int mBufferSize;
156 MockBufferFactoryD3D mMockBufferFactory;
157 MockGLFactoryD3D mMockGLFactory;
158 gl::Buffer mIndexBuffer;
159 };
160
IndexDataManagerPerfTest()161 IndexDataManagerPerfTest::IndexDataManagerPerfTest()
162 : ANGLEPerfTest("IndexDataManager", "", "_run", kIterationsPerStep),
163 mIndexDataManager(&mMockBufferFactory),
164 mIndexCount(4000),
165 mBufferSize(mIndexCount * sizeof(GLushort)),
166 mMockBufferFactory(mBufferSize, gl::DrawElementsType::UnsignedShort),
167 mMockGLFactory(&mMockBufferFactory),
168 mIndexBuffer(&mMockGLFactory, {1})
169 {
170 std::vector<GLushort> indexData(mIndexCount);
171 for (GLsizei index = 0; index < mIndexCount; ++index)
172 {
173 indexData[index] = static_cast<GLushort>(index);
174 }
175 EXPECT_EQ(
176 angle::Result::Continue,
177 mIndexBuffer.bufferData(nullptr, gl::BufferBinding::Array, &indexData[0],
178 indexData.size() * sizeof(GLushort), gl::BufferUsage::StaticDraw));
179 }
180
step()181 void IndexDataManagerPerfTest::step()
182 {
183 rx::TranslatedIndexData translatedIndexData;
184 gl::IndexRange indexRange;
185 for (unsigned int iteration = 0; iteration < kIterationsPerStep; ++iteration)
186 {
187 (void)mIndexBuffer.getIndexRange(nullptr, gl::DrawElementsType::UnsignedShort, 0,
188 mIndexCount, false, &indexRange);
189 (void)mIndexDataManager.prepareIndexData(nullptr, gl::DrawElementsType::UnsignedShort,
190 gl::DrawElementsType::UnsignedShort, mIndexCount,
191 &mIndexBuffer, nullptr, &translatedIndexData);
192 }
193 }
194
TEST_F(IndexDataManagerPerfTest,Run)195 TEST_F(IndexDataManagerPerfTest, Run)
196 {
197 run();
198 }
199
200 } // anonymous namespace
201