mirror of
https://github.com/bnmgh1/NodeSandbox.git
synced 2025-04-21 01:00:09 +08:00
279 lines
9.7 KiB
C++
279 lines
9.7 KiB
C++
//
|
|
// Copyright (c) 2014 The ANGLE Project Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style license that can be
|
|
// found in the LICENSE file.
|
|
//
|
|
|
|
// Based on Hello_Triangle.c from
|
|
// Book: OpenGL(R) ES 2.0 Programming Guide
|
|
// Authors: Aaftab Munshi, Dan Ginsburg, Dave Shreiner
|
|
// ISBN-10: 0321502795
|
|
// ISBN-13: 9780321502797
|
|
// Publisher: Addison-Wesley Professional
|
|
// URLs: http://safari.informit.com/9780321563835
|
|
// http://www.opengles-book.com
|
|
|
|
#include "SampleApplication.h"
|
|
#include "shader_utils.h"
|
|
#include "texture_utils.h"
|
|
|
|
#include <cstring>
|
|
#include <iostream>
|
|
|
|
// This sample demonstrates the differences in rendering efficiency when
|
|
// drawing with already-created textures whose dimensions have been altered
|
|
// versus drawing with newly created textures.
|
|
//
|
|
// In order to support GL's per-level texture creation semantics over the
|
|
// D3D API in particular, which requires textures' full mip chains to be
|
|
// created at texture object creation time, ANGLE maintains copies of the
|
|
// constituent texture images in system memory until the texture is used in
|
|
// a draw call, at which time, if the texture passes GL's mip completeness
|
|
// rules, the D3D texture is created and the contents of the texture are
|
|
// uploaded. Once the texture is created, redefinition of the dimensions or
|
|
// format of the texture is costly-- a new D3D texture needs to be created,
|
|
// and ANGLE may need to read the contents back into system memory.
|
|
//
|
|
// Creating an entirely new texture also requires that a new D3D texture be
|
|
// created, but any overhead associated with tracking the already-present
|
|
// texture images is eliminated, as it's a novel texture. This sample
|
|
// demonstrates the contrast in draw call time between these two situations.
|
|
//
|
|
// The resizing & creation of a new texture is delayed until several frames
|
|
// after startup, to eliminate draw time differences caused by caching of
|
|
// rendering state subsequent to the first frame.
|
|
|
|
class TexRedefBenchSample : public SampleApplication
|
|
{
|
|
public:
|
|
TexRedefBenchSample()
|
|
: SampleApplication("Microbench", 1280, 1280),
|
|
mPixelsResize(NULL), mPixelsNewTex(NULL), mTimeFrame(false), mFrameCount(0)
|
|
{
|
|
}
|
|
|
|
void defineSquareTexture2D(GLuint texId, GLsizei baseDimension, GLenum format, GLenum type, void* data)
|
|
{
|
|
glBindTexture(GL_TEXTURE_2D, texId);
|
|
GLsizei curDim = baseDimension;
|
|
GLuint level = 0;
|
|
|
|
while (curDim >= 1)
|
|
{
|
|
glTexImage2D(GL_TEXTURE_2D, level, format, curDim, curDim, 0, format, type, data);
|
|
curDim /= 2;
|
|
level++;
|
|
}
|
|
}
|
|
|
|
void createPixelData()
|
|
{
|
|
mPixelsResize = new GLubyte[512 * 512 * 4];
|
|
mPixelsNewTex = new GLubyte[512 * 512 * 4];
|
|
GLubyte *pixPtr0 = mPixelsResize;
|
|
GLubyte *pixPtr1 = mPixelsNewTex;
|
|
GLubyte zeroPix[] = { 0, 192, 192, 255 };
|
|
GLubyte onePix[] = { 192, 0, 0, 255 };
|
|
for (int i = 0; i < 512 * 512; ++i)
|
|
{
|
|
memcpy(pixPtr0, zeroPix, 4 * sizeof(GLubyte));
|
|
memcpy(pixPtr1, onePix, 4 * sizeof(GLubyte));
|
|
pixPtr0 += 4;
|
|
pixPtr1 += 4;
|
|
}
|
|
}
|
|
|
|
virtual bool initialize()
|
|
{
|
|
const std::string vs = SHADER_SOURCE
|
|
(
|
|
attribute vec4 a_position;
|
|
attribute vec2 a_texCoord;
|
|
varying vec2 v_texCoord;
|
|
void main()
|
|
{
|
|
gl_Position = a_position;
|
|
v_texCoord = a_texCoord;
|
|
}
|
|
);
|
|
|
|
const std::string fs = SHADER_SOURCE
|
|
(
|
|
precision mediump float;
|
|
varying vec2 v_texCoord;
|
|
uniform sampler2D s_texture;
|
|
void main()
|
|
{
|
|
gl_FragColor = texture2D(s_texture, v_texCoord);
|
|
}
|
|
);
|
|
|
|
mProgram = CompileProgram(vs, fs);
|
|
if (!mProgram)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
// Get the attribute locations
|
|
mPositionLoc = glGetAttribLocation(mProgram, "a_position");
|
|
mTexCoordLoc = glGetAttribLocation(mProgram, "a_texCoord");
|
|
|
|
// Get the sampler location
|
|
mSamplerLoc = glGetUniformLocation(mProgram, "s_texture");
|
|
|
|
// Generate texture IDs, and create texture 0
|
|
glGenTextures(3, mTextureIds);
|
|
|
|
createPixelData();
|
|
defineSquareTexture2D(mTextureIds[0], 256, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsResize);
|
|
|
|
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|
|
|
mOrigTimer = CreateTimer();
|
|
mResizeDrawTimer = CreateTimer();
|
|
mResizeDefineTimer = CreateTimer();
|
|
mNewTexDrawTimer = CreateTimer();
|
|
mNewTexDefineTimer = CreateTimer();
|
|
|
|
return true;
|
|
}
|
|
|
|
virtual void destroy()
|
|
{
|
|
glDeleteProgram(mProgram);
|
|
|
|
delete [] mPixelsResize;
|
|
delete [] mPixelsNewTex;
|
|
}
|
|
|
|
virtual void draw()
|
|
{
|
|
GLfloat vertices[] =
|
|
{
|
|
-0.5f, 0.5f, 0.0f, // Position 0
|
|
0.0f, 0.0f, // TexCoord 0
|
|
-0.5f, -0.5f, 0.0f, // Position 1
|
|
0.0f, 1.0f, // TexCoord 1
|
|
0.5f, -0.5f, 0.0f, // Position 2
|
|
1.0f, 1.0f, // TexCoord 2
|
|
0.5f, 0.5f, 0.0f, // Position 3
|
|
1.0f, 0.0f // TexCoord 3
|
|
};
|
|
GLushort indices[] = { 0, 1, 2, 0, 2, 3 };
|
|
|
|
// Set the viewport
|
|
glViewport(0, 0, getWindow()->getWidth(), getWindow()->getHeight());
|
|
|
|
// Clear the color buffer
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Use the program object
|
|
glUseProgram(mProgram);
|
|
|
|
// Load the vertex position
|
|
glVertexAttribPointer(mPositionLoc, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices);
|
|
// Load the texture coordinate
|
|
glVertexAttribPointer(mTexCoordLoc, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), vertices + 3);
|
|
|
|
glEnableVertexAttribArray(mPositionLoc);
|
|
glEnableVertexAttribArray(mTexCoordLoc);
|
|
|
|
// Bind the texture
|
|
glActiveTexture(GL_TEXTURE0);
|
|
glBindTexture(GL_TEXTURE_2D, mTextureIds[0]);
|
|
|
|
// Set the texture sampler to texture unit to 0
|
|
glUniform1i(mSamplerLoc, 0);
|
|
|
|
// We delay timing of texture resize/creation until after the first frame, as
|
|
// caching optimizations will reduce draw time for subsequent frames for reasons
|
|
// unreleated to texture creation. mTimeFrame is set to true on the fifth frame.
|
|
if (mTimeFrame)
|
|
{
|
|
mOrigTimer->start();
|
|
}
|
|
|
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
|
|
|
if (mTimeFrame)
|
|
{
|
|
mOrigTimer->stop();
|
|
// This timer indicates draw time for an already-created texture resident on the GPU, which
|
|
// needs no updates. It will be faster than the other draws.
|
|
std::cout << "Original texture draw: " << mOrigTimer->getElapsedTime() * 1000 << "msec" << std::endl;
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Now, change the texture dimensions of the original texture
|
|
mResizeDefineTimer->start();
|
|
defineSquareTexture2D(mTextureIds[0], 512, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsResize);
|
|
mResizeDefineTimer->stop();
|
|
|
|
mResizeDrawTimer->start();
|
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
|
mResizeDrawTimer->stop();
|
|
// This timer indicates draw time for a texture which has already been used in a draw, causing the
|
|
// underlying resource to be allocated, and then resized, requiring resource reallocation and
|
|
// related overhead.
|
|
std::cout << "Resized texture definition: " << mResizeDefineTimer->getElapsedTime() * 1000 << "msec" << std::endl;
|
|
std::cout << "Resized texture draw: " << mResizeDrawTimer->getElapsedTime() * 1000 << "msec" << std::endl;
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
// Create texure at same dimensions we resized previous texture to
|
|
mNewTexDefineTimer->start();
|
|
defineSquareTexture2D(mTextureIds[1], 512, GL_RGBA, GL_UNSIGNED_BYTE, mPixelsNewTex);
|
|
mNewTexDefineTimer->stop();
|
|
|
|
mNewTexDrawTimer->start();
|
|
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
|
|
mNewTexDrawTimer->stop();
|
|
// This timer indicates draw time for a texture newly created this frame. The underlying resource
|
|
// will need to be created, but because it has not previously been used, there is no already-resident
|
|
// texture object to manage. This draw is expected to be faster than the resized texture draw.
|
|
std::cout << "Newly created texture definition: " << mNewTexDefineTimer->getElapsedTime() * 1000 << "msec" << std::endl;
|
|
std::cout << "Newly created texture draw: " << mNewTexDrawTimer->getElapsedTime() * 1000 << "msec" << std::endl;
|
|
}
|
|
|
|
if (mFrameCount == 5)
|
|
mTimeFrame = true;
|
|
else
|
|
mTimeFrame = false;
|
|
|
|
mFrameCount++;
|
|
}
|
|
|
|
private:
|
|
// Handle to a program object
|
|
GLuint mProgram;
|
|
|
|
// Attribute locations
|
|
GLint mPositionLoc;
|
|
GLint mTexCoordLoc;
|
|
|
|
// Sampler location
|
|
GLint mSamplerLoc;
|
|
|
|
// Texture handle
|
|
GLuint mTextureIds[2]; // 0: texture created, then resized
|
|
// 1: texture newly created with TexImage
|
|
|
|
// Texture pixel data
|
|
GLubyte *mPixelsResize;
|
|
GLubyte *mPixelsNewTex;
|
|
|
|
Timer *mOrigTimer;
|
|
Timer *mResizeDrawTimer;
|
|
Timer *mResizeDefineTimer;
|
|
Timer *mNewTexDrawTimer;
|
|
Timer *mNewTexDefineTimer;
|
|
bool mTimeFrame;
|
|
unsigned int mFrameCount;
|
|
};
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
TexRedefBenchSample app;
|
|
return app.run();
|
|
}
|