Commit 90080e3b by apatrick@chromium.org

Support for serializing a linked program to binary.

The format has a text section followed by a binary section. The binary section contains an image of the device caps and the two shader executables. The text section has everything else newline deliminated. Ran WebGL conformance tests with temporary change to glLinkProgram that round trips all linked programs through glGetProgramBinary and glProgramBinary. No regressions. Review URL: https://codereview.appspot.com/6295092 git-svn-id: https://angleproject.googlecode.com/svn/trunk@1199 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent 68b3e91c
#define MAJOR_VERSION 1
#define MINOR_VERSION 0
#define BUILD_VERSION 0
#define BUILD_REVISION 1196
#define BUILD_REVISION 1199
#define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x)
......
......@@ -298,10 +298,18 @@ ProgramBinary* Program::getProgramBinary()
return mProgramBinary;
}
void Program::setProgramBinary(ProgramBinary *programBinary)
void Program::setProgramBinary(const void *binary, GLsizei length)
{
unlink(false);
mProgramBinary = programBinary;
mInfoLog.reset();
mProgramBinary = new ProgramBinary;
if (!mProgramBinary->load(mInfoLog, binary, length))
{
delete mProgramBinary;
mProgramBinary = NULL;
}
}
void Program::release()
......@@ -329,6 +337,18 @@ unsigned int Program::getSerial() const
return mSerial;
}
GLint Program::getProgramBinaryLength() const
{
if (mProgramBinary)
{
return mProgramBinary->getLength();
}
else
{
return 0;
}
}
unsigned int Program::issueSerial()
{
return mCurrentSerial++;
......
......@@ -69,7 +69,7 @@ class Program
void bindAttributeLocation(GLuint index, const char *name);
void link();
void setProgramBinary(ProgramBinary *programBinary);
void setProgramBinary(const void *binary, GLsizei length);
ProgramBinary *getProgramBinary();
int getInfoLogLength() const;
......@@ -95,6 +95,8 @@ class Program
unsigned int getSerial() const;
GLint getProgramBinaryLength() const;
private:
DISALLOW_COPY_AND_ASSIGN(Program);
......
......@@ -7,10 +7,13 @@
// Program.cpp: Implements the gl::Program class. Implements GL program objects
// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
#include <sstream>
#include "libGLESv2/Program.h"
#include "libGLESv2/ProgramBinary.h"
#include "common/debug.h"
#include "common/version.h"
#include "libGLESv2/main.h"
#include "libGLESv2/Shader.h"
......@@ -1585,6 +1588,291 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::
return true;
}
bool ProgramBinary::load(InfoLog &infoLog, const void *binary, GLsizei length)
{
std::istringstream stream((const char*) binary, length);
stream >> std::boolalpha;
int format = 0;
stream >> format;
if (format != GL_PROGRAM_BINARY_ANGLE)
{
infoLog.append("Invalid program binary format.");
return false;
}
int version = 0;
stream >> version;
if (version != BUILD_REVISION)
{
infoLog.append("Invalid program binary version.");
return false;
}
for (int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
stream >> mLinkedAttribute[i].type;
std::string name;
stream >> name;
mLinkedAttribute[i].name = name.substr(1, name.length() - 2);
stream >> mSemanticIndex[i];
}
for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
{
stream >> mSamplersPS[i].active;
stream >> mSamplersPS[i].logicalTextureUnit;
int textureType;
stream >> textureType;
mSamplersPS[i].textureType = (TextureType) textureType;
}
for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
{
stream >> mSamplersVS[i].active;
stream >> mSamplersVS[i].logicalTextureUnit;
int textureType;
stream >> textureType;
mSamplersVS[i].textureType = (TextureType) textureType;
}
stream >> mUsedVertexSamplerRange;
stream >> mUsedPixelSamplerRange;
unsigned int size;
stream >> size;
if (!stream.good())
{
infoLog.append("Invalid program binary.");
return false;
}
mUniforms.resize(size);
for (unsigned int i = 0; i < size; ++i)
{
GLenum type;
std::string _name;
unsigned int arraySize;
stream >> type >> _name >> arraySize;
mUniforms[i] = new Uniform(type, _name.substr(1, _name.length() - 2), arraySize);
stream >> mUniforms[i]->ps.float4Index;
stream >> mUniforms[i]->ps.samplerIndex;
stream >> mUniforms[i]->ps.boolIndex;
stream >> mUniforms[i]->ps.registerCount;
stream >> mUniforms[i]->vs.float4Index;
stream >> mUniforms[i]->vs.samplerIndex;
stream >> mUniforms[i]->vs.boolIndex;
stream >> mUniforms[i]->vs.registerCount;
}
stream >> size;
if (!stream.good())
{
infoLog.append("Invalid program binary.");
return false;
}
mUniformIndex.resize(size);
for (unsigned int i = 0; i < size; ++i)
{
std::string name;
stream >> name;
mUniformIndex[i].name = name.substr(1, name.length() - 2);
stream >> mUniformIndex[i].element;
stream >> mUniformIndex[i].index;
}
stream >> mDxDepthRangeLocation;
stream >> mDxDepthLocation;
stream >> mDxCoordLocation;
stream >> mDxHalfPixelSizeLocation;
stream >> mDxFrontCCWLocation;
stream >> mDxPointsOrLinesLocation;
unsigned int pixelShaderSize;
stream >> pixelShaderSize;
unsigned int vertexShaderSize;
stream >> vertexShaderSize;
// Skip final newline.
stream.ignore(1);
const char *ptr = (const char*) binary + stream.tellg();
const D3DCAPS9 *binaryIdentifier = (const D3DCAPS9*) ptr;
ptr += sizeof(GUID);
D3DADAPTER_IDENTIFIER9 *currentIdentifier = getDisplay()->getAdapterIdentifier();
if (memcmp(&currentIdentifier->DeviceIdentifier, binaryIdentifier, sizeof(GUID)) != 0)
{
infoLog.append("Invalid program binary.");
return false;
}
const char *pixelShaderFunction = ptr;
ptr += pixelShaderSize;
const char *vertexShaderFunction = ptr;
ptr += vertexShaderSize;
HRESULT result = mDevice->CreatePixelShader(reinterpret_cast<const DWORD*>(pixelShaderFunction), &mPixelExecutable);
if (FAILED(result))
{
infoLog.append("Could not create pixel shader.");
return false;
}
result = mDevice->CreateVertexShader(reinterpret_cast<const DWORD*>(vertexShaderFunction), &mVertexExecutable);
if (FAILED(result))
{
infoLog.append("Could not create vertex shader.");
mPixelExecutable->Release();
mPixelExecutable = NULL;
return false;
}
return true;
}
bool ProgramBinary::save(void* binary, GLsizei bufSize, GLsizei *length)
{
std::ostringstream stream;
stream << std::boolalpha;
stream << GL_PROGRAM_BINARY_ANGLE << std::endl;
stream << BUILD_REVISION << std::endl;
for (unsigned int i = 0; i < MAX_VERTEX_ATTRIBS; ++i)
{
stream << mLinkedAttribute[i].type << std::endl;
stream << "\"" << mLinkedAttribute[i].name << "\"" << std::endl;
stream << mSemanticIndex[i] << std::endl << std::endl;
}
for (unsigned int i = 0; i < MAX_TEXTURE_IMAGE_UNITS; ++i)
{
stream << mSamplersPS[i].active << std::endl;
stream << mSamplersPS[i].logicalTextureUnit << std::endl;
stream << (int) mSamplersPS[i].textureType << std::endl << std::endl;
}
for (unsigned int i = 0; i < MAX_VERTEX_TEXTURE_IMAGE_UNITS_VTF; ++i)
{
stream << mSamplersVS[i].active << std::endl;
stream << mSamplersVS[i].logicalTextureUnit << std::endl;
stream << (int) mSamplersVS[i].textureType << std::endl << std::endl;
}
stream << mUsedVertexSamplerRange << std::endl;
stream << mUsedPixelSamplerRange << std::endl << std::endl;
stream << mUniforms.size() << std::endl;
for (unsigned int i = 0; i < mUniforms.size(); ++i)
{
stream << mUniforms[i]->type << std::endl;
stream << "\"" << mUniforms[i]->_name << "\"" << std::endl;
stream << mUniforms[i]->arraySize << std::endl << std::endl;
stream << mUniforms[i]->ps.float4Index << std::endl;
stream << mUniforms[i]->ps.samplerIndex << std::endl;
stream << mUniforms[i]->ps.boolIndex << std::endl;
stream << mUniforms[i]->ps.registerCount << std::endl;
stream << mUniforms[i]->vs.float4Index << std::endl;
stream << mUniforms[i]->vs.samplerIndex << std::endl;
stream << mUniforms[i]->vs.boolIndex << std::endl;
stream << mUniforms[i]->vs.registerCount << std::endl;
}
stream << mUniformIndex.size() << std::endl;
for (unsigned int i = 0; i < mUniformIndex.size(); ++i)
{
stream << "\"" << mUniformIndex[i].name << "\"" << std::endl;
stream << mUniformIndex[i].element << std::endl;
stream << mUniformIndex[i].index << std::endl << std::endl;
}
stream << mDxDepthRangeLocation << std::endl;
stream << mDxDepthLocation << std::endl;
stream << mDxCoordLocation << std::endl;
stream << mDxHalfPixelSizeLocation << std::endl;
stream << mDxFrontCCWLocation << std::endl;
stream << mDxPointsOrLinesLocation << std::endl;
UINT pixelShaderSize;
HRESULT result = mPixelExecutable->GetFunction(NULL, &pixelShaderSize);
ASSERT(SUCCEEDED(result));
stream << pixelShaderSize << std::endl;
UINT vertexShaderSize;
result = mVertexExecutable->GetFunction(NULL, &vertexShaderSize);
ASSERT(SUCCEEDED(result));
stream << vertexShaderSize << std::endl;
std::string text = stream.str();
D3DADAPTER_IDENTIFIER9 *identifier = getDisplay()->getAdapterIdentifier();
GLsizei totalLength = text.length() + sizeof(GUID) + pixelShaderSize + vertexShaderSize;
if (totalLength > bufSize)
{
if (length)
{
*length = 0;
}
return false;
}
if (binary)
{
char *ptr = (char*) binary;
memcpy(ptr, text.c_str(), text.length());
ptr += text.length();
memcpy(ptr, &identifier->DeviceIdentifier, sizeof(GUID));
ptr += sizeof(GUID);
result = mPixelExecutable->GetFunction(ptr, &pixelShaderSize);
ASSERT(SUCCEEDED(result));
ptr += pixelShaderSize;
result = mVertexExecutable->GetFunction(ptr, &vertexShaderSize);
ASSERT(SUCCEEDED(result));
ptr += vertexShaderSize;
ASSERT(ptr - totalLength == binary);
}
if (length)
{
*length = totalLength;
}
return true;
}
GLint ProgramBinary::getLength()
{
GLint length;
if (save(NULL, INT_MAX, &length))
{
return length;
}
else
{
return 0;
}
}
bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
{
if (!fragmentShader || !fragmentShader->isCompiled())
......@@ -2477,4 +2765,8 @@ GLint ProgramBinary::getDxPointsOrLinesLocation() const
return mDxPointsOrLinesLocation;
}
ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
{
}
}
......@@ -10,6 +10,10 @@
#ifndef LIBGLESV2_PROGRAM_BINARY_H_
#define LIBGLESV2_PROGRAM_BINARY_H_
#define GL_APICALL
#include <gles2/gl2.h>
#include <gles2/gl2ext.h>
#include <d3dx9.h>
#include <d3dcompiler.h>
#include <string>
......@@ -78,6 +82,10 @@ struct Uniform
// Struct used for correlating uniforms/elements of uniform arrays to handles
struct UniformLocation
{
UniformLocation()
{
}
UniformLocation(const std::string &_name, unsigned int element, unsigned int index);
std::string name;
......@@ -128,6 +136,10 @@ class ProgramBinary
void dirtyAllUniforms();
void applyUniforms();
bool load(InfoLog &infoLog, const void *binary, GLsizei length);
bool save(void* binary, GLsizei bufSize, GLsizei *length);
GLint getLength();
bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
......@@ -182,6 +194,8 @@ class ProgramBinary
struct Sampler
{
Sampler();
bool active;
GLint logicalTextureUnit;
TextureType textureType;
......
......@@ -3422,7 +3422,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params)
*params = programObject->getActiveUniformMaxLength();
return;
case GL_PROGRAM_BINARY_LENGTH_OES:
*params = 0;
*params = programObject->getProgramBinaryLength();
return;
default:
return error(GL_INVALID_ENUM);
......@@ -6818,7 +6818,7 @@ void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat
void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length,
GLenum *binaryFormat, void *binary)
{
EVENT("(GLenum program = 0x%X, bufSize = %s, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)",
EVENT("(GLenum program = 0x%X, bufSize = %d, length = 0x%0.8p, binaryFormat = 0x%0.8p, binary = 0x%0.8p)",
program, bufSize, length, binaryFormat, binary);
try
......@@ -6841,12 +6841,12 @@ void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *l
return error(GL_INVALID_OPERATION);
}
*binaryFormat = GL_PROGRAM_BINARY_ANGLE;
if (length)
if (!programBinary->save(binary, bufSize, length))
{
*length = 0;
return error(GL_INVALID_OPERATION);
}
*binaryFormat = GL_PROGRAM_BINARY_ANGLE;
}
}
catch(std::bad_alloc&)
......@@ -6879,7 +6879,7 @@ void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
return error(GL_INVALID_OPERATION);
}
programObject->setProgramBinary(NULL);
programObject->setProgramBinary(binary, length);
}
}
catch(std::bad_alloc&)
......
......@@ -170,6 +170,8 @@ EXPORTS
glVertexAttribDivisorANGLE @172
glDrawArraysInstancedANGLE @173
glDrawElementsInstancedANGLE @174
glProgramBinaryOES @175
glGetProgramBinaryOES @176
; EGL dependencies
glCreateContext @144 NONAME
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment