1 //
2 // Copyright 2014 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 
7 //            Based on Hello_Triangle.c from
8 // Book:      OpenGL(R) ES 2.0 Programming Guide
9 // Authors:   Aaftab Munshi, Dan Ginsburg, Dave Shreiner
10 // ISBN-10:   0321502795
11 // ISBN-13:   9780321502797
12 // Publisher: Addison-Wesley Professional
13 // URLs:      http://safari.informit.com/9780321563835
14 //            http://www.opengles-book.com
15 
16 #include "SampleApplication.h"
17 
18 #include "texture_utils.h"
19 #include "util/shader_utils.h"
20 
21 #include <cstring>
22 #include <iostream>
23 
24 // This sample demonstrates the differences in rendering efficiency when
25 // drawing with already-created textures whose dimensions have been altered
26 // versus drawing with newly created textures.
27 //
28 // In order to support GL's per-level texture creation semantics over the
29 // D3D API in particular, which requires textures' full mip chains to be
30 // created at texture object creation time, ANGLE maintains copies of the
31 // constituent texture images in system memory until the texture is used in
32 // a draw call, at which time, if the texture passes GL's mip completeness
33 // rules, the D3D texture is created and the contents of the texture are
34 // uploaded. Once the texture is created, redefinition of the dimensions or
35 // format of the texture is costly-- a new D3D texture needs to be created,
36 // and ANGLE may need to read the contents back into system memory.
37 //
38 // Creating an entirely new texture also requires that a new D3D texture be
39 // created, but any overhead associated with tracking the already-present
40 // texture images is eliminated, as it's a novel texture. This sample
41 // demonstrates the contrast in draw call time between these two situations.
42 //
43 // The resizing & creation of a new texture is delayed until several frames
44 // after startup, to eliminate draw time differences caused by caching of
45 // rendering state subsequent to the first frame.
46 
47 class TexRedefBenchSample : public SampleApplication
48 {
49   public:
TexRedefBenchSample(int argc,char ** argv)50     TexRedefBenchSample(int argc, char **argv)
51         : SampleApplication("Microbench", argc, argv, 2, 0, 1280, 1280),
52           mPixelsResize(nullptr),
53           mPixelsNewTex(nullptr),
54           mTimeFrame(false),
55           mFrameCount(0)
56     {}
57 
defineSquareTexture2D(GLuint texId,GLsizei baseDimension,GLenum format,GLenum type,void * data)58     void defineSquareTexture2D(GLuint texId,
59                                GLsizei baseDimension,
60                                GLenum format,
61                                GLenum type,
62                                void *data)
63     {
64         glBindTexture(GL_TEXTURE_2D, texId);
65         GLsizei curDim = baseDimension;
66         GLuint level   = 0;
67 
68         while (curDim >= 1)
69         {
70             glTexImage2D(GL_TEXTURE_2D, level, format, curDim, curDim, 0, format, type, data);
71             curDim /= 2;
72             level++;
73         }
74     }
75 
createPixelData()76     void createPixelData()
77     {
78         mPixelsResize     = new GLubyte[512 * 512 * 4];
79         mPixelsNewTex     = new GLubyte[512 * 512 * 4];
80         GLubyte *pixPtr0  = mPixelsResize;
81         GLubyte *pixPtr1  = mPixelsNewTex;
82         GLubyte zeroPix[] = {0, 192, 192, 255};
83         GLubyte onePix[]  = {192, 0, 0, 255};
84         for (int i = 0; i < 512 * 512; ++i)
85         {
86             memcpy(pixPtr0, zeroPix, 4 * sizeof(GLubyte));
87             memcpy(pixPtr1, onePix, 4 * sizeof(GLubyte));
88             pixPtr0 += 4;
89             pixPtr1 += 4;
90         }
91     }
92 
initialize()93     bool initialize() override
94     {
95         constexpr char kVS[] = R"(attribute vec4 a_position;
96 attribute vec2 a_texCoord;
97 varying vec2 v_texCoord;
98 void main()
99 {
100     gl_Position = a_position;
101     v_texCoord = a_texCoord;
102 })";
103 
104         constexpr char kFS[] = R"(precision mediump float;
105 varying vec2 v_texCoord;
106 uniform sampler2D s_texture;
107 void main()
108 {
109     gl_FragColor = texture2D(s_texture, v_texCoord);
110 })";
111 
112         mProgram = CompileProgram(kVS, kFS);
113         if (!mProgram)
114         {
115             return false;
116         }
117 
118         // Get the attribute locations
119         mPositionLoc = glGetAttribLocation(mProgram, "a_position");
120         mTexCoordLoc = glGetAttribLocation(mProgram, "a_texCoord");
121 
122         // Get the sampler location
123         mSamplerLoc = glGetUniformLocation(mProgram, "s_texture");
124 
125         // Generate texture IDs, and create texture 0
126         glGenTextures(3, mTextureIds);
127 
128         createPixelData();
129         defineSquareTexture2D(mTextureIds[0], 256, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsResize);
130 
131         glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
132 
133         return true;
134     }
135 
destroy()136     void destroy() override
137     {
138         glDeleteProgram(mProgram);
139 
140         delete[] mPixelsResize;
141         delete[] mPixelsNewTex;
142     }
143 
draw()144     void draw() override
145     {
146         GLfloat vertices[] = {
147             -0.5f, 0.5f,  0.0f,  // Position 0
148             0.0f,  0.0f,         // TexCoord 0
149             -0.5f, -0.5f, 0.0f,  // Position 1
150             0.0f,  1.0f,         // TexCoord 1
151             0.5f,  -0.5f, 0.0f,  // Position 2
152             1.0f,  1.0f,         // TexCoord 2
153             0.5f,  0.5f,  0.0f,  // Position 3
154             1.0f,  0.0f          // TexCoord 3
155         };
156         GLushort indices[] = {0, 1, 2, 0, 2, 3};
157 
158         // Set the viewport
159         glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
160 
161         // Clear the color buffer
162         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
163 
164         // Use the program object
165         glUseProgram(mProgram);
166 
167         // Load the vertex position
168         glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
169         // Load the texture coordinate
170         glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat),
171                               vertices + 3);
172 
173         glEnableVertexAttribArray(mPositionLoc);
174         glEnableVertexAttribArray(mTexCoordLoc);
175 
176         // Bind the texture
177         glActiveTexture(GL_TEXTURE0);
178         glBindTexture(GL_TEXTURE_2D, mTextureIds[0]);
179 
180         // Set the texture sampler to texture unit to 0
181         glUniform1i(mSamplerLoc, 0);
182 
183         // We delay timing of texture resize/creation until after the first frame, as
184         // caching optimizations will reduce draw time for subsequent frames for reasons
185         // unreleated to texture creation. mTimeFrame is set to true on the fifth frame.
186         if (mTimeFrame)
187         {
188             mOrigTimer.start();
189         }
190 
191         glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
192 
193         if (mTimeFrame)
194         {
195             mOrigTimer.stop();
196             // This timer indicates draw time for an already-created texture resident on the GPU,
197             // which needs no updates. It will be faster than the other draws.
198             std::cout << "Original texture draw: " << mOrigTimer.getElapsedTime() * 1000 << "msec"
199                       << std::endl;
200 
201             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
202 
203             // Now, change the texture dimensions of the original texture
204             mResizeDefineTimer.start();
205             defineSquareTexture2D(mTextureIds[0], 512, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsResize);
206             mResizeDefineTimer.stop();
207 
208             mResizeDrawTimer.start();
209             glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
210             mResizeDrawTimer.stop();
211             // This timer indicates draw time for a texture which has already been used in a draw,
212             // causing the underlying resource to be allocated, and then resized, requiring resource
213             // reallocation and related overhead.
214             std::cout << "Resized texture definition: "
215                       << mResizeDefineTimer.getElapsedTime() * 1000 << "msec" << std::endl;
216             std::cout << "Resized texture draw: " << mResizeDrawTimer.getElapsedTime() * 1000
217                       << "msec" << std::endl;
218 
219             glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
220 
221             // Create texure at same dimensions we resized previous texture to
222             mNewTexDefineTimer.start();
223             defineSquareTexture2D(mTextureIds[1], 512, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsNewTex);
224             mNewTexDefineTimer.stop();
225 
226             mNewTexDrawTimer.start();
227             glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
228             mNewTexDrawTimer.stop();
229             // This timer indicates draw time for a texture newly created this frame. The underlying
230             // resource will need to be created, but because it has not previously been used, there
231             // is no already-resident texture object to manage. This draw is expected to be faster
232             // than the resized texture draw.
233             std::cout << "Newly created texture definition: "
234                       << mNewTexDefineTimer.getElapsedTime() * 1000 << "msec" << std::endl;
235             std::cout << "Newly created texture draw: " << mNewTexDrawTimer.getElapsedTime() * 1000
236                       << "msec" << std::endl;
237         }
238 
239         if (mFrameCount == 5)
240             mTimeFrame = true;
241         else
242             mTimeFrame = false;
243 
244         mFrameCount++;
245     }
246 
247   private:
248     // Handle to a program object
249     GLuint mProgram;
250 
251     // Attribute locations
252     GLint mPositionLoc;
253     GLint mTexCoordLoc;
254 
255     // Sampler location
256     GLint mSamplerLoc;
257 
258     // Texture handle
259     GLuint mTextureIds[2];  // 0: texture created, then resized
260                             // 1: texture newly created with TexImage
261 
262     // Texture pixel data
263     GLubyte *mPixelsResize;
264     GLubyte *mPixelsNewTex;
265 
266     Timer mOrigTimer;
267     Timer mResizeDrawTimer;
268     Timer mResizeDefineTimer;
269     Timer mNewTexDrawTimer;
270     Timer mNewTexDefineTimer;
271     bool mTimeFrame;
272     unsigned int mFrameCount;
273 };
274 
main(int argc,char ** argv)275 int main(int argc, char **argv)
276 {
277     TexRedefBenchSample app(argc, argv);
278     return app.run();
279 }
280