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 MAJOR_VERSION 1
#define MINOR_VERSION 0 #define MINOR_VERSION 0
#define BUILD_VERSION 0 #define BUILD_VERSION 0
#define BUILD_REVISION 1196 #define BUILD_REVISION 1199
#define STRINGIFY(x) #x #define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x) #define MACRO_STRINGIFY(x) STRINGIFY(x)
......
...@@ -298,10 +298,18 @@ ProgramBinary* Program::getProgramBinary() ...@@ -298,10 +298,18 @@ ProgramBinary* Program::getProgramBinary()
return mProgramBinary; return mProgramBinary;
} }
void Program::setProgramBinary(ProgramBinary *programBinary) void Program::setProgramBinary(const void *binary, GLsizei length)
{ {
unlink(false); unlink(false);
mProgramBinary = programBinary;
mInfoLog.reset();
mProgramBinary = new ProgramBinary;
if (!mProgramBinary->load(mInfoLog, binary, length))
{
delete mProgramBinary;
mProgramBinary = NULL;
}
} }
void Program::release() void Program::release()
...@@ -329,6 +337,18 @@ unsigned int Program::getSerial() const ...@@ -329,6 +337,18 @@ unsigned int Program::getSerial() const
return mSerial; return mSerial;
} }
GLint Program::getProgramBinaryLength() const
{
if (mProgramBinary)
{
return mProgramBinary->getLength();
}
else
{
return 0;
}
}
unsigned int Program::issueSerial() unsigned int Program::issueSerial()
{ {
return mCurrentSerial++; return mCurrentSerial++;
......
...@@ -69,7 +69,7 @@ class Program ...@@ -69,7 +69,7 @@ class Program
void bindAttributeLocation(GLuint index, const char *name); void bindAttributeLocation(GLuint index, const char *name);
void link(); void link();
void setProgramBinary(ProgramBinary *programBinary); void setProgramBinary(const void *binary, GLsizei length);
ProgramBinary *getProgramBinary(); ProgramBinary *getProgramBinary();
int getInfoLogLength() const; int getInfoLogLength() const;
...@@ -95,6 +95,8 @@ class Program ...@@ -95,6 +95,8 @@ class Program
unsigned int getSerial() const; unsigned int getSerial() const;
GLint getProgramBinaryLength() const;
private: private:
DISALLOW_COPY_AND_ASSIGN(Program); DISALLOW_COPY_AND_ASSIGN(Program);
......
...@@ -7,10 +7,13 @@ ...@@ -7,10 +7,13 @@
// Program.cpp: Implements the gl::Program class. Implements GL program objects // 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. // and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28.
#include <sstream>
#include "libGLESv2/Program.h" #include "libGLESv2/Program.h"
#include "libGLESv2/ProgramBinary.h" #include "libGLESv2/ProgramBinary.h"
#include "common/debug.h" #include "common/debug.h"
#include "common/version.h"
#include "libGLESv2/main.h" #include "libGLESv2/main.h"
#include "libGLESv2/Shader.h" #include "libGLESv2/Shader.h"
...@@ -1585,6 +1588,291 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std:: ...@@ -1585,6 +1588,291 @@ bool ProgramBinary::linkVaryings(InfoLog &infoLog, std::string& pixelHLSL, std::
return true; 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) bool ProgramBinary::link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader)
{ {
if (!fragmentShader || !fragmentShader->isCompiled()) if (!fragmentShader || !fragmentShader->isCompiled())
...@@ -2477,4 +2765,8 @@ GLint ProgramBinary::getDxPointsOrLinesLocation() const ...@@ -2477,4 +2765,8 @@ GLint ProgramBinary::getDxPointsOrLinesLocation() const
return mDxPointsOrLinesLocation; return mDxPointsOrLinesLocation;
} }
ProgramBinary::Sampler::Sampler() : active(false), logicalTextureUnit(0), textureType(TEXTURE_2D)
{
}
} }
...@@ -10,6 +10,10 @@ ...@@ -10,6 +10,10 @@
#ifndef LIBGLESV2_PROGRAM_BINARY_H_ #ifndef LIBGLESV2_PROGRAM_BINARY_H_
#define LIBGLESV2_PROGRAM_BINARY_H_ #define LIBGLESV2_PROGRAM_BINARY_H_
#define GL_APICALL
#include <gles2/gl2.h>
#include <gles2/gl2ext.h>
#include <d3dx9.h> #include <d3dx9.h>
#include <d3dcompiler.h> #include <d3dcompiler.h>
#include <string> #include <string>
...@@ -78,6 +82,10 @@ struct Uniform ...@@ -78,6 +82,10 @@ struct Uniform
// Struct used for correlating uniforms/elements of uniform arrays to handles // Struct used for correlating uniforms/elements of uniform arrays to handles
struct UniformLocation struct UniformLocation
{ {
UniformLocation()
{
}
UniformLocation(const std::string &_name, unsigned int element, unsigned int index); UniformLocation(const std::string &_name, unsigned int element, unsigned int index);
std::string name; std::string name;
...@@ -128,6 +136,10 @@ class ProgramBinary ...@@ -128,6 +136,10 @@ class ProgramBinary
void dirtyAllUniforms(); void dirtyAllUniforms();
void applyUniforms(); 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); bool link(InfoLog &infoLog, const AttributeBindings &attributeBindings, FragmentShader *fragmentShader, VertexShader *vertexShader);
void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders); void getAttachedShaders(GLsizei maxCount, GLsizei *count, GLuint *shaders);
...@@ -182,6 +194,8 @@ class ProgramBinary ...@@ -182,6 +194,8 @@ class ProgramBinary
struct Sampler struct Sampler
{ {
Sampler();
bool active; bool active;
GLint logicalTextureUnit; GLint logicalTextureUnit;
TextureType textureType; TextureType textureType;
......
...@@ -3422,7 +3422,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) ...@@ -3422,7 +3422,7 @@ void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params)
*params = programObject->getActiveUniformMaxLength(); *params = programObject->getActiveUniformMaxLength();
return; return;
case GL_PROGRAM_BINARY_LENGTH_OES: case GL_PROGRAM_BINARY_LENGTH_OES:
*params = 0; *params = programObject->getProgramBinaryLength();
return; return;
default: default:
return error(GL_INVALID_ENUM); return error(GL_INVALID_ENUM);
...@@ -6818,7 +6818,7 @@ void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat ...@@ -6818,7 +6818,7 @@ void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat
void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length, void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *length,
GLenum *binaryFormat, void *binary) 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); program, bufSize, length, binaryFormat, binary);
try try
...@@ -6841,12 +6841,12 @@ void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *l ...@@ -6841,12 +6841,12 @@ void __stdcall glGetProgramBinaryOES(GLuint program, GLsizei bufSize, GLsizei *l
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
*binaryFormat = GL_PROGRAM_BINARY_ANGLE; if (!programBinary->save(binary, bufSize, length))
if (length)
{ {
*length = 0; return error(GL_INVALID_OPERATION);
} }
*binaryFormat = GL_PROGRAM_BINARY_ANGLE;
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
...@@ -6879,7 +6879,7 @@ void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat, ...@@ -6879,7 +6879,7 @@ void __stdcall glProgramBinaryOES(GLuint program, GLenum binaryFormat,
return error(GL_INVALID_OPERATION); return error(GL_INVALID_OPERATION);
} }
programObject->setProgramBinary(NULL); programObject->setProgramBinary(binary, length);
} }
} }
catch(std::bad_alloc&) catch(std::bad_alloc&)
......
...@@ -170,6 +170,8 @@ EXPORTS ...@@ -170,6 +170,8 @@ EXPORTS
glVertexAttribDivisorANGLE @172 glVertexAttribDivisorANGLE @172
glDrawArraysInstancedANGLE @173 glDrawArraysInstancedANGLE @173
glDrawElementsInstancedANGLE @174 glDrawElementsInstancedANGLE @174
glProgramBinaryOES @175
glGetProgramBinaryOES @176
; EGL dependencies ; EGL dependencies
glCreateContext @144 NONAME 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