xref: /aosp_15_r20/external/angle/src/tests/perf_tests/TextureUploadPerf.cpp (revision 8975f5c5ed3d1c378011245431ada316dfb6f244)
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 "media/etc2bc_rgba8.inc"
17 #include "test_utils/gl_raii.h"
18 #include "util/shader_utils.h"
19 
20 using namespace angle;
21 
22 namespace
23 {
24 constexpr unsigned int kIterationsPerStep = 2;
25 
26 struct TextureUploadParams final : public RenderTestParams
27 {
TextureUploadParams__anona0f4d5780111::TextureUploadParams28     TextureUploadParams()
29     {
30         iterationsPerStep = kIterationsPerStep;
31         trackGpuTime      = true;
32 
33         baseSize     = 1024;
34         subImageSize = 64;
35 
36         webgl = false;
37     }
38 
39     std::string story() const override;
40 
41     GLsizei baseSize;
42     GLsizei subImageSize;
43 
44     bool webgl;
45 };
46 
operator <<(std::ostream & os,const TextureUploadParams & params)47 std::ostream &operator<<(std::ostream &os, const TextureUploadParams &params)
48 {
49     os << params.backendAndStory().substr(1);
50     return os;
51 }
52 
story() const53 std::string TextureUploadParams::story() const
54 {
55     std::stringstream strstr;
56 
57     strstr << RenderTestParams::story();
58 
59     if (webgl)
60     {
61         strstr << "_webgl";
62     }
63 
64     return strstr.str();
65 }
66 
67 class TextureUploadBenchmarkBase : public ANGLERenderTest,
68                                    public ::testing::WithParamInterface<TextureUploadParams>
69 {
70   public:
71     TextureUploadBenchmarkBase(const char *benchmarkName);
72 
73     void initializeBenchmark() override;
74     void destroyBenchmark() override;
75 
76   protected:
77     void initShaders();
78 
79     GLuint mProgram    = 0;
80     GLint mPositionLoc = -1;
81     GLint mSamplerLoc  = -1;
82     GLuint mTexture    = 0;
83     std::vector<float> mTextureData;
84 };
85 
86 class TextureUploadSubImageBenchmark : public TextureUploadBenchmarkBase
87 {
88   public:
TextureUploadSubImageBenchmark()89     TextureUploadSubImageBenchmark() : TextureUploadBenchmarkBase("TexSubImage")
90     {
91         addExtensionPrerequisite("GL_EXT_texture_storage");
92 
93         if (IsLinux() && IsIntel() &&
94             GetParam().eglParameters.renderer == EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE)
95         {
96             skipTest("http://anglebug.com/42264836");
97         }
98     }
99 
initializeBenchmark()100     void initializeBenchmark() override
101     {
102         TextureUploadBenchmarkBase::initializeBenchmark();
103 
104         const auto &params = GetParam();
105         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
106     }
107 
108     void drawBenchmark() override;
109 };
110 
111 class TextureUploadFullMipBenchmark : public TextureUploadBenchmarkBase
112 {
113   public:
TextureUploadFullMipBenchmark()114     TextureUploadFullMipBenchmark() : TextureUploadBenchmarkBase("TextureUpload") {}
115 
116     void drawBenchmark() override;
117 };
118 
119 class PBOSubImageBenchmark : public TextureUploadBenchmarkBase
120 {
121   public:
PBOSubImageBenchmark()122     PBOSubImageBenchmark() : TextureUploadBenchmarkBase("PBO") {}
123 
initializeBenchmark()124     void initializeBenchmark() override
125     {
126         TextureUploadBenchmarkBase::initializeBenchmark();
127 
128         const auto &params = GetParam();
129 
130         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_RGBA8, params.baseSize, params.baseSize);
131 
132         glGenBuffers(1, &mPBO);
133         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
134         glBufferData(GL_PIXEL_UNPACK_BUFFER, params.baseSize * params.baseSize * 4,
135                      mTextureData.data(), GL_STREAM_DRAW);
136     }
137 
destroyBenchmark()138     void destroyBenchmark()
139     {
140         TextureUploadBenchmarkBase::destroyBenchmark();
141         glDeleteBuffers(1, &mPBO);
142     }
143 
144     void drawBenchmark() override;
145 
146   private:
147     GLuint mPBO;
148 };
149 
150 class PBOCompressedSubImageBenchmark : public TextureUploadBenchmarkBase
151 {
152   public:
PBOCompressedSubImageBenchmark()153     PBOCompressedSubImageBenchmark() : TextureUploadBenchmarkBase("PBOCompressed") {}
154 
initializeBenchmark()155     void initializeBenchmark() override
156     {
157         TextureUploadBenchmarkBase::initializeBenchmark();
158 
159         const auto &params = GetParam();
160 
161         glTexStorage2DEXT(GL_TEXTURE_2D, 1, GL_COMPRESSED_RGB8_ETC2, params.baseSize,
162                           params.baseSize);
163 
164         glGenBuffers(1, &mPBO);
165         glBindBuffer(GL_PIXEL_UNPACK_BUFFER, mPBO);
166         glBufferData(GL_PIXEL_UNPACK_BUFFER, params.subImageSize * params.subImageSize / 2,
167                      mTextureData.data(), GL_STREAM_DRAW);
168     }
169 
destroyBenchmark()170     void destroyBenchmark()
171     {
172         TextureUploadBenchmarkBase::destroyBenchmark();
173         glDeleteBuffers(1, &mPBO);
174     }
175 
176     void drawBenchmark() override;
177 
178   private:
179     GLuint mPBO;
180 };
181 
182 class TextureUploadETC2TranscodingBenchmark : public TextureUploadBenchmarkBase
183 {
184   public:
TextureUploadETC2TranscodingBenchmark()185     TextureUploadETC2TranscodingBenchmark() : TextureUploadBenchmarkBase("ETC2Transcoding") {}
186 
initializeBenchmark()187     void initializeBenchmark() override
188     {
189         static GLsizei kMaxTextureSize = 2048;
190         static GLsizei kMinTextureSize = 4;
191         const auto &params             = GetParam();
192         ASSERT(params.baseSize <= kMaxTextureSize && params.baseSize >= kMinTextureSize);
193         initShaders();
194         ASSERT_GL_NO_ERROR();
195 
196         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
197         glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
198         ASSERT_GL_NO_ERROR();
199         mLevels               = (int)ceilf(log2(params.baseSize));
200         mTextureBaseLevelSize = 1 << (mLevels - 1);
201         // since we testing ETC texture, the minimum block size is 4.
202         mLevels -= 2;
203         ASSERT_TRUE(mLevels > 0);
204 
205         mTextures.resize(params.iterationsPerStep);
206         glGenTextures(params.iterationsPerStep, mTextures.data());
207         for (unsigned int i = 0; i < params.iterationsPerStep; ++i)
208         {
209             glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[i]);
210             glTexStorage2D(GL_TEXTURE_CUBE_MAP, mLevels, GL_COMPRESSED_RGB8_ETC2,
211                            mTextureBaseLevelSize, mTextureBaseLevelSize);
212             glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
213             glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
214             glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
215             glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
216         }
217         glActiveTexture(GL_TEXTURE0);
218         ASSERT_GL_NO_ERROR();
219     }
220 
destroyBenchmark()221     void destroyBenchmark()
222     {
223         TextureUploadBenchmarkBase::destroyBenchmark();
224         glDeleteTextures(static_cast<GLsizei>(mTextures.size()), mTextures.data());
225     }
226 
227     void drawBenchmark() override;
228 
229     void initShaders();
230 
231   public:
232     GLsizei mTextureBaseLevelSize;
233     GLsizei mLevels;
234     std::vector<GLuint> mTextures;
235 };
236 
initShaders()237 void TextureUploadETC2TranscodingBenchmark::initShaders()
238 {
239     constexpr char kVS[] = R"(#version 300 es
240 in vec4 a_position;
241 void main()
242 {
243     gl_Position = a_position;
244 })";
245 
246     constexpr char kFS[] = R"(#version 300 es
247 precision mediump float;
248 uniform samplerCube texCube;
249 out vec4 FragColor;
250 void main()
251 {
252     FragColor = texture(texCube, vec3(1.0f, 1.0f, 1.0f));
253 })";
254 
255     mProgram = CompileProgram(kVS, kFS);
256     ASSERT_NE(0u, mProgram);
257 
258     mPositionLoc = glGetAttribLocation(mProgram, "a_position");
259     mSamplerLoc  = glGetUniformLocation(mProgram, "texCube");
260     glUseProgram(mProgram);
261     glUniform1i(mSamplerLoc, 0);
262 
263     glDisable(GL_DEPTH_TEST);
264 
265     ASSERT_GL_NO_ERROR();
266 }
267 
drawBenchmark()268 void TextureUploadETC2TranscodingBenchmark::drawBenchmark()
269 {
270     const auto &params = GetParam();
271     startGpuTimer();
272     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
273     {
274         glBindTexture(GL_TEXTURE_CUBE_MAP, mTextures[iteration]);
275         GLsizei size = mTextureBaseLevelSize;
276         for (GLint level = 0; level < mLevels; ++level)
277         {
278             for (GLenum face = GL_TEXTURE_CUBE_MAP_POSITIVE_X;
279                  face <= GL_TEXTURE_CUBE_MAP_NEGATIVE_Z; ++face)
280             {
281                 glCompressedTexSubImage2D(face, level, 0, 0, size, size, GL_COMPRESSED_RGB8_ETC2,
282                                           size / 4 * size / 4 * 8, garden_etc2_rgba8);
283             }
284             size >>= 1;
285         }
286         // Perform a draw just so the texture data is flushed.  With the position attributes not
287         // set, a constant default value is used, resulting in a very cheap draw.
288         glDrawArrays(GL_TRIANGLES, 0, 3);
289     }
290     stopGpuTimer();
291 }
292 
TextureUploadBenchmarkBase(const char * benchmarkName)293 TextureUploadBenchmarkBase::TextureUploadBenchmarkBase(const char *benchmarkName)
294     : ANGLERenderTest(benchmarkName, GetParam())
295 {
296     setWebGLCompatibilityEnabled(GetParam().webgl);
297     setRobustResourceInit(GetParam().webgl);
298 
299     if (GetParam().getRenderer() == EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE)
300     {
301         skipTest("http://crbug.com/945415 Crashes on nvidia+d3d11");
302     }
303 }
304 
initializeBenchmark()305 void TextureUploadBenchmarkBase::initializeBenchmark()
306 {
307     const auto &params = GetParam();
308 
309     initShaders();
310     glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
311     glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
312 
313     glActiveTexture(GL_TEXTURE0);
314     glGenTextures(1, &mTexture);
315     glBindTexture(GL_TEXTURE_2D, mTexture);
316 
317     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
318     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
319     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
320     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
321 
322     ASSERT_TRUE(params.baseSize >= params.subImageSize);
323     mTextureData.resize(params.baseSize * params.baseSize * 4, 0.5);
324 
325     ASSERT_GL_NO_ERROR();
326 }
327 
initShaders()328 void TextureUploadBenchmarkBase::initShaders()
329 {
330     constexpr char kVS[] = R"(attribute vec4 a_position;
331 void main()
332 {
333     gl_Position = a_position;
334 })";
335 
336     constexpr char kFS[] = R"(precision mediump float;
337 uniform sampler2D s_texture;
338 void main()
339 {
340     gl_FragColor = texture2D(s_texture, vec2(0, 0));
341 })";
342 
343     mProgram = CompileProgram(kVS, kFS);
344     ASSERT_NE(0u, mProgram);
345 
346     mPositionLoc = glGetAttribLocation(mProgram, "a_position");
347     mSamplerLoc  = glGetUniformLocation(mProgram, "s_texture");
348     glUseProgram(mProgram);
349     glUniform1i(mSamplerLoc, 0);
350 
351     glDisable(GL_DEPTH_TEST);
352 
353     ASSERT_GL_NO_ERROR();
354 }
355 
destroyBenchmark()356 void TextureUploadBenchmarkBase::destroyBenchmark()
357 {
358     glDeleteTextures(1, &mTexture);
359     glDeleteProgram(mProgram);
360 }
361 
drawBenchmark()362 void TextureUploadSubImageBenchmark::drawBenchmark()
363 {
364     const auto &params = GetParam();
365 
366     startGpuTimer();
367     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
368     {
369         glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
370                         rand() % (params.baseSize - params.subImageSize), params.subImageSize,
371                         params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, mTextureData.data());
372 
373         // Perform a draw just so the texture data is flushed.  With the position attributes not
374         // set, a constant default value is used, resulting in a very cheap draw.
375         glDrawArrays(GL_TRIANGLES, 0, 3);
376     }
377     stopGpuTimer();
378 
379     ASSERT_GL_NO_ERROR();
380 }
381 
drawBenchmark()382 void TextureUploadFullMipBenchmark::drawBenchmark()
383 {
384     const auto &params = GetParam();
385 
386     startGpuTimer();
387     for (size_t it = 0; it < params.iterationsPerStep; ++it)
388     {
389         // Stage data for all mips
390         GLint mip = 0;
391         for (GLsizei levelSize = params.baseSize; levelSize > 0; levelSize >>= 1)
392         {
393             glTexImage2D(GL_TEXTURE_2D, mip++, GL_RGBA, levelSize, levelSize, 0, GL_RGBA,
394                          GL_UNSIGNED_BYTE, mTextureData.data());
395         }
396 
397         // Perform a draw just so the texture data is flushed.  With the position attributes not
398         // set, a constant default value is used, resulting in a very cheap draw.
399         glDrawArrays(GL_TRIANGLES, 0, 3);
400     }
401     stopGpuTimer();
402 
403     ASSERT_GL_NO_ERROR();
404 }
405 
drawBenchmark()406 void PBOSubImageBenchmark::drawBenchmark()
407 {
408     const auto &params = GetParam();
409 
410     startGpuTimer();
411     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
412     {
413         glTexSubImage2D(GL_TEXTURE_2D, 0, rand() % (params.baseSize - params.subImageSize),
414                         rand() % (params.baseSize - params.subImageSize), params.subImageSize,
415                         params.subImageSize, GL_RGBA, GL_UNSIGNED_BYTE, 0);
416 
417         // Perform a draw just so the texture data is flushed.  With the position attributes not
418         // set, a constant default value is used, resulting in a very cheap draw.
419         glDrawArrays(GL_TRIANGLES, 0, 3);
420     }
421     stopGpuTimer();
422 
423     ASSERT_GL_NO_ERROR();
424 }
425 
drawBenchmark()426 void PBOCompressedSubImageBenchmark::drawBenchmark()
427 {
428     const auto &params = GetParam();
429 
430     startGpuTimer();
431     for (unsigned int iteration = 0; iteration < params.iterationsPerStep; ++iteration)
432     {
433         glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, params.subImageSize, params.subImageSize,
434                                   GL_COMPRESSED_RGB8_ETC2,
435                                   params.subImageSize * params.subImageSize / 2, 0);
436 
437         // Perform a draw just so the texture data is flushed.  With the position attributes not
438         // set, a constant default value is used, resulting in a very cheap draw.
439         glDrawArrays(GL_TRIANGLES, 0, 3);
440     }
441     stopGpuTimer();
442 
443     ASSERT_GL_NO_ERROR();
444 }
445 
D3D11Params(bool webglCompat)446 TextureUploadParams D3D11Params(bool webglCompat)
447 {
448     TextureUploadParams params;
449     params.eglParameters = egl_platform::D3D11();
450     params.webgl         = webglCompat;
451     return params;
452 }
453 
MetalParams(bool webglCompat)454 TextureUploadParams MetalParams(bool webglCompat)
455 {
456     TextureUploadParams params;
457     params.eglParameters = egl_platform::METAL();
458     params.webgl         = webglCompat;
459     return params;
460 }
461 
OpenGLOrGLESParams(bool webglCompat)462 TextureUploadParams OpenGLOrGLESParams(bool webglCompat)
463 {
464     TextureUploadParams params;
465     params.eglParameters = egl_platform::OPENGL_OR_GLES();
466     params.webgl         = webglCompat;
467     return params;
468 }
469 
VulkanParams(bool webglCompat)470 TextureUploadParams VulkanParams(bool webglCompat)
471 {
472     TextureUploadParams params;
473     params.eglParameters = egl_platform::VULKAN();
474     params.webgl         = webglCompat;
475     return params;
476 }
477 
ES3VulkanParams(bool webglCompat)478 TextureUploadParams ES3VulkanParams(bool webglCompat)
479 {
480     TextureUploadParams params;
481     params.eglParameters = egl_platform::VULKAN();
482     params.webgl         = webglCompat;
483     params.majorVersion  = 3;
484     params.minorVersion  = 0;
485     params.enable(Feature::SupportsComputeTranscodeEtcToBc);
486     params.iterationsPerStep = 16;
487     params.baseSize          = 256;
488     return params;
489 }
490 
MetalPBOParams(GLsizei baseSize,GLsizei subImageSize)491 TextureUploadParams MetalPBOParams(GLsizei baseSize, GLsizei subImageSize)
492 {
493     TextureUploadParams params;
494     params.eglParameters = egl_platform::METAL();
495     params.webgl         = false;
496     params.trackGpuTime  = false;
497     params.baseSize      = baseSize;
498     params.subImageSize  = subImageSize;
499     return params;
500 }
501 
VulkanPBOParams(GLsizei baseSize,GLsizei subImageSize)502 TextureUploadParams VulkanPBOParams(GLsizei baseSize, GLsizei subImageSize)
503 {
504     TextureUploadParams params;
505     params.eglParameters = egl_platform::VULKAN();
506     params.webgl         = false;
507     params.trackGpuTime  = false;
508     params.baseSize      = baseSize;
509     params.subImageSize  = subImageSize;
510     return params;
511 }
512 
ES3OpenGLPBOParams(GLsizei baseSize,GLsizei subImageSize)513 TextureUploadParams ES3OpenGLPBOParams(GLsizei baseSize, GLsizei subImageSize)
514 {
515     TextureUploadParams params;
516     params.eglParameters = egl_platform::OPENGL();
517     params.majorVersion  = 3;
518     params.minorVersion  = 0;
519     params.webgl         = false;
520     params.trackGpuTime  = false;
521     params.baseSize      = baseSize;
522     params.subImageSize  = subImageSize;
523     return params;
524 }
525 
526 }  // anonymous namespace
527 
528 // Test etc to bc transcoding performance.
TEST_P(TextureUploadETC2TranscodingBenchmark,Run)529 TEST_P(TextureUploadETC2TranscodingBenchmark, Run)
530 {
531     run();
532 }
533 
TEST_P(TextureUploadSubImageBenchmark,Run)534 TEST_P(TextureUploadSubImageBenchmark, Run)
535 {
536     run();
537 }
538 
TEST_P(TextureUploadFullMipBenchmark,Run)539 TEST_P(TextureUploadFullMipBenchmark, Run)
540 {
541     run();
542 }
543 
TEST_P(PBOSubImageBenchmark,Run)544 TEST_P(PBOSubImageBenchmark, Run)
545 {
546     run();
547 }
548 
TEST_P(PBOCompressedSubImageBenchmark,Run)549 TEST_P(PBOCompressedSubImageBenchmark, Run)
550 {
551     run();
552 }
553 
554 using namespace params;
555 
556 ANGLE_INSTANTIATE_TEST(TextureUploadSubImageBenchmark,
557                        D3D11Params(false),
558                        D3D11Params(true),
559                        MetalParams(false),
560                        MetalParams(true),
561                        OpenGLOrGLESParams(false),
562                        OpenGLOrGLESParams(true),
563                        VulkanParams(false),
564                        NullDevice(VulkanParams(false)),
565                        VulkanParams(true));
566 
567 ANGLE_INSTANTIATE_TEST(TextureUploadETC2TranscodingBenchmark, ES3VulkanParams(false));
568 
569 ANGLE_INSTANTIATE_TEST(TextureUploadFullMipBenchmark,
570                        D3D11Params(false),
571                        D3D11Params(true),
572                        MetalParams(false),
573                        MetalParams(true),
574                        OpenGLOrGLESParams(false),
575                        OpenGLOrGLESParams(true),
576                        VulkanParams(false),
577                        VulkanParams(true));
578 
579 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PBOSubImageBenchmark);
580 ANGLE_INSTANTIATE_TEST(PBOSubImageBenchmark,
581                        ES3OpenGLPBOParams(1024, 128),
582                        MetalPBOParams(1024, 128),
583                        VulkanPBOParams(1024, 128));
584 
585 GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(PBOCompressedSubImageBenchmark);
586 ANGLE_INSTANTIATE_TEST(PBOCompressedSubImageBenchmark,
587                        ES3OpenGLPBOParams(128, 128),
588                        MetalPBOParams(128, 128),
589                        VulkanPBOParams(128, 128));
590