Commit 5601ea0d by zmo@google.com

Implement ES2 backend for Angle translator.

With this CL, we have the option to select a code output backend: GLSL, GLSL ES, or HLSL. Note that we always emit the highest supported float precision for fragment shader due to anglebug 168. Although this is a temporary solution, it's not against GLSL ES spec, because it's ok for implementation to upgrade precision. Tested with WebGL conformance test suite, GLES2 conformance test suite (only failed 2/1198), and a few webgl demos, including worlds of webgl, aquarium, etc. anglebug=81 test=translator emitting correct GLSL ES code when ES2 backend is selected. Review URL: http://codereview.appspot.com/4550129 git-svn-id: https://angleproject.googlecode.com/svn/trunk@687 736b8ea6-26fd-11df-bfd4-992fa37f6226
parent db5d5f66
......@@ -24,6 +24,7 @@ Google Inc.
Kenneth Russell
Ben Vanik
Adrienne Walker
Zhenyao Mo
Mozilla Corp.
Vladimir Vukicevic
......
......@@ -17,7 +17,7 @@ extern "C" {
// Version number for shader translation API.
// It is incremented everytime the API changes.
#define SH_VERSION 104
#define SH_VERSION 105
//
// The names of the following enums have been derived by replacing GL prefix
......@@ -36,6 +36,12 @@ typedef enum {
} ShShaderSpec;
typedef enum {
SH_ESSL_OUTPUT = 0x8B45,
SH_GLSL_OUTPUT = 0x8B46,
SH_HLSL_OUTPUT = 0x8B47
} ShShaderOutput;
typedef enum {
SH_NONE = 0,
SH_INT = 0x1404,
SH_FLOAT = 0x1406,
......@@ -128,13 +134,17 @@ typedef void* ShHandle;
//
// Driver calls these to create and destroy compiler objects.
//
// Returns the handle of constructed compiler.
// Returns the handle of constructed compiler, null if the requested compiler is
// not supported.
// Parameters:
// type: Specifies the type of shader - SH_FRAGMENT_SHADER or SH_VERTEX_SHADER.
// spec: Specifies the language spec the compiler must conform to -
// SH_GLES2_SPEC or SH_WEBGL_SPEC.
// output: Specifies the output code type - SH_ESSL_OUTPUT, SH_GLSL_OUTPUT,
// or SH_HLSL_OUTPUT.
// resources: Specifies the built-in resources.
ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
ShShaderOutput output,
const ShBuiltInResources* resources);
void ShDestruct(ShHandle handle);
......
......@@ -66,6 +66,7 @@ int main(int argc, char* argv[])
char* buffer = 0;
int bufferLen = 0;
int numAttribs = 0, numUniforms = 0;
ShShaderOutput output = SH_ESSL_OUTPUT;
ShInitialize();
......@@ -81,6 +82,18 @@ int main(int argc, char* argv[])
case 'm': compileOptions |= SH_MAP_LONG_VARIABLE_NAMES; break;
case 'o': compileOptions |= SH_OBJECT_CODE; break;
case 'u': compileOptions |= SH_ATTRIBUTES_UNIFORMS; break;
case 'b':
if (argv[0][2] == '=') {
switch (argv[0][3]) {
case 'e': output = SH_ESSL_OUTPUT; break;
case 'g': output = SH_GLSL_OUTPUT; break;
case 'h': output = SH_HLSL_OUTPUT; break;
default: failCode = EFailUsage;
}
} else {
failCode = EFailUsage;
}
break;
default: failCode = EFailUsage;
}
} else {
......@@ -88,12 +101,14 @@ int main(int argc, char* argv[])
switch (FindShaderType(argv[0])) {
case SH_VERTEX_SHADER:
if (vertexCompiler == 0)
vertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
vertexCompiler = ShConstructCompiler(
SH_VERTEX_SHADER, SH_GLES2_SPEC, output, &resources);
compiler = vertexCompiler;
break;
case SH_FRAGMENT_SHADER:
if (fragmentCompiler == 0)
fragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
fragmentCompiler = ShConstructCompiler(
SH_FRAGMENT_SHADER, SH_GLES2_SPEC, output, &resources);
compiler = fragmentCompiler;
break;
default: break;
......@@ -159,12 +174,15 @@ int main(int argc, char* argv[])
//
void usage()
{
printf("Usage: translate [-i -m -o -u] file1 file2 ...\n"
"Where: filename = filename ending in .frag or .vert\n"
" -i = print intermediate tree\n"
" -m = map long variable names\n"
" -o = print translated code\n"
" -u = print active attribs and uniforms\n");
printf("Usage: translate [-i -m -o -u -b=e -b=g -b=h] file1 file2 ...\n"
"Where: filename : filename ending in .frag or .vert\n"
" -i : print intermediate tree\n"
" -m : map long variable names\n"
" -o : print translated code\n"
" -u : print active attribs and uniforms\n"
" -b=e : output GLSL ES code (this is by default)\n"
" -b=g : output GLSL code\n"
" -b=h : output HLSL code\n");
}
//
......
......@@ -104,8 +104,14 @@
'compiler/CodeGenGLSL.cpp',
'compiler/ForLoopUnroll.cpp',
'compiler/ForLoopUnroll.h',
'compiler/OutputESSL.cpp',
'compiler/OutputESSL.h',
'compiler/OutputGLSLBase.cpp',
'compiler/OutputGLSLBase.h',
'compiler/OutputGLSL.cpp',
'compiler/OutputGLSL.h',
'compiler/TranslatorESSL.cpp',
'compiler/TranslatorESSL.h',
'compiler/TranslatorGLSL.cpp',
'compiler/TranslatorGLSL.h',
'compiler/VersionGLSL.cpp',
......
#define MAJOR_VERSION 0
#define MINOR_VERSION 0
#define BUILD_VERSION 0
#define BUILD_REVISION 686
#define BUILD_REVISION 687
#define STRINGIFY(x) #x
#define MACRO_STRINGIFY(x) STRINGIFY(x)
......
......@@ -5,15 +5,24 @@
//
#include "compiler/TranslatorGLSL.h"
#include "compiler/TranslatorESSL.h"
//
// This function must be provided to create the actual
// compile object used by higher level code. It returns
// a subclass of TCompiler.
//
TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec)
TCompiler* ConstructCompiler(
ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
{
return new TranslatorGLSL(type, spec);
switch (output) {
case SH_GLSL_OUTPUT:
return new TranslatorGLSL(type, spec);
case SH_ESSL_OUTPUT:
return new TranslatorESSL(type, spec);
default:
return NULL;
}
}
//
......
......@@ -11,9 +11,15 @@
// compile object used by higher level code. It returns
// a subclass of TCompiler.
//
TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec)
TCompiler* ConstructCompiler(
ShShaderType type, ShShaderSpec spec, ShShaderOutput output)
{
return new TranslatorHLSL(type, spec);
switch (output) {
case SH_HLSL_OUTPUT:
return new TranslatorHLSL(type, spec);
default:
return NULL;
}
}
//
......
......@@ -215,3 +215,8 @@ int TCompiler::getMappedNameMaxLength() const
{
return MAX_IDENTIFIER_NAME_SIZE + 1;
}
const TExtensionBehavior& TCompiler::getExtensionBehavior() const
{
return extensionBehavior;
}
......@@ -16,6 +16,22 @@ typedef enum {
EBhDisable
} TBehavior;
inline const char* getBehaviorString(TBehavior b)
{
switch(b) {
case EBhRequire:
return "require";
case EBhEnable:
return "enable";
case EBhWarn:
return "warn";
case EBhDisable:
return "disable";
default:
return NULL;
}
}
typedef TMap<TString, TBehavior> TExtensionBehavior;
#endif // _EXTENSION_TABLE_INCLUDED_
//
// Copyright (c) 2002-2011 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.
//
#include "compiler/OutputESSL.h"
TOutputESSL::TOutputESSL(TInfoSinkBase& objSink)
: TOutputGLSLBase(objSink)
{
}
bool TOutputESSL::writeVariablePrecision(TPrecision precision)
{
if (precision == EbpUndefined)
return false;
TInfoSinkBase& out = objSink();
out << getPrecisionString(precision);
return true;
}
//
// Copyright (c) 2002-2011 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.
//
#ifndef CROSSCOMPILERGLSL_OUTPUTESSL_H_
#define CROSSCOMPILERGLSL_OUTPUTESSL_H_
#include "compiler/OutputGLSLBase.h"
class TOutputESSL : public TOutputGLSLBase
{
public:
TOutputESSL(TInfoSinkBase& objSink);
protected:
virtual bool writeVariablePrecision(TPrecision precision);
};
#endif // CROSSCOMPILERGLSL_OUTPUTESSL_H_
//
// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
// Copyright (c) 2002-2011 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.
//
......@@ -7,46 +7,15 @@
#ifndef CROSSCOMPILERGLSL_OUTPUTGLSL_H_
#define CROSSCOMPILERGLSL_OUTPUTGLSL_H_
#include <set>
#include "compiler/OutputGLSLBase.h"
#include "compiler/ForLoopUnroll.h"
#include "compiler/intermediate.h"
#include "compiler/ParseHelper.h"
class TOutputGLSL : public TIntermTraverser
class TOutputGLSL : public TOutputGLSLBase
{
public:
TOutputGLSL(TInfoSinkBase& objSink);
protected:
TInfoSinkBase& objSink() { return mObjSink; }
void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
void writeVariableType(const TType& type);
void writeFunctionParameters(const TIntermSequence& args);
const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
virtual void visitSymbol(TIntermSymbol* node);
virtual void visitConstantUnion(TIntermConstantUnion* node);
virtual bool visitBinary(Visit visit, TIntermBinary* node);
virtual bool visitUnary(Visit visit, TIntermUnary* node);
virtual bool visitSelection(Visit visit, TIntermSelection* node);
virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
virtual bool visitLoop(Visit visit, TIntermLoop* node);
virtual bool visitBranch(Visit visit, TIntermBranch* node);
void visitCodeBlock(TIntermNode* node);
private:
TInfoSinkBase& mObjSink;
bool mDeclaringVariables;
// Structs are declared as the tree is traversed. This set contains all
// the structs already declared. It is maintained so that a struct is
// declared only once.
typedef std::set<TString> DeclaredStructs;
DeclaredStructs mDeclaredStructs;
ForLoopUnroll mLoopUnroll;
virtual bool writeVariablePrecision(TPrecision);
};
#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
//
// Copyright (c) 2002-2011 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.
//
#ifndef CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
#define CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
#include <set>
#include "compiler/ForLoopUnroll.h"
#include "compiler/intermediate.h"
#include "compiler/ParseHelper.h"
class TOutputGLSLBase : public TIntermTraverser
{
public:
TOutputGLSLBase(TInfoSinkBase& objSink);
protected:
TInfoSinkBase& objSink() { return mObjSink; }
void writeTriplet(Visit visit, const char* preStr, const char* inStr, const char* postStr);
void writeVariableType(const TType& type);
virtual bool writeVariablePrecision(TPrecision precision) = 0;
void writeFunctionParameters(const TIntermSequence& args);
const ConstantUnion* writeConstantUnion(const TType& type, const ConstantUnion* pConstUnion);
virtual void visitSymbol(TIntermSymbol* node);
virtual void visitConstantUnion(TIntermConstantUnion* node);
virtual bool visitBinary(Visit visit, TIntermBinary* node);
virtual bool visitUnary(Visit visit, TIntermUnary* node);
virtual bool visitSelection(Visit visit, TIntermSelection* node);
virtual bool visitAggregate(Visit visit, TIntermAggregate* node);
virtual bool visitLoop(Visit visit, TIntermLoop* node);
virtual bool visitBranch(Visit visit, TIntermBranch* node);
void visitCodeBlock(TIntermNode* node);
private:
TInfoSinkBase& mObjSink;
bool mDeclaringVariables;
// Structs are declared as the tree is traversed. This set contains all
// the structs already declared. It is maintained so that a struct is
// declared only once.
typedef std::set<TString> DeclaredStructs;
DeclaredStructs mDeclaredStructs;
ForLoopUnroll mLoopUnroll;
};
#endif // CROSSCOMPILERGLSL_OUTPUTGLSLBASE_H_
......@@ -30,13 +30,13 @@ struct TPragma {
// they can be passed to the parser without needing a global.
//
struct TParseContext {
TParseContext(TSymbolTable& symt, const TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, const char* sourcePath, TInfoSink& is) :
TParseContext(TSymbolTable& symt, TExtensionBehavior& ext, TIntermediate& interm, ShShaderType type, ShShaderSpec spec, int options, const char* sourcePath, TInfoSink& is) :
intermediate(interm), symbolTable(symt), extensionBehavior(ext), infoSink(is), shaderType(type), shaderSpec(spec), compileOptions(options), sourcePath(sourcePath), treeRoot(0),
recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0),
inTypeParen(false), scanner(NULL), contextPragma(true, false) { }
TIntermediate& intermediate; // to hold and build a parse tree
TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed
TExtensionBehavior extensionBehavior; // mapping between supported extensions and current behavior.
TExtensionBehavior& extensionBehavior; // mapping between supported extensions and current behavior.
TInfoSink& infoSink;
ShShaderType shaderType; // vertex or fragment language (future: pack or unpack)
ShShaderSpec shaderSpec; // The language specification compiler conforms to - GLES2 or WebGL.
......
......@@ -75,6 +75,8 @@ protected:
void mapLongVariableNames(TIntermNode* root);
// Translate to object code.
virtual void translate(TIntermNode* root) = 0;
// Get built-in extensions with default behavior.
const TExtensionBehavior& getExtensionBehavior() const;
private:
ShShaderType shaderType;
......@@ -104,7 +106,8 @@ private:
// destroy the machine dependent objects, which contain the
// above machine independent information.
//
TCompiler* ConstructCompiler(ShShaderType type, ShShaderSpec spec);
TCompiler* ConstructCompiler(
ShShaderType type, ShShaderSpec spec, ShShaderOutput output);
void DeleteCompiler(TCompiler*);
#endif // _SHHANDLE_INCLUDED_
......@@ -110,12 +110,13 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
// Driver calls these to create and destroy compiler objects.
//
ShHandle ShConstructCompiler(ShShaderType type, ShShaderSpec spec,
ShShaderOutput output,
const ShBuiltInResources* resources)
{
if (!InitThread())
return 0;
TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec));
TShHandleBase* base = static_cast<TShHandleBase*>(ConstructCompiler(type, spec, output));
TCompiler* compiler = base->getAsCompiler();
if (compiler == 0)
return 0;
......
//
// Copyright (c) 2002-2011 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.
//
#include "compiler/TranslatorESSL.h"
#include "compiler/OutputESSL.h"
TranslatorESSL::TranslatorESSL(ShShaderType type, ShShaderSpec spec)
: TCompiler(type, spec) {
}
void TranslatorESSL::translate(TIntermNode* root) {
TInfoSinkBase& sink = getInfoSink().obj;
// Write built-in extension behaviors.
writeExtensionBehavior();
// FIXME(zmo): no need to emit default precision if all variables emit
// their own precision.
// http://code.google.com/p/angleproject/issues/detail?id=168
if (this->getShaderType() == SH_FRAGMENT_SHADER) {
// Write default float precision.
sink << "#if defined(GL_FRAGMENT_PRECISION_HIGH)\n"
<< "precision highp float;\n"
<< "#else\n"
<< "precision mediump float;\n"
<< "#endif\n";
}
// Write translated shader.
TOutputESSL outputESSL(sink);
root->traverse(&outputESSL);
}
void TranslatorESSL::writeExtensionBehavior() {
TInfoSinkBase& sink = getInfoSink().obj;
const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
iter != extensionBehavior.end(); ++iter) {
sink << "#extension " << iter->first << " : "
<< getBehaviorString(iter->second) << "\n";
}
}
//
// Copyright (c) 2002-2011 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.
//
#ifndef COMPILER_TRANSLATORESSL_H_
#define COMPILER_TRANSLATORESSL_H_
#include "compiler/ShHandle.h"
class TranslatorESSL : public TCompiler {
public:
TranslatorESSL(ShShaderType type, ShShaderSpec spec);
protected:
virtual void translate(TIntermNode* root);
private:
void writeExtensionBehavior();
};
#endif // COMPILER_TRANSLATORESSL_H_
......@@ -36,7 +36,7 @@ Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mReso
{
ShBuiltInResources resources;
ShInitBuiltInResources(&resources);
Context *context = getContext();
Context *context = getContext();
resources.MaxVertexAttribs = MAX_VERTEX_ATTRIBS;
resources.MaxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS;
......@@ -48,8 +48,8 @@ Shader::Shader(ResourceManager *manager, GLuint handle) : mHandle(handle), mReso
resources.MaxDrawBuffers = MAX_DRAW_BUFFERS;
resources.OES_standard_derivatives = 1;
mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, &resources);
mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, &resources);
mFragmentCompiler = ShConstructCompiler(SH_FRAGMENT_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
mVertexCompiler = ShConstructCompiler(SH_VERTEX_SHADER, SH_GLES2_SPEC, SH_HLSL_OUTPUT, &resources);
}
}
......
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