• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright 2019 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 // TextureUploadBenchmark:
7 //   Performance test for uploading texture data.
8 //
9 
10 #include "ANGLEPerfTest.h"
11 
12 #include <iostream>
13 #include <random>
14 #include <sstream>
15 
16 #include "test_utils/gl_raii.h"
17 #include "util/shader_utils.h"
18 
19 using namespace angle;
20 
21 namespace
22 {
23 constexpr unsigned int kIterationsPerStep = 2;
24 
25 struct TextureUploadParams final : public RenderTestParams
26 {
TextureUploadParams__anonc15d59220111::TextureUploadParams27     TextureUploadParams()
28     {
29         iterationsPerStep = kIterationsPerStep;
30         trackGpuTime      = true;
31 
32         baseSize     = 1024;
33         subImageSize = 64;
34 
35         webgl = false;
36     }
37 
38     std::string story() const override;
39 
40     GLsizei baseSize;
41     GLsizei subImageSize;
42 
43     bool webgl;
44 };
45 
operator <<(std::ostream & os,const TextureUploadParams & params)46 std::ostream &operator<<(std::ostream &os, const TextureUploadParams &params)
47 {
48     os << params.backendAndStory().substr(1);
49     return os;
50 }
51 
story() const52 std::string TextureUploadParams::story() const
53 {
54     std::stringstream strstr;
55 
56     strstr << RenderTestParams::story();
57 
58     if (webgl)
59     {
60         strstr << "_webgl";
61     }
62 
63     return strstr.str();
64 }
65 
66 class TextureUploadBenchmarkBase : public ANGLERenderTest,
67                                    public ::testing::WithParamInterface<TextureUploadParams>
68 {
69   public:
70     TextureUploadBenchmarkBase(const char *benchmarkName);
71 
72     void initializeBenchmark() override;
73     void destroyBenchmark() override;
74 
75   protected:
76     void initShaders();
77 
78     GLuint mProgram    = 0;
79     GLint mPositionLoc = -1;
80     GLint mSamplerLoc  = -1;
81     GLuint mTexture    = 0;
82     std::vector<float> mTextureData;
83 };
84 
85 class TextureUploadSubImageBenchmark : public TextureUploadBenchmarkBase
86 {
87   public:
TextureUploadSubImageBenchmark()88     TextureUploadSubImageBenchmark() : TextureUploadBenchmarkBase("TexSubImage")
89     {
90         addExtensionPrerequisite("GL_EXT_texture_storage");
91     }
92 
initializeBenchmark()93     void initializeBenchmark() override
94     {
95         TextureUploadBenchmarkBase::initializeBenchmark();
96 
97         const auto &params = GetParam();
98         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
99     }
100 
101     void drawBenchmark() override;
102 };
103 
104 class TextureUploadFullMipBenchmark : public TextureUploadBenchmarkBase
105 {
106   public:
TextureUploadFullMipBenchmark()107     TextureUploadFullMipBenchmark() : TextureUploadBenchmarkBase("TextureUpload") {}
108 
109     void drawBenchmark() override;
110 };
111 
112 class PBOSubImageBenchmark : public TextureUploadBenchmarkBase
113 {
114   public:
PBOSubImageBenchmark()115     PBOSubImageBenchmark() : TextureUploadBenchmarkBase("PBO") {}
116 
initializeBenchmark()117     void initializeBenchmark() override
118     {
119         TextureUploadBenchmarkBase::initializeBenchmark();
120 
121         const auto &params = GetParam();
122 
123         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
124 
125         glGenBuffers(1, &mPBO);
126         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
127         glBufferData(GL_PIXEL_UNPACK_BUFFER, params.baseSize * params.baseSize * 4,
128                      mTextureData.data(), GL_STREAM_DRAW);
129     }
130 
destroyBenchmark()131     void destroyBenchmark()
132     {
133         TextureUploadBenchmarkBase::destroyBenchmark();
134         glDeleteBuffers(1, &mPBO);
135     }
136 
137     void drawBenchmark() override;
138 
139   private:
140     GLuint mPBO;
141 };
142 
143 class PBOCompressedSubImageBenchmark : public TextureUploadBenchmarkBase
144 {
145   public:
PBOCompressedSubImageBenchmark()146     PBOCompressedSubImageBenchmark() : TextureUploadBenchmarkBase("PBOCompressed") {}
147 
initializeBenchmark()148     void initializeBenchmark() override
149     {
150         TextureUploadBenchmarkBase::initializeBenchmark();
151 
152         const auto &params = GetParam();
153 
154         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, params.baseSize,
155                           params.baseSize);
156 
157         glGenBuffers(1, &mPBO);
158         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
159         glBufferData(GL_PIXEL_UNPACK_BUFFER, params.subImageSize * params.subImageSize / 2,
160                      mTextureData.data(), GL_STREAM_DRAW);
161     }
162 
destroyBenchmark()163     void destroyBenchmark()
164     {
165         TextureUploadBenchmarkBase::destroyBenchmark();
166         glDeleteBuffers(1, &mPBO);
167     }
168 
169     void drawBenchmark() override;
170 
171   private:
172     GLuint mPBO;
173 };
174 
TextureUploadBenchmarkBase(const char * benchmarkName)175 TextureUploadBenchmarkBase::TextureUploadBenchmarkBase(const char *benchmarkName)
176     : ANGLERenderTest(benchmarkName, GetParam())
177 {
178     setWebGLCompatibilityEnabled(GetParam().webgl);
179     setRobustResourceInit(GetParam().webgl);
180 
181     // Crashes on nvidia+d3d11. http://crbug.com/945415
182     if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
183     {
184         mSkipTest = true;
185     }
186 }
187 
initializeBenchmark()188 void TextureUploadBenchmarkBase::initializeBenchmark()
189 {
190     const auto &params = GetParam();
191 
192     initShaders();
193     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
194     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
195 
196     if (params.webgl)
197     {
198         glRequestExtensionANGLE("GL_EXT_disjoint_timer_query");
199     }
200 
201     glActiveTexture(GL_TEXTURE0);
202     glGenTextures(1, &mTexture);
203     glBindTexture(GL_TEXTURE_2D, mTexture);
204 
205     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
206     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
207     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
208     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
209 
210     ASSERT_TRUE(params.baseSize >= params.subImageSize);
211     mTextureData.resize(params.baseSize * params.baseSize * 4, 0.5);
212 
213     ASSERT_GL_NO_ERROR();
214 }
215 
initShaders()216 void TextureUploadBenchmarkBase::initShaders()
217 {
218     constexpr char kVS[] = R"(attribute vec4 a_position;
219 void main()
220 {
221     gl_Position = a_position;
222 })";
223 
224     constexpr char kFS[] = R"(precision mediump float;
225 uniform sampler2D s_texture;
226 void main()
227 {
228     gl_FragColor = texture2D(s_texture, vec2(0, 0));
229 })";
230 
231     mProgram = CompileProgram(kVS, kFS);
232     ASSERT_NE(0u, mProgram);
233 
234     mPositionLoc = glGetAttribLocation(mProgram, "a_position");
235     mSamplerLoc  = glGetUniformLocation(mProgram, "s_texture");
236     glUseProgram(mProgram);
237     glUniform1i(mSamplerLoc, 0);
238 
239     glDisable(GL_DEPTH_TEST);
240 
241     ASSERT_GL_NO_ERROR();
242 }
243 
destroyBenchmark()244 void TextureUploadBenchmarkBase::destroyBenchmark()
245 {
246     glDeleteTextures(1, &mTexture);
247     glDeleteProgram(mProgram);
248 }
249 
drawBenchmark()250 void TextureUploadSubImageBenchmark::drawBenchmark()
251 {
252     const auto &params = GetParam();
253 
254     startGpuTimer();
255     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
256     {
257         glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
258                         rand() % (params.baseSize - params.subImageSize), params.subImageSize,
259                         params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, mTextureData.data());
260 
261         // Perform a draw just so the texture data is flushed.  With the position attributes not
262         // set, a constant default value is used, resulting in a very cheap draw.
263         glDrawArrays(GL_TRIANGLES, 0, 3);
264     }
265     stopGpuTimer();
266 
267     ASSERT_GL_NO_ERROR();
268 }
269 
drawBenchmark()270 void TextureUploadFullMipBenchmark::drawBenchmark()
271 {
272     const auto &params = GetParam();
273 
274     startGpuTimer();
275     for (size_t it = 0; it < params.iterationsPerStep; ++it)
276     {
277         // Stage data for all mips
278         GLint mip = 0;
279         for (GLsizei levelSize = params.baseSize; levelSize > 0; levelSize >>= 1)
280         {
281             glTexImage2D(GL_TEXTURE_2D, mip++, GL_RGBA, levelSize, levelSize, 0, GL_RGBA,
282                          GL_UNSIGNED_BYTE, mTextureData.data());
283         }
284 
285         // Perform a draw just so the texture data is flushed.  With the position attributes not
286         // set, a constant default value is used, resulting in a very cheap draw.
287         glDrawArrays(GL_TRIANGLES, 0, 3);
288     }
289     stopGpuTimer();
290 
291     ASSERT_GL_NO_ERROR();
292 }
293 
drawBenchmark()294 void PBOSubImageBenchmark::drawBenchmark()
295 {
296     const auto &params = GetParam();
297 
298     startGpuTimer();
299     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
300     {
301         glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
302                         rand() % (params.baseSize - params.subImageSize), params.subImageSize,
303                         params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, 0);
304 
305         // Perform a draw just so the texture data is flushed.  With the position attributes not
306         // set, a constant default value is used, resulting in a very cheap draw.
307         glDrawArrays(GL_TRIANGLES, 0, 3);
308     }
309     stopGpuTimer();
310 
311     ASSERT_GL_NO_ERROR();
312 }
313 
drawBenchmark()314 void PBOCompressedSubImageBenchmark::drawBenchmark()
315 {
316     const auto &params = GetParam();
317 
318     startGpuTimer();
319     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
320     {
321         glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, params.subImageSize, params.subImageSize,
322                                   GL_COMPRESSED_RGB8_ETC2,
323                                   params.subImageSize * params.subImageSize / 2, 0);
324 
325         // Perform a draw just so the texture data is flushed.  With the position attributes not
326         // set, a constant default value is used, resulting in a very cheap draw.
327         glDrawArrays(GL_TRIANGLES, 0, 3);
328     }
329     stopGpuTimer();
330 
331     ASSERT_GL_NO_ERROR();
332 }
333 
D3D11Params(bool webglCompat)334 TextureUploadParams D3D11Params(bool webglCompat)
335 {
336     TextureUploadParams params;
337     params.eglParameters = egl_platform::D3D11();
338     params.webgl         = webglCompat;
339     return params;
340 }
341 
OpenGLOrGLESParams(bool webglCompat)342 TextureUploadParams OpenGLOrGLESParams(bool webglCompat)
343 {
344     TextureUploadParams params;
345     params.eglParameters = egl_platform::OPENGL_OR_GLES();
346     params.webgl         = webglCompat;
347     return params;
348 }
349 
VulkanParams(bool webglCompat)350 TextureUploadParams VulkanParams(bool webglCompat)
351 {
352     TextureUploadParams params;
353     params.eglParameters = egl_platform::VULKAN();
354     params.webgl         = webglCompat;
355     return params;
356 }
357 
VulkanPBOParams(GLsizei baseSize,GLsizei subImageSize)358 TextureUploadParams VulkanPBOParams(GLsizei baseSize, GLsizei subImageSize)
359 {
360     TextureUploadParams params;
361     params.eglParameters = egl_platform::VULKAN();
362     params.webgl         = false;
363     params.trackGpuTime  = false;
364     params.baseSize      = baseSize;
365     params.subImageSize  = subImageSize;
366     return params;
367 }
368 
ES3OpenGLPBOParams(GLsizei baseSize,GLsizei subImageSize)369 TextureUploadParams ES3OpenGLPBOParams(GLsizei baseSize, GLsizei subImageSize)
370 {
371     TextureUploadParams params;
372     params.eglParameters = egl_platform::OPENGL();
373     params.majorVersion  = 3;
374     params.minorVersion  = 0;
375     params.webgl         = false;
376     params.trackGpuTime  = false;
377     params.baseSize      = baseSize;
378     params.subImageSize  = subImageSize;
379     return params;
380 }
381 
382 }  // anonymous namespace
383 
TEST_P(TextureUploadSubImageBenchmark,Run)384 TEST_P(TextureUploadSubImageBenchmark, Run)
385 {
386     run();
387 }
388 
TEST_P(TextureUploadFullMipBenchmark,Run)389 TEST_P(TextureUploadFullMipBenchmark, Run)
390 {
391     run();
392 }
393 
TEST_P(PBOSubImageBenchmark,Run)394 TEST_P(PBOSubImageBenchmark, Run)
395 {
396     run();
397 }
398 
TEST_P(PBOCompressedSubImageBenchmark,Run)399 TEST_P(PBOCompressedSubImageBenchmark, Run)
400 {
401     run();
402 }
403 
404 using namespace params;
405 
406 ANGLE_INSTANTIATE_TEST(TextureUploadSubImageBenchmark,
407                        D3D11Params(false),
408                        D3D11Params(true),
409                        OpenGLOrGLESParams(false),
410                        OpenGLOrGLESParams(true),
411                        VulkanParams(false),
412                        NullDevice(VulkanParams(false)),
413                        VulkanParams(true));
414 
415 ANGLE_INSTANTIATE_TEST(TextureUploadFullMipBenchmark,
416                        D3D11Params(false),
417                        D3D11Params(true),
418                        OpenGLOrGLESParams(false),
419                        OpenGLOrGLESParams(true),
420                        VulkanParams(false),
421                        VulkanParams(true));
422 
423 ANGLE_INSTANTIATE_TEST(PBOSubImageBenchmark,
424                        ES3OpenGLPBOParams(1024, 128),
425                        VulkanPBOParams(1024, 128));
426 
427 ANGLE_INSTANTIATE_TEST(PBOCompressedSubImageBenchmark,
428                        ES3OpenGLPBOParams(128, 128),
429                        VulkanPBOParams(128, 128));
430