diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..37c8466f5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +Debug +Release +ANGLE.ncb +ANGLE.suo +Compiler/Compiler.vcproj.* +Compiler/Gen_glslang.cpp +Compiler/Gen_glslang_tab.cpp +Compiler/glslang.output +Compiler/glslang_tab.h +Compiler/Debug +Compiler/Release +libEGL/Debug +libEGL/Release +libEGL/libEGL.vcproj.* +libGLESv2/Debug +libGLESv2/Release +libGLESv2/libGLESv2.vcproj.* + diff --git a/ANGLE.sln b/ANGLE.sln new file mode 100644 index 000000000..ba98b73f1 --- /dev/null +++ b/ANGLE.sln @@ -0,0 +1,38 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libEGL", "libEGL\libEGL.vcproj", "{E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}" + ProjectSection(ProjectDependencies) = postProject + {B5871A7A-968C-42E3-A33B-981E6F448E78} = {B5871A7A-968C-42E3-A33B-981E6F448E78} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libGLESv2", "libGLESv2\libGLESv2.vcproj", "{B5871A7A-968C-42E3-A33B-981E6F448E78}" + ProjectSection(ProjectDependencies) = postProject + {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD} = {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD} + EndProjectSection +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Compiler", "Compiler\Compiler.vcproj", "{5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.ActiveCfg = Debug|Win32 + {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Debug|Win32.Build.0 = Debug|Win32 + {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.ActiveCfg = Release|Win32 + {E746FCA9-64C3-433E-85E8-9A5A67AB7ED6}.Release|Win32.Build.0 = Release|Win32 + {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.ActiveCfg = Debug|Win32 + {B5871A7A-968C-42E3-A33B-981E6F448E78}.Debug|Win32.Build.0 = Debug|Win32 + {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.ActiveCfg = Release|Win32 + {B5871A7A-968C-42E3-A33B-981E6F448E78}.Release|Win32.Build.0 = Release|Win32 + {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.ActiveCfg = Debug|Win32 + {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Debug|Win32.Build.0 = Debug|Win32 + {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.ActiveCfg = Release|Win32 + {5B3A6DB8-1E7E-40D7-92B9-DA8AAE619FAD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..5bde28430 --- /dev/null +++ b/AUTHORS @@ -0,0 +1,15 @@ +# This is the official list of The ANGLE Project Authors +# for copyright purposes. +# This file is distinct from the CONTRIBUTORS files. +# See the latter for an explanation. + +# Names should be added to this file as +# Name or Organization +# The email address is not required for organizations. + +TransGaming Inc. + +Google Inc. + +3DLabs Inc. Ltd. + diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 000000000..b5d79750b --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,18 @@ +# This is the official list of people who can contribute +# (and who have contributed) code to the ANGLE project +# repository. +# The AUTHORS file lists the copyright holders; this file +# lists people. For example, Google employees are listed here +# but not in AUTHORS, because Google holds the copyright. +# + +TransGaming Inc. + Nicolas Capens + Daniel Koch + Andrew Lewycky + Gavriel State + Shannon Woods + +Google Inc. + Henry Bridge + Vangelis Kokkevis diff --git a/Common/debug.cpp b/Common/debug.cpp new file mode 100644 index 000000000..14c0d090f --- /dev/null +++ b/Common/debug.cpp @@ -0,0 +1,36 @@ +// +// Copyright (c) 2002-2010 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. +// + +// debug.cpp: Debugging utilities. + +#include "debug.h" + +#include +#include + +namespace gl +{ +void trace(const char *format, ...) +{ + if (true) + { + if (format) + { + FILE *file = fopen("debug.txt", "a"); + + if (file) + { + va_list vararg; + va_start(vararg, format); + vfprintf(file, format, vararg); + va_end(vararg); + + fclose(file); + } + } + } +} +} diff --git a/Compiler/BaseTypes.h b/Compiler/BaseTypes.h new file mode 100644 index 000000000..2265b9661 --- /dev/null +++ b/Compiler/BaseTypes.h @@ -0,0 +1,130 @@ +// +// Copyright (c) 2002-2010 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 _BASICTYPES_INCLUDED_ +#define _BASICTYPES_INCLUDED_ + +// +// Precision qualifiers +// +enum TPrecision +{ + EbpHigh, + EbpMedium, + EbpLow, +}; + +__inline const char* getPrecisionString(TPrecision p) +{ + switch(p) + { + case EbpHigh: return "highp"; break; + case EbpMedium: return "mediump"; break; + case EbpLow: return "lowp"; break; + default: return "unknown precision"; + } +} + +// +// Basic type. Arrays, vectors, etc., are orthogonal to this. +// +enum TBasicType +{ + EbtVoid, + EbtFloat, + EbtInt, + EbtBool, + EbtGuardSamplerBegin, // non type: see implementation of IsSampler() + EbtSampler2D, + EbtSamplerCube, + EbtGuardSamplerEnd, // non type: see implementation of IsSampler() + EbtStruct, + EbtAddress, // should be deprecated?? +}; + +__inline bool IsSampler(TBasicType type) +{ + return type > EbtGuardSamplerBegin && type < EbtGuardSamplerEnd; +} + +// +// Qualifiers and built-ins. These are mainly used to see what can be read +// or written, and by the machine dependent translator to know which registers +// to allocate variables in. Since built-ins tend to go to different registers +// than varying or uniform, it makes sense they are peers, not sub-classes. +// +enum TQualifier +{ + EvqTemporary, // For temporaries (within a function), read/write + EvqGlobal, // For globals read/write + EvqConst, // User defined constants and non-output parameters in functions + EvqAttribute, // Readonly + EvqVaryingIn, // readonly, fragment shaders only + EvqVaryingOut, // vertex shaders only read/write + EvqInvariantVaryingIn, // readonly, fragment shaders only + EvqInvariantVaryingOut, // vertex shaders only read/write + EvqUniform, // Readonly, vertex and fragment + + // pack/unpack input and output + EvqInput, + EvqOutput, + + // parameters + EvqIn, + EvqOut, + EvqInOut, + EvqConstReadOnly, + + // built-ins written by vertex shader + EvqPosition, + EvqPointSize, + + // built-ins read by fragment shader + EvqFragCoord, + EvqFrontFacing, + EvqPointCoord, + + // built-ins written by fragment shader + EvqFragColor, + EvqFragData, + + // end of list + EvqLast, +}; + +// +// This is just for debug print out, carried along with the definitions above. +// +__inline const char* getQualifierString(TQualifier q) +{ + switch(q) + { + case EvqTemporary: return "Temporary"; break; + case EvqGlobal: return "Global"; break; + case EvqConst: return "const"; break; + case EvqConstReadOnly: return "const"; break; + case EvqAttribute: return "attribute"; break; + case EvqVaryingIn: return "varying"; break; + case EvqVaryingOut: return "varying"; break; + case EvqInvariantVaryingIn: return "invariant varying"; break; + case EvqInvariantVaryingOut:return "invariant varying"; break; + case EvqUniform: return "uniform"; break; + case EvqIn: return "in"; break; + case EvqOut: return "out"; break; + case EvqInOut: return "inout"; break; + case EvqInput: return "input"; break; + case EvqOutput: return "output"; break; + case EvqPosition: return "Position"; break; + case EvqPointSize: return "PointSize"; break; + case EvqFragCoord: return "FragCoord"; break; + case EvqFrontFacing: return "FrontFacing"; break; + case EvqFragColor: return "FragColor"; break; + case EvqFragData: return "FragData"; break; + default: return "unknown qualifier"; + } +} + +#endif // _BASICTYPES_INCLUDED_ diff --git a/Compiler/CodeGen.cpp b/Compiler/CodeGen.cpp new file mode 100644 index 000000000..fa54c7edc --- /dev/null +++ b/Compiler/CodeGen.cpp @@ -0,0 +1,47 @@ +// +// Copyright (c) 2002-2010 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 "Common.h" +#include "ShHandle.h" + +// +// Here is where real machine specific high-level data would be defined. +// +class TGenericCompiler : public TCompiler { +public: + TGenericCompiler(EShLanguage l, int dOptions) : TCompiler(l, infoSink), debugOptions(dOptions) { } + virtual bool compile(TIntermNode* root); + TInfoSink infoSink; + int debugOptions; +}; + +// +// This function must be provided to create the actual +// compile object used by higher level code. It returns +// a subclass of TCompiler. +// +TCompiler* ConstructCompiler(EShLanguage language, int debugOptions) +{ + return new TGenericCompiler(language, debugOptions); +} + +// +// Delete the compiler made by ConstructCompiler +// +void DeleteCompiler(TCompiler* compiler) +{ + delete compiler; +} + +// +// Generate code from the given parse tree +// +bool TGenericCompiler::compile(TIntermNode *root) +{ + haveValidObjectCode = true; + + return haveValidObjectCode; +} diff --git a/Compiler/Common.h b/Compiler/Common.h new file mode 100644 index 000000000..1ab2e9114 --- /dev/null +++ b/Compiler/Common.h @@ -0,0 +1,164 @@ +// +// Copyright (c) 2002-2010 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 _COMMON_INCLUDED_ +#define _COMMON_INCLUDED_ + +#ifdef _WIN32 + #include +#elif defined (solaris) + #include + #define UINT_PTR uintptr_t +#else + #include + #define UINT_PTR uintptr_t +#endif + +/* windows only pragma */ +#ifdef _MSC_VER + #pragma warning(disable : 4786) // Don't warn about too long identifiers + #pragma warning(disable : 4514) // unused inline method + #pragma warning(disable : 4201) // nameless union +#endif + +// +// Doing the push and pop below for warnings does not leave the warning state +// the way it was. This seems like a defect in the compiler. We would like +// to do this, but since it does not work correctly right now, it is turned +// off. +// +//??#pragma warning(push, 3) + + #include + #include + #include + #include + #include + #include + +//??#pragma warning(pop) + +typedef int TSourceLoc; + + #include + +#include "PoolAlloc.h" + +// +// Put POOL_ALLOCATOR_NEW_DELETE in base classes to make them use this scheme. +// +#define POOL_ALLOCATOR_NEW_DELETE(A) \ + void* operator new(size_t s) { return (A).allocate(s); } \ + void* operator new(size_t, void *_Where) { return (_Where); } \ + void operator delete(void*) { } \ + void operator delete(void *, void *) { } \ + void* operator new[](size_t s) { return (A).allocate(s); } \ + void* operator new[](size_t, void *_Where) { return (_Where); } \ + void operator delete[](void*) { } \ + void operator delete[](void *, void *) { } + +#define TBaseMap std::map +#define TBaseList std::list +#define TBaseSet std::set + +// +// Pool version of string. +// +typedef pool_allocator TStringAllocator; +typedef std::basic_string , TStringAllocator > TString; +inline TString* NewPoolTString(const char* s) +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TString)); + return new(memory) TString(s); +} + +// +// Pool allocator versions of vectors, lists, and maps +// +template class TVector : public std::vector > { +public: + typedef typename std::vector >::size_type size_type; + TVector() : std::vector >() {} + TVector(const pool_allocator& a) : std::vector >(a) {} + TVector(size_type i): std::vector >(i) {} +}; + +template class TList : public TBaseList > { +public: + typedef typename TBaseList >::size_type size_type; + TList() : TBaseList >() {} + TList(const pool_allocator& a) : TBaseList >(a) {} + TList(size_type i): TBaseList >(i) {} +}; + +// This is called TStlSet, because TSet is taken by an existing compiler class. +template class TStlSet : public std::set > { + // No pool allocator versions of constructors in std::set. +}; + + +template > +class TMap : public TBaseMap > > { +public: + typedef pool_allocator > tAllocator; + + TMap() : TBaseMap() {} + // use correct two-stage name lookup supported in gcc 3.4 and above + TMap(const tAllocator& a) : TBaseMap(TBaseMap::key_compare(), a) {} +}; + +// +// Persistent string memory. Should only be used for strings that survive +// across compiles/links. +// +typedef std::basic_string TPersistString; + +// +// templatized min and max functions. +// +template T Min(const T a, const T b) { return a < b ? a : b; } +template T Max(const T a, const T b) { return a > b ? a : b; } + +// +// Create a TString object from an integer. +// +inline const TString String(const int i, const int base = 10) +{ + char text[16]; // 32 bit ints are at most 10 digits in base 10 + + #ifdef _WIN32 + _itoa(i, text, base); + #else + // we assume base 10 for all cases + sprintf(text, "%d", i); + #endif + + return text; +} + +const unsigned int SourceLocLineMask = 0xffff; +const unsigned int SourceLocStringShift = 16; + +__inline TPersistString FormatSourceLoc(const TSourceLoc loc) +{ + char locText[64]; + + int string = loc >> SourceLocStringShift; + int line = loc & SourceLocLineMask; + + if (line) + sprintf(locText, "%d:%d", string, line); + else + sprintf(locText, "%d:? ", string); + + return TPersistString(locText); +} + + +typedef TMap TPragmaTable; +typedef TMap::tAllocator TPragmaTableAllocator; + +#endif // _COMMON_INCLUDED_ diff --git a/Compiler/Compiler.vcproj b/Compiler/Compiler.vcproj new file mode 100644 index 000000000..7c380e91d --- /dev/null +++ b/Compiler/Compiler.vcproj @@ -0,0 +1,474 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Compiler/ConstantUnion.h b/Compiler/ConstantUnion.h new file mode 100644 index 000000000..b0ab97132 --- /dev/null +++ b/Compiler/ConstantUnion.h @@ -0,0 +1,287 @@ +// +// Copyright (c) 2002-2010 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 _CONSTANT_UNION_INCLUDED_ +#define _CONSTANT_UNION_INCLUDED_ + + +class constUnion { +public: + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + void setIConst(int i) {iConst = i; type = EbtInt; } + void setFConst(float f) {fConst = f; type = EbtFloat; } + void setBConst(bool b) {bConst = b; type = EbtBool; } + + int getIConst() { return iConst; } + float getFConst() { return fConst; } + bool getBConst() { return bConst; } + int getIConst() const { return iConst; } + float getFConst() const { return fConst; } + bool getBConst() const { return bConst; } + + bool operator==(const int i) const + { + if (i == iConst) + return true; + + return false; + } + + bool operator==(const float f) const + { + if (f == fConst) + return true; + + return false; + } + + bool operator==(const bool b) const + { + if (b == bConst) + return true; + + return false; + } + + bool operator==(const constUnion& constant) const + { + if (constant.type != type) + return false; + + switch (type) { + case EbtInt: + if (constant.iConst == iConst) + return true; + + break; + case EbtFloat: + if (constant.fConst == fConst) + return true; + + break; + case EbtBool: + if (constant.bConst == bConst) + return true; + + break; + } + + return false; + } + + bool operator!=(const int i) const + { + return !operator==(i); + } + + bool operator!=(const float f) const + { + return !operator==(f); + } + + bool operator!=(const bool b) const + { + return !operator==(b); + } + + bool operator!=(const constUnion& constant) const + { + return !operator==(constant); + } + + bool operator>(const constUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + if (iConst > constant.iConst) + return true; + + return false; + case EbtFloat: + if (fConst > constant.fConst) + return true; + + return false; + default: + assert(false && "Default missing"); + return false; + } + + return false; + } + + bool operator<(const constUnion& constant) const + { + assert(type == constant.type); + switch (type) { + case EbtInt: + if (iConst < constant.iConst) + return true; + + return false; + case EbtFloat: + if (fConst < constant.fConst) + return true; + + return false; + default: + assert(false && "Default missing"); + return false; + } + + return false; + } + + constUnion operator+(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst + constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst + constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator-(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst - constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst - constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator*(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst * constant.iConst); break; + case EbtFloat: returnValue.setFConst(fConst * constant.fConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator%(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst % constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator>>(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst >> constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator<<(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst << constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator&(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst & constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator|(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst | constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator^(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtInt: returnValue.setIConst(iConst ^ constant.iConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator&&(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst && constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + constUnion operator||(const constUnion& constant) const + { + constUnion returnValue; + assert(type == constant.type); + switch (type) { + case EbtBool: returnValue.setBConst(bConst || constant.bConst); break; + default: assert(false && "Default missing"); + } + + return returnValue; + } + + TBasicType getType() { return type; } +private: + + union { + int iConst; // used for ivec, scalar ints + bool bConst; // used for bvec, scalar bools + float fConst; // used for vec, mat, scalar floats + } ; + + TBasicType type; +}; + +#endif // _CONSTANT_UNION_INCLUDED_ diff --git a/Compiler/InfoSink.cpp b/Compiler/InfoSink.cpp new file mode 100644 index 000000000..9f2a188f6 --- /dev/null +++ b/Compiler/InfoSink.cpp @@ -0,0 +1,79 @@ +// +// Copyright (c) 2002-2010 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 "InfoSink.h" + +#ifdef _WIN32 + #include +#endif + +void TInfoSinkBase::append(const char *s) +{ + if (outputStream & EString) { + checkMem(strlen(s)); + sink.append(s); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(s); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", s); +} + +void TInfoSinkBase::append(int count, char c) +{ + if (outputStream & EString) { + checkMem(count); + sink.append(count, c); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) { + char str[2]; + str[0] = c; + str[1] = '\0'; + OutputDebugString(str); + } +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%c", c); +} + +void TInfoSinkBase::append(const TPersistString& t) +{ + if (outputStream & EString) { + checkMem(t.size()); + sink.append(t); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(t.c_str()); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", t.c_str()); +} + +void TInfoSinkBase::append(const TString& t) +{ + if (outputStream & EString) { + checkMem(t.size()); + sink.append(t.c_str()); + } + +#ifdef _WIN32 + if (outputStream & EDebugger) + OutputDebugString(t.c_str()); +#endif + + if (outputStream & EStdOut) + fprintf(stdout, "%s", t.c_str()); +} diff --git a/Compiler/InfoSink.h b/Compiler/InfoSink.h new file mode 100644 index 000000000..525a37868 --- /dev/null +++ b/Compiler/InfoSink.h @@ -0,0 +1,109 @@ +// +// Copyright (c) 2002-2010 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 _INFOSINK_INCLUDED_ +#define _INFOSINK_INCLUDED_ + +#include "Common.h" +#include + +// +// TPrefixType is used to centralize how info log messages start. +// See below. +// +enum TPrefixType { + EPrefixNone, + EPrefixWarning, + EPrefixError, + EPrefixInternalError, + EPrefixUnimplemented, + EPrefixNote +}; + +enum TOutputStream { + ENull = 0, + EDebugger = 0x01, + EStdOut = 0x02, + EString = 0x04, +}; +// +// Encapsulate info logs for all objects that have them. +// +// The methods are a general set of tools for getting a variety of +// messages and types inserted into the log. +// +class TInfoSinkBase { +public: + TInfoSinkBase() : outputStream(4) {} + void erase() { sink.erase(); } + TInfoSinkBase& operator<<(const TPersistString& t) { append(t); return *this; } + TInfoSinkBase& operator<<(char c) { append(1, c); return *this; } + TInfoSinkBase& operator<<(const char* s) { append(s); return *this; } + TInfoSinkBase& operator<<(int n) { append(String(n)); return *this; } + TInfoSinkBase& operator<<(const unsigned int n) { append(String(n)); return *this; } + TInfoSinkBase& operator<<(float n) { char buf[40]; + sprintf(buf, "%.8g", n); + append(buf); + return *this; } + TInfoSinkBase& operator+(const TPersistString& t) { append(t); return *this; } + TInfoSinkBase& operator+(const TString& t) { append(t); return *this; } + TInfoSinkBase& operator<<(const TString& t) { append(t); return *this; } + TInfoSinkBase& operator+(const char* s) { append(s); return *this; } + const char* c_str() const { return sink.c_str(); } + void prefix(TPrefixType message) { + switch(message) { + case EPrefixNone: break; + case EPrefixWarning: append("WARNING: "); break; + case EPrefixError: append("ERROR: "); break; + case EPrefixInternalError: append("INTERNAL ERROR: "); break; + case EPrefixUnimplemented: append("UNIMPLEMENTED: "); break; + case EPrefixNote: append("NOTE: "); break; + default: append("UNKOWN ERROR: "); break; + } + } + void location(TSourceLoc loc) { + append(FormatSourceLoc(loc).c_str()); + append(": "); + } + void message(TPrefixType message, const char* s) { + prefix(message); + append(s); + append("\n"); + } + void message(TPrefixType message, const char* s, TSourceLoc loc) { + prefix(message); + location(loc); + append(s); + append("\n"); + } + + void setOutputStream(int output = 4) + { + outputStream = output; + } + +protected: + void append(const char *s); + + void append(int count, char c); + void append(const TPersistString& t); + void append(const TString& t); + + void checkMem(size_t growth) { if (sink.capacity() < sink.size() + growth + 2) + sink.reserve(sink.capacity() + sink.capacity() / 2); } + void appendToStream(const char* s); + TPersistString sink; + int outputStream; +}; + +class TInfoSink { +public: + TInfoSinkBase info; + TInfoSinkBase debug; + TInfoSinkBase obj; +}; + +#endif // _INFOSINK_INCLUDED_ diff --git a/Compiler/Initialize.cpp b/Compiler/Initialize.cpp new file mode 100644 index 000000000..2b7ecfff1 --- /dev/null +++ b/Compiler/Initialize.cpp @@ -0,0 +1,616 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// Create strings that declare built-in definitions, add built-ins that +// cannot be expressed in the files, and establish mappings between +// built-in functions and operators. +// + +#include "intermediate.h" +#include "Initialize.h" + +void TBuiltIns::initialize() +{ + // + // Initialize all the built-in strings for parsing. + // + TString BuiltInFunctions; + TString BuiltInFunctionsVertex; + TString BuiltInFunctionsFragment; + TString StandardUniforms; + + { + //============================================================================ + // + // Prototypes for built-in functions seen by both vertex and fragment shaders. + // + //============================================================================ + + TString& s = BuiltInFunctions; + + // + // Angle and Trigonometric Functions. + // + s.append(TString("float radians(float degrees);")); + s.append(TString("vec2 radians(vec2 degrees);")); + s.append(TString("vec3 radians(vec3 degrees);")); + s.append(TString("vec4 radians(vec4 degrees);")); + + s.append(TString("float degrees(float radians);")); + s.append(TString("vec2 degrees(vec2 radians);")); + s.append(TString("vec3 degrees(vec3 radians);")); + s.append(TString("vec4 degrees(vec4 radians);")); + + s.append(TString("float sin(float angle);")); + s.append(TString("vec2 sin(vec2 angle);")); + s.append(TString("vec3 sin(vec3 angle);")); + s.append(TString("vec4 sin(vec4 angle);")); + + s.append(TString("float cos(float angle);")); + s.append(TString("vec2 cos(vec2 angle);")); + s.append(TString("vec3 cos(vec3 angle);")); + s.append(TString("vec4 cos(vec4 angle);")); + + s.append(TString("float tan(float angle);")); + s.append(TString("vec2 tan(vec2 angle);")); + s.append(TString("vec3 tan(vec3 angle);")); + s.append(TString("vec4 tan(vec4 angle);")); + + s.append(TString("float asin(float x);")); + s.append(TString("vec2 asin(vec2 x);")); + s.append(TString("vec3 asin(vec3 x);")); + s.append(TString("vec4 asin(vec4 x);")); + + s.append(TString("float acos(float x);")); + s.append(TString("vec2 acos(vec2 x);")); + s.append(TString("vec3 acos(vec3 x);")); + s.append(TString("vec4 acos(vec4 x);")); + + s.append(TString("float atan(float y, float x);")); + s.append(TString("vec2 atan(vec2 y, vec2 x);")); + s.append(TString("vec3 atan(vec3 y, vec3 x);")); + s.append(TString("vec4 atan(vec4 y, vec4 x);")); + + s.append(TString("float atan(float y_over_x);")); + s.append(TString("vec2 atan(vec2 y_over_x);")); + s.append(TString("vec3 atan(vec3 y_over_x);")); + s.append(TString("vec4 atan(vec4 y_over_x);")); + + // + // Exponential Functions. + // + s.append(TString("float pow(float x, float y);")); + s.append(TString("vec2 pow(vec2 x, vec2 y);")); + s.append(TString("vec3 pow(vec3 x, vec3 y);")); + s.append(TString("vec4 pow(vec4 x, vec4 y);")); + + s.append(TString("float exp(float x);")); + s.append(TString("vec2 exp(vec2 x);")); + s.append(TString("vec3 exp(vec3 x);")); + s.append(TString("vec4 exp(vec4 x);")); + + s.append(TString("float log(float x);")); + s.append(TString("vec2 log(vec2 x);")); + s.append(TString("vec3 log(vec3 x);")); + s.append(TString("vec4 log(vec4 x);")); + + s.append(TString("float exp2(float x);")); + s.append(TString("vec2 exp2(vec2 x);")); + s.append(TString("vec3 exp2(vec3 x);")); + s.append(TString("vec4 exp2(vec4 x);")); + + s.append(TString("float log2(float x);")); + s.append(TString("vec2 log2(vec2 x);")); + s.append(TString("vec3 log2(vec3 x);")); + s.append(TString("vec4 log2(vec4 x);")); + + s.append(TString("float sqrt(float x);")); + s.append(TString("vec2 sqrt(vec2 x);")); + s.append(TString("vec3 sqrt(vec3 x);")); + s.append(TString("vec4 sqrt(vec4 x);")); + + s.append(TString("float inversesqrt(float x);")); + s.append(TString("vec2 inversesqrt(vec2 x);")); + s.append(TString("vec3 inversesqrt(vec3 x);")); + s.append(TString("vec4 inversesqrt(vec4 x);")); + + // + // Common Functions. + // + s.append(TString("float abs(float x);")); + s.append(TString("vec2 abs(vec2 x);")); + s.append(TString("vec3 abs(vec3 x);")); + s.append(TString("vec4 abs(vec4 x);")); + + s.append(TString("float sign(float x);")); + s.append(TString("vec2 sign(vec2 x);")); + s.append(TString("vec3 sign(vec3 x);")); + s.append(TString("vec4 sign(vec4 x);")); + + s.append(TString("float floor(float x);")); + s.append(TString("vec2 floor(vec2 x);")); + s.append(TString("vec3 floor(vec3 x);")); + s.append(TString("vec4 floor(vec4 x);")); + + s.append(TString("float ceil(float x);")); + s.append(TString("vec2 ceil(vec2 x);")); + s.append(TString("vec3 ceil(vec3 x);")); + s.append(TString("vec4 ceil(vec4 x);")); + + s.append(TString("float fract(float x);")); + s.append(TString("vec2 fract(vec2 x);")); + s.append(TString("vec3 fract(vec3 x);")); + s.append(TString("vec4 fract(vec4 x);")); + + s.append(TString("float mod(float x, float y);")); + s.append(TString("vec2 mod(vec2 x, float y);")); + s.append(TString("vec3 mod(vec3 x, float y);")); + s.append(TString("vec4 mod(vec4 x, float y);")); + s.append(TString("vec2 mod(vec2 x, vec2 y);")); + s.append(TString("vec3 mod(vec3 x, vec3 y);")); + s.append(TString("vec4 mod(vec4 x, vec4 y);")); + + s.append(TString("float min(float x, float y);")); + s.append(TString("vec2 min(vec2 x, float y);")); + s.append(TString("vec3 min(vec3 x, float y);")); + s.append(TString("vec4 min(vec4 x, float y);")); + s.append(TString("vec2 min(vec2 x, vec2 y);")); + s.append(TString("vec3 min(vec3 x, vec3 y);")); + s.append(TString("vec4 min(vec4 x, vec4 y);")); + + s.append(TString("float max(float x, float y);")); + s.append(TString("vec2 max(vec2 x, float y);")); + s.append(TString("vec3 max(vec3 x, float y);")); + s.append(TString("vec4 max(vec4 x, float y);")); + s.append(TString("vec2 max(vec2 x, vec2 y);")); + s.append(TString("vec3 max(vec3 x, vec3 y);")); + s.append(TString("vec4 max(vec4 x, vec4 y);")); + + s.append(TString("float clamp(float x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, float minVal, float maxVal);")); + s.append(TString("vec3 clamp(vec3 x, float minVal, float maxVal);")); + s.append(TString("vec4 clamp(vec4 x, float minVal, float maxVal);")); + s.append(TString("vec2 clamp(vec2 x, vec2 minVal, vec2 maxVal);")); + s.append(TString("vec3 clamp(vec3 x, vec3 minVal, vec3 maxVal);")); + s.append(TString("vec4 clamp(vec4 x, vec4 minVal, vec4 maxVal);")); + + s.append(TString("float mix(float x, float y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, float a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, float a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, float a);")); + s.append(TString("vec2 mix(vec2 x, vec2 y, vec2 a);")); + s.append(TString("vec3 mix(vec3 x, vec3 y, vec3 a);")); + s.append(TString("vec4 mix(vec4 x, vec4 y, vec4 a);")); + + s.append(TString("float step(float edge, float x);")); + s.append(TString("vec2 step(vec2 edge, vec2 x);")); + s.append(TString("vec3 step(vec3 edge, vec3 x);")); + s.append(TString("vec4 step(vec4 edge, vec4 x);")); + s.append(TString("vec2 step(float edge, vec2 x);")); + s.append(TString("vec3 step(float edge, vec3 x);")); + s.append(TString("vec4 step(float edge, vec4 x);")); + + s.append(TString("float smoothstep(float edge0, float edge1, float x);")); + s.append(TString("vec2 smoothstep(vec2 edge0, vec2 edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(vec3 edge0, vec3 edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(vec4 edge0, vec4 edge1, vec4 x);")); + s.append(TString("vec2 smoothstep(float edge0, float edge1, vec2 x);")); + s.append(TString("vec3 smoothstep(float edge0, float edge1, vec3 x);")); + s.append(TString("vec4 smoothstep(float edge0, float edge1, vec4 x);")); + + // + // Geometric Functions. + // + s.append(TString("float length(float x);")); + s.append(TString("float length(vec2 x);")); + s.append(TString("float length(vec3 x);")); + s.append(TString("float length(vec4 x);")); + + s.append(TString("float distance(float p0, float p1);")); + s.append(TString("float distance(vec2 p0, vec2 p1);")); + s.append(TString("float distance(vec3 p0, vec3 p1);")); + s.append(TString("float distance(vec4 p0, vec4 p1);")); + + s.append(TString("float dot(float x, float y);")); + s.append(TString("float dot(vec2 x, vec2 y);")); + s.append(TString("float dot(vec3 x, vec3 y);")); + s.append(TString("float dot(vec4 x, vec4 y);")); + + s.append(TString("vec3 cross(vec3 x, vec3 y);")); + s.append(TString("float normalize(float x);")); + s.append(TString("vec2 normalize(vec2 x);")); + s.append(TString("vec3 normalize(vec3 x);")); + s.append(TString("vec4 normalize(vec4 x);")); + + s.append(TString("float faceforward(float N, float I, float Nref);")); + s.append(TString("vec2 faceforward(vec2 N, vec2 I, vec2 Nref);")); + s.append(TString("vec3 faceforward(vec3 N, vec3 I, vec3 Nref);")); + s.append(TString("vec4 faceforward(vec4 N, vec4 I, vec4 Nref);")); + + s.append(TString("float reflect(float I, float N);")); + s.append(TString("vec2 reflect(vec2 I, vec2 N);")); + s.append(TString("vec3 reflect(vec3 I, vec3 N);")); + s.append(TString("vec4 reflect(vec4 I, vec4 N);")); + + s.append(TString("float refract(float I, float N, float eta);")); + s.append(TString("vec2 refract(vec2 I, vec2 N, float eta);")); + s.append(TString("vec3 refract(vec3 I, vec3 N, float eta);")); + s.append(TString("vec4 refract(vec4 I, vec4 N, float eta);")); + + // + // Matrix Functions. + // + s.append(TString("mat2 matrixCompMult(mat2 x, mat2 y);")); + s.append(TString("mat3 matrixCompMult(mat3 x, mat3 y);")); + s.append(TString("mat4 matrixCompMult(mat4 x, mat4 y);")); + + // + // Vector relational functions. + // + s.append(TString("bvec2 lessThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 lessThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 lessThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 lessThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 lessThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 lessThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 lessThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThan(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThan(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThan(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThan(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThan(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThan(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 greaterThanEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 greaterThanEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 greaterThanEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 greaterThanEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 greaterThanEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(vec2 x, vec2 y);")); + s.append(TString("bvec3 equal(vec3 x, vec3 y);")); + s.append(TString("bvec4 equal(vec4 x, vec4 y);")); + + s.append(TString("bvec2 equal(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 equal(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 equal(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 equal(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 equal(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 equal(bvec4 x, bvec4 y);")); + + s.append(TString("bvec2 notEqual(vec2 x, vec2 y);")); + s.append(TString("bvec3 notEqual(vec3 x, vec3 y);")); + s.append(TString("bvec4 notEqual(vec4 x, vec4 y);")); + + s.append(TString("bvec2 notEqual(ivec2 x, ivec2 y);")); + s.append(TString("bvec3 notEqual(ivec3 x, ivec3 y);")); + s.append(TString("bvec4 notEqual(ivec4 x, ivec4 y);")); + + s.append(TString("bvec2 notEqual(bvec2 x, bvec2 y);")); + s.append(TString("bvec3 notEqual(bvec3 x, bvec3 y);")); + s.append(TString("bvec4 notEqual(bvec4 x, bvec4 y);")); + + s.append(TString("bool any(bvec2 x);")); + s.append(TString("bool any(bvec3 x);")); + s.append(TString("bool any(bvec4 x);")); + + s.append(TString("bool all(bvec2 x);")); + s.append(TString("bool all(bvec3 x);")); + s.append(TString("bool all(bvec4 x);")); + + s.append(TString("bvec2 not(bvec2 x);")); + s.append(TString("bvec3 not(bvec3 x);")); + s.append(TString("bvec4 not(bvec4 x);")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord);")); + + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord);")); + + // + // Noise functions. + // + // s.append(TString("float noise1(float x);")); + // s.append(TString("float noise1(vec2 x);")); + // s.append(TString("float noise1(vec3 x);")); + // s.append(TString("float noise1(vec4 x);")); + + // s.append(TString("vec2 noise2(float x);")); + // s.append(TString("vec2 noise2(vec2 x);")); + // s.append(TString("vec2 noise2(vec3 x);")); + // s.append(TString("vec2 noise2(vec4 x);")); + + // s.append(TString("vec3 noise3(float x);")); + // s.append(TString("vec3 noise3(vec2 x);")); + // s.append(TString("vec3 noise3(vec3 x);")); + // s.append(TString("vec3 noise3(vec4 x);")); + + // s.append(TString("vec4 noise4(float x);")); + // s.append(TString("vec4 noise4(vec2 x);")); + // s.append(TString("vec4 noise4(vec3 x);")); + // s.append(TString("vec4 noise4(vec4 x);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Prototypes for built-in functions seen by vertex shaders only. + // + //============================================================================ + + TString& s = BuiltInFunctionsVertex; + + // + // Geometric Functions. + // + s.append(TString("vec4 ftransform();")); + + // + // Texture Functions. + // + s.append(TString("vec4 texture2DLod(sampler2D sampler, vec2 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec3 coord, float lod);")); + s.append(TString("vec4 texture2DProjLod(sampler2D sampler, vec4 coord, float lod);")); + + s.append(TString("vec4 textureCubeLod(samplerCube sampler, vec3 coord, float lod);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Prototypes for built-in functions seen by fragment shaders only. + // + //============================================================================ + + TString& s = BuiltInFunctionsFragment; + + // + // Texture Functions. + // + s.append(TString("vec4 texture2D(sampler2D sampler, vec2 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);")); + s.append(TString("vec4 texture2DProj(sampler2D sampler, vec4 coord, float bias);")); + + s.append(TString("vec4 textureCube(samplerCube sampler, vec3 coord, float bias);")); + + // s.append(TString("float dFdx(float p);")); + // s.append(TString("vec2 dFdx(vec2 p);")); + // s.append(TString("vec3 dFdx(vec3 p);")); + // s.append(TString("vec4 dFdx(vec4 p);")); + + // s.append(TString("float dFdy(float p);")); + // s.append(TString("vec2 dFdy(vec2 p);")); + // s.append(TString("vec3 dFdy(vec3 p);")); + // s.append(TString("vec4 dFdy(vec4 p);")); + + s.append(TString("float fwidth(float p);")); + s.append(TString("vec2 fwidth(vec2 p);")); + s.append(TString("vec3 fwidth(vec3 p);")); + s.append(TString("vec4 fwidth(vec4 p);")); + + s.append(TString("\n")); + } + { + //============================================================================ + // + // Standard Uniforms + // + //============================================================================ + + TString& s = StandardUniforms; + + // + // Depth range in window coordinates + // + s.append(TString("struct gl_DepthRangeParameters {")); + s.append(TString(" float near;")); // n // FIXME: highp + s.append(TString(" float far;")); // f // FIXME: highp + s.append(TString(" float diff;")); // f - n // FIXME: highp + s.append(TString("};")); + s.append(TString("uniform gl_DepthRangeParameters gl_DepthRange;")); + + s.append(TString("\n")); + } + + builtInStrings[EShLangFragment].push_back(BuiltInFunctions.c_str()); + builtInStrings[EShLangFragment].push_back(BuiltInFunctionsFragment); + builtInStrings[EShLangFragment].push_back(StandardUniforms); + + builtInStrings[EShLangVertex].push_back(BuiltInFunctions); + builtInStrings[EShLangVertex].push_back(BuiltInFunctionsVertex); + builtInStrings[EShLangVertex].push_back(StandardUniforms); +} + +void TBuiltIns::initialize(const TBuiltInResource &resources) +{ + TString builtIns; + + // Implementation dependent constants + char builtInConstant[80]; + + sprintf(builtInConstant, "const int gl_MaxVertexAttribs = %d;", resources.maxVertexAttribs); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVertexUniformVectors = %d;", resources.maxVertexUniformVectors); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVaryingVectors = %d;", resources.maxVaryingVectors); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxVertexTextureImageUnits = %d;", resources.maxVertexTextureImageUnits); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxCombinedTextureImageUnits = %d;", resources.maxCombinedTextureImageUnits); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxTextureImageUnits = %d;", resources.maxTextureImageUnits); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxFragmentUniformVectors = %d;", resources.maxFragmentUniformVectors); + builtIns.append(TString(builtInConstant)); + + sprintf(builtInConstant, "const int gl_MaxDrawBuffers = %d;", resources.maxDrawBuffers); + builtIns.append(TString(builtInConstant)); + + builtInStrings[EShLangFragment].push_back(builtIns); + builtInStrings[EShLangVertex].push_back(builtIns); +} + +void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(language) { + + case EShLangFragment: { + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragCoord"), TType(EbtFloat, EvqFragCoord, 4))); // FIXME: mediump + symbolTable.insert(*new TVariable(NewPoolTString("gl_FrontFacing"), TType(EbtBool, EvqFrontFacing, 1))); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragColor"), TType(EbtFloat, EvqFragColor, 4))); // FIXME: mediump + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData[gl_MaxDrawBuffers]"), TType(EbtFloat, EvqFragData, 4))); // FIXME: mediump + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointCoord"), TType(EbtFloat, EvqPointCoord, 2))); // FIXME: mediump + + } + break; + + case EShLangVertex: + symbolTable.insert(*new TVariable(NewPoolTString("gl_Position"), TType(EbtFloat, EvqPosition, 4))); // FIXME: highp + symbolTable.insert(*new TVariable(NewPoolTString("gl_PointSize"), TType(EbtFloat, EvqPointSize, 1))); // FIXME: mediump + break; + default: break; + } + + // + // Next, identify which built-ins from the already loaded headers have + // a mapping to an operator. Those that are not identified as such are + // expected to be resolved through a library of functions, versus as + // operations. + // + symbolTable.relateToOperator("not", EOpVectorLogicalNot); + + symbolTable.relateToOperator("matrixCompMult", EOpMul); + symbolTable.relateToOperator("mod", EOpMod); + + symbolTable.relateToOperator("equal", EOpVectorEqual); + symbolTable.relateToOperator("notEqual", EOpVectorNotEqual); + symbolTable.relateToOperator("lessThan", EOpLessThan); + symbolTable.relateToOperator("greaterThan", EOpGreaterThan); + symbolTable.relateToOperator("lessThanEqual", EOpLessThanEqual); + symbolTable.relateToOperator("greaterThanEqual", EOpGreaterThanEqual); + + symbolTable.relateToOperator("radians", EOpRadians); + symbolTable.relateToOperator("degrees", EOpDegrees); + symbolTable.relateToOperator("sin", EOpSin); + symbolTable.relateToOperator("cos", EOpCos); + symbolTable.relateToOperator("tan", EOpTan); + symbolTable.relateToOperator("asin", EOpAsin); + symbolTable.relateToOperator("acos", EOpAcos); + symbolTable.relateToOperator("atan", EOpAtan); + + symbolTable.relateToOperator("pow", EOpPow); + symbolTable.relateToOperator("exp2", EOpExp2); + symbolTable.relateToOperator("log", EOpLog); + symbolTable.relateToOperator("exp", EOpExp); + symbolTable.relateToOperator("log2", EOpLog2); + symbolTable.relateToOperator("sqrt", EOpSqrt); + symbolTable.relateToOperator("inversesqrt", EOpInverseSqrt); + + symbolTable.relateToOperator("abs", EOpAbs); + symbolTable.relateToOperator("sign", EOpSign); + symbolTable.relateToOperator("floor", EOpFloor); + symbolTable.relateToOperator("ceil", EOpCeil); + symbolTable.relateToOperator("fract", EOpFract); + symbolTable.relateToOperator("min", EOpMin); + symbolTable.relateToOperator("max", EOpMax); + symbolTable.relateToOperator("clamp", EOpClamp); + symbolTable.relateToOperator("mix", EOpMix); + symbolTable.relateToOperator("step", EOpStep); + symbolTable.relateToOperator("smoothstep", EOpSmoothStep); + + symbolTable.relateToOperator("length", EOpLength); + symbolTable.relateToOperator("distance", EOpDistance); + symbolTable.relateToOperator("dot", EOpDot); + symbolTable.relateToOperator("cross", EOpCross); + symbolTable.relateToOperator("normalize", EOpNormalize); + symbolTable.relateToOperator("forward", EOpFaceForward); + symbolTable.relateToOperator("reflect", EOpReflect); + symbolTable.relateToOperator("refract", EOpRefract); + + symbolTable.relateToOperator("any", EOpAny); + symbolTable.relateToOperator("all", EOpAll); + + switch(language) + { + case EShLangVertex: + break; + case EShLangFragment: + // symbolTable.relateToOperator("dFdx", EOpDPdx); + // symbolTable.relateToOperator("dFdy", EOpDPdy); + // symbolTable.relateToOperator("fwidth", EOpFwidth); + break; + case EShLangPack: + case EShLangUnpack: + symbolTable.relateToOperator("itof", EOpItof); + symbolTable.relateToOperator("ftoi", EOpFtoi); + symbolTable.relateToOperator("skipPixels", EOpSkipPixels); + symbolTable.relateToOperator("readInput", EOpReadInput); + symbolTable.relateToOperator("writePixel", EOpWritePixel); + symbolTable.relateToOperator("bitmapLSB", EOpBitmapLsb); + symbolTable.relateToOperator("bitmapMSB", EOpBitmapMsb); + symbolTable.relateToOperator("writeOutput", EOpWriteOutput); + symbolTable.relateToOperator("readPixel", EOpReadPixel); + break; + default: assert(false && "Language not supported"); + } +} + +void IdentifyBuiltIns(EShLanguage language, TSymbolTable& symbolTable, const TBuiltInResource &resources) +{ + // + // First, insert some special built-in variables that are not in + // the built-in header files. + // + switch(language) { + + case EShLangFragment: { + // Set up gl_FragData. The array size. + TType fragData(EbtFloat, EvqFragColor, 4, false, true); + fragData.setArraySize(resources.maxDrawBuffers); + symbolTable.insert(*new TVariable(NewPoolTString("gl_FragData"), fragData)); + } + break; + + default: break; + } +} + +const char* GetPreprocessorBuiltinString() +{ + static const char *PreprocessorBuiltinString = ""; + + return PreprocessorBuiltinString; +} diff --git a/Compiler/Initialize.h b/Compiler/Initialize.h new file mode 100644 index 000000000..99b0dfc24 --- /dev/null +++ b/Compiler/Initialize.h @@ -0,0 +1,35 @@ +// +// Copyright (c) 2002-2010 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 _INITIALIZE_INCLUDED_ +#define _INITIALIZE_INCLUDED_ + +#include "ResourceLimits.h" +#include "Common.h" +#include "ShHandle.h" +#include "SymbolTable.h" + +typedef TVector TBuiltInStrings; + +class TBuiltIns { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + void initialize(); + void initialize(const TBuiltInResource& resources); + TBuiltInStrings* getBuiltInStrings() { return builtInStrings; } +protected: + TBuiltInStrings builtInStrings[EShLangCount]; +}; + +void IdentifyBuiltIns(EShLanguage, TSymbolTable&); +void IdentifyBuiltIns(EShLanguage, TSymbolTable&, const TBuiltInResource &resources); +bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink&, TSymbolTable*, EShLanguage language = EShLangCount); +bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource *resources, TSymbolTable*); +const char* GetPreprocessorBuiltinString(); +extern "C" int InitPreprocessor(void); +extern "C" int FinalizePreprocessor(void); + +#endif // _INITIALIZE_INCLUDED_ diff --git a/Compiler/InitializeDll.cpp b/Compiler/InitializeDll.cpp new file mode 100644 index 000000000..fd7c3abeb --- /dev/null +++ b/Compiler/InitializeDll.cpp @@ -0,0 +1,119 @@ +// +// Copyright (c) 2002-2010 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 "InitializeDll.h" +#include "InitializeGlobals.h" +#include "InitializeParseContext.h" + +#include "ShaderLang.h" + +OS_TLSIndex ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + +bool InitProcess() +{ + if (ThreadInitializeIndex != OS_INVALID_TLS_INDEX) { + // + // Function is re-entrant. + // + return true; + } + + ThreadInitializeIndex = OS_AllocTLSIndex(); + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitProcess(): Failed to allocate TLS area for init flag"); + return false; + } + + + if (!InitializePoolIndex()) { + assert(0 && "InitProcess(): Failed to initalize global pool"); + return false; + } + + if (!InitializeParseContextIndex()) { + assert(0 && "InitProcess(): Failed to initalize parse context"); + return false; + } + + InitThread(); + return true; +} + + +bool InitThread() +{ + // + // This function is re-entrant + // + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitThread(): Process hasn't been initalised."); + return false; + } + + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) + return true; + + InitializeGlobalPools(); + + if (!InitializeGlobalParseContext()) + return false; + + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)1)) { + assert(0 && "InitThread(): Unable to set init flag."); + return false; + } + + return true; +} + + +bool DetachThread() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + // + // Function is re-entrant and this thread may not have been initalised. + // + if (OS_GetTLSValue(ThreadInitializeIndex) != 0) { + if (!OS_SetTLSValue(ThreadInitializeIndex, (void *)0)) { + assert(0 && "DetachThread(): Unable to clear init flag."); + success = false; + } + + FreeGlobalPools(); + + if (!FreeParseContext()) + success = false; + } + + return success; +} + +bool DetachProcess() +{ + bool success = true; + + if (ThreadInitializeIndex == OS_INVALID_TLS_INDEX) + return true; + + ShFinalize(); + + success = DetachThread(); + + FreePoolIndex(); + + if (!FreeParseContextIndex()) + success = false; + + OS_FreeTLSIndex(ThreadInitializeIndex); + ThreadInitializeIndex = OS_INVALID_TLS_INDEX; + + return success; +} diff --git a/Compiler/InitializeDll.h b/Compiler/InitializeDll.h new file mode 100644 index 000000000..ec7b3032f --- /dev/null +++ b/Compiler/InitializeDll.h @@ -0,0 +1,19 @@ +// +// Copyright (c) 2002-2010 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 __INITIALIZEDLL_H +#define __INITIALIZEDLL_H + + +#include "osinclude.h" + + +bool InitProcess(); +bool InitThread(); +bool DetachThread(); +bool DetachProcess(); + +#endif // __INITIALIZEDLL_H + diff --git a/Compiler/InitializeGlobals.h b/Compiler/InitializeGlobals.h new file mode 100644 index 000000000..842a45281 --- /dev/null +++ b/Compiler/InitializeGlobals.h @@ -0,0 +1,15 @@ +// +// Copyright (c) 2002-2010 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 __INITIALIZE_GLOBALS_INCLUDED_ +#define __INITIALIZE_GLOBALS_INCLUDED_ + +void InitializeGlobalPools(); +void FreeGlobalPools(); +bool InitializePoolIndex(); +void FreePoolIndex(); + +#endif // __INITIALIZE_GLOBALS_INCLUDED_ diff --git a/Compiler/InitializeParseContext.h b/Compiler/InitializeParseContext.h new file mode 100644 index 000000000..45fc3f3a2 --- /dev/null +++ b/Compiler/InitializeParseContext.h @@ -0,0 +1,17 @@ +// +// Copyright (c) 2002-2010 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 __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#define __INITIALIZE_PARSE_CONTEXT_INCLUDED_ +#include "osinclude.h" + +bool InitializeParseContextIndex(); +bool InitializeGlobalParseContext(); +bool FreeParseContext(); +bool FreeParseContextIndex(); + + +#endif // __INITIALIZE_PARSE_CONTEXT_INCLUDED_ diff --git a/Compiler/IntermTraverse.cpp b/Compiler/IntermTraverse.cpp new file mode 100644 index 000000000..6a6188427 --- /dev/null +++ b/Compiler/IntermTraverse.cpp @@ -0,0 +1,293 @@ +// +// Copyright (c) 2002-2010 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 "intermediate.h" + +// +// Traverse the intermediate representation tree, and +// call a node type specific function for each node. +// Done recursively through the member function Traverse(). +// Node types can be skipped if their function to call is 0, +// but their subtree will still be traversed. +// Nodes with children can have their whole subtree skipped +// if preVisit is turned on and the type specific function +// returns false. +// +// preVisit, postVisit, and rightToLeft control what order +// nodes are visited in. +// + +// +// Traversal functions for terminals are straighforward.... +// +void TIntermSymbol::traverse(TIntermTraverser* it) +{ + it->visitSymbol(this); +} + +void TIntermConstantUnion::traverse(TIntermTraverser* it) +{ + it->visitConstantUnion(this); +} + +// +// Traverse a binary node. +// +void TIntermBinary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + // + // visit the node before children if pre-visiting. + // + if(it->preVisit) + { + visit = it->visitBinary(PreVisit, this); + } + + // + // Visit the children, in the right order. + // + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(right) + { + right->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && left) + { + left->traverse(it); + } + } + else + { + if(left) + { + left->traverse(it); + } + + if(it->inVisit) + { + visit = it->visitBinary(InVisit, this); + } + + if(visit && right) + { + right->traverse(it); + } + } + + it->decrementDepth(); + } + + // + // Visit the node after the children, if requested and the traversal + // hasn't been cancelled yet. + // + if(visit && it->postVisit) + { + it->visitBinary(PostVisit, this); + } +} + +// +// Traverse a unary node. Same comments in binary node apply here. +// +void TIntermUnary::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitUnary(PreVisit, this); + + if (visit) { + it->incrementDepth(); + operand->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitUnary(PostVisit, this); +} + +// +// Traverse an aggregate node. Same comments in binary node apply here. +// +void TIntermAggregate::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitAggregate(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + for(TIntermSequence::reverse_iterator sit = sequence.rbegin(); sit != sequence.rend(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.front()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + else + { + for(TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + (*sit)->traverse(it); + + if(visit && it->inVisit) + { + if(*sit != sequence.back()) + { + visit = it->visitAggregate(InVisit, this); + } + } + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitAggregate(PostVisit, this); + } +} + +// +// Traverse a selection node. Same comments in binary node apply here. +// +void TIntermSelection::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitSelection(PreVisit, this); + + if (visit) { + it->incrementDepth(); + if (it->rightToLeft) { + if (falseBlock) + falseBlock->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + condition->traverse(it); + } else { + condition->traverse(it); + if (trueBlock) + trueBlock->traverse(it); + if (falseBlock) + falseBlock->traverse(it); + } + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitSelection(PostVisit, this); +} + +// +// Traverse a loop node. Same comments in binary node apply here. +// +void TIntermLoop::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if(it->preVisit) + { + visit = it->visitLoop(PreVisit, this); + } + + if(visit) + { + it->incrementDepth(); + + if(it->rightToLeft) + { + if(terminal) + { + terminal->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(test) + { + test->traverse(it); + } + } + else + { + if(test) + { + test->traverse(it); + } + + if(body) + { + body->traverse(it); + } + + if(terminal) + { + terminal->traverse(it); + } + } + + it->decrementDepth(); + } + + if(visit && it->postVisit) + { + it->visitLoop(PostVisit, this); + } +} + +// +// Traverse a branch node. Same comments in binary node apply here. +// +void TIntermBranch::traverse(TIntermTraverser* it) +{ + bool visit = true; + + if (it->preVisit) + visit = it->visitBranch(PreVisit, this); + + if (visit && expression) { + it->incrementDepth(); + expression->traverse(it); + it->decrementDepth(); + } + + if (visit && it->postVisit) + it->visitBranch(PostVisit, this); +} + diff --git a/Compiler/Intermediate.cpp b/Compiler/Intermediate.cpp new file mode 100644 index 000000000..54fa79656 --- /dev/null +++ b/Compiler/Intermediate.cpp @@ -0,0 +1,1483 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// Build the intermediate representation. +// + +#include "localintermediate.h" +#include "QualifierAlive.h" +#include "RemoveTree.h" +#include + +bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray); + +//////////////////////////////////////////////////////////////////////////// +// +// First set of functions are to help build the intermediate representation. +// These functions are not member functions of the nodes. +// They are called from parser productions. +// +///////////////////////////////////////////////////////////////////////////// + +// +// Add a terminal node for an identifier in an expression. +// +// Returns the added node. +// +TIntermSymbol* TIntermediate::addSymbol(int id, const TString& name, const TType& type, TSourceLoc line) +{ + TIntermSymbol* node = new TIntermSymbol(id, name, type); + node->setLine(line); + + return node; +} + +// +// Connect two nodes with a new parent that does a binary operation on the nodes. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line, TSymbolTable& symbolTable) +{ + switch (op) { + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector() || left->getType().getBasicType() == EbtStruct) { + return 0; + } + break; + case EOpLogicalOr: + case EOpLogicalXor: + case EOpLogicalAnd: + if (left->getType().getBasicType() != EbtBool || left->getType().isMatrix() || left->getType().isArray() || left->getType().isVector()) { + return 0; + } + break; + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMul: + if (left->getType().getBasicType() == EbtStruct || left->getType().getBasicType() == EbtBool) + return 0; + default: break; + } + + // + // First try converting the children to compatible types. + // + + if (!(left->getType().getStruct() && right->getType().getStruct())) { + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child) + right = child; + else { + child = addConversion(op, right->getType(), left); + if (child) + left = child; + else + return 0; + } + } else { + if (left->getType() != right->getType()) + return 0; + } + + + // + // Need a new node holding things together then. Make + // one and promote it to the right type. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = right->getLine(); + node->setLine(line); + + node->setLeft(left); + node->setRight(right); + if (! node->promote(infoSink)) + return 0; + + TIntermConstantUnion *leftTempConstant = left->getAsConstantUnion(); + TIntermConstantUnion *rightTempConstant = right->getAsConstantUnion(); + + if (leftTempConstant) + leftTempConstant = left->getAsConstantUnion(); + + if (rightTempConstant) + rightTempConstant = right->getAsConstantUnion(); + + // + // See if we can fold constants. + // + + TIntermTyped* typedReturnNode = 0; + if ( leftTempConstant && rightTempConstant) { + typedReturnNode = leftTempConstant->fold(node->getOp(), rightTempConstant, infoSink); + + if (typedReturnNode) + return typedReturnNode; + } + + return node; +} + +// +// Connect two nodes through an assignment. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + // + // Like adding binary math, except the conversion can only go + // from right to left. + // + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = left->getLine(); + node->setLine(line); + + TIntermTyped* child = addConversion(op, left->getType(), right); + if (child == 0) + return 0; + + node->setLeft(left); + node->setRight(child); + if (! node->promote(infoSink)) + return 0; + + return node; +} + +// +// Connect two nodes through an index operator, where the left node is the base +// of an array or struct, and the right node is a direct or indirect offset. +// +// Returns the added node. +// The caller should set the type of the returned node. +// +TIntermTyped* TIntermediate::addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc line) +{ + TIntermBinary* node = new TIntermBinary(op); + if (line == 0) + line = index->getLine(); + node->setLine(line); + node->setLeft(base); + node->setRight(index); + + // caller should set the type + + return node; +} + +// +// Add one node as the parent of another that it operates on. +// +// Returns the added node. +// +TIntermTyped* TIntermediate::addUnaryMath(TOperator op, TIntermNode* childNode, TSourceLoc line, TSymbolTable& symbolTable) +{ + TIntermUnary* node; + TIntermTyped* child = childNode->getAsTyped(); + + if (child == 0) { + infoSink.info.message(EPrefixInternalError, "Bad type in AddUnaryMath", line); + return 0; + } + + switch (op) { + case EOpLogicalNot: + if (child->getType().getBasicType() != EbtBool || child->getType().isMatrix() || child->getType().isArray() || child->getType().isVector()) { + return 0; + } + break; + + case EOpPostIncrement: + case EOpPreIncrement: + case EOpPostDecrement: + case EOpPreDecrement: + case EOpNegative: + if (child->getType().getBasicType() == EbtStruct || child->getType().isArray()) + return 0; + default: break; + } + + // + // Do we need to promote the operand? + // + // Note: Implicit promotions were removed from the language. + // + TBasicType newType = EbtVoid; + switch (op) { + case EOpConstructInt: newType = EbtInt; break; + case EOpConstructBool: newType = EbtBool; break; + case EOpConstructFloat: newType = EbtFloat; break; + default: break; + } + + if (newType != EbtVoid) { + child = addConversion(op, TType(newType, EvqTemporary, child->getNominalSize(), + child->isMatrix(), + child->isArray()), + child); + if (child == 0) + return 0; + } + + // + // For constructors, we are now done, it's all in the conversion. + // + switch (op) { + case EOpConstructInt: + case EOpConstructBool: + case EOpConstructFloat: + return child; + default: break; + } + + TIntermConstantUnion *childTempConstant = 0; + if (child->getAsConstantUnion()) + childTempConstant = child->getAsConstantUnion(); + + // + // Make a new node for the operator. + // + node = new TIntermUnary(op); + if (line == 0) + line = child->getLine(); + node->setLine(line); + node->setOperand(child); + + if (! node->promote(infoSink)) + return 0; + + if (childTempConstant) { + TIntermTyped* newChild = childTempConstant->fold(op, 0, infoSink); + + if (newChild) + return newChild; + } + + return node; +} + +// +// This is the safe way to change the operator on an aggregate, as it +// does lots of error checking and fixing. Especially for establishing +// a function call's operation on it's set of parameters. Sequences +// of instructions are also aggregates, but they just direnctly set +// their operator to EOpSequence. +// +// Returns an aggregate node, which could be the one passed in if +// it was already an aggregate. +// +TIntermAggregate* TIntermediate::setAggregateOperator(TIntermNode* node, TOperator op, TSourceLoc line) +{ + TIntermAggregate* aggNode; + + // + // Make sure we have an aggregate. If not turn it into one. + // + if (node) { + aggNode = node->getAsAggregate(); + if (aggNode == 0 || aggNode->getOp() != EOpNull) { + // + // Make an aggregate containing this node. + // + aggNode = new TIntermAggregate(); + aggNode->getSequence().push_back(node); + if (line == 0) + line = node->getLine(); + } + } else + aggNode = new TIntermAggregate(); + + // + // Set the operator. + // + aggNode->setOperator(op); + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Convert one type to another. +// +// Returns the node representing the conversion, which could be the same +// node passed in if no conversion was needed. +// +// Return 0 if a conversion can't be done. +// +TIntermTyped* TIntermediate::addConversion(TOperator op, const TType& type, TIntermTyped* node) +{ + // + // Does the base type allow operation? + // + switch (node->getBasicType()) { + case EbtVoid: + case EbtSampler2D: + case EbtSamplerCube: + return 0; + default: break; + } + + // + // Otherwise, if types are identical, no problem + // + if (type == node->getType()) + return node; + + // + // If one's a structure, then no conversions. + // + if (type.getStruct() || node->getType().getStruct()) + return 0; + + // + // If one's an array, then no conversions. + // + if (type.isArray() || node->getType().isArray()) + return 0; + + TBasicType promoteTo; + + switch (op) { + // + // Explicit conversions + // + case EOpConstructBool: + promoteTo = EbtBool; + break; + case EOpConstructFloat: + promoteTo = EbtFloat; + break; + case EOpConstructInt: + promoteTo = EbtInt; + break; + default: + // + // implicit conversions were removed from the language. + // + if (type.getBasicType() != node->getType().getBasicType()) + return 0; + // + // Size and structure could still differ, but that's + // handled by operator promotion. + // + return node; + } + + if (node->getAsConstantUnion()) { + + return (promoteConstantUnion(promoteTo, node->getAsConstantUnion())); + } else { + + // + // Add a new newNode for the conversion. + // + TIntermUnary* newNode = 0; + + TOperator newOp = EOpNull; + switch (promoteTo) { + case EbtFloat: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToFloat; break; + case EbtBool: newOp = EOpConvBoolToFloat; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getBasicType()) { + case EbtInt: newOp = EOpConvIntToBool; break; + case EbtFloat: newOp = EOpConvFloatToBool; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getBasicType()) { + case EbtBool: newOp = EOpConvBoolToInt; break; + case EbtFloat: newOp = EOpConvFloatToInt; break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion node", node->getLine()); + return 0; + } + break; + default: + infoSink.info.message(EPrefixInternalError, "Bad promotion type", node->getLine()); + return 0; + } + + TType type(promoteTo, EvqTemporary, node->getNominalSize(), node->isMatrix(), node->isArray()); + newNode = new TIntermUnary(newOp, type); + newNode->setLine(node->getLine()); + newNode->setOperand(node); + + return newNode; + } +} + +// +// Safe way to combine two nodes into an aggregate. Works with null pointers, +// a node that's not a aggregate yet, etc. +// +// Returns the resulting aggregate, unless 0 was passed in for +// both existing nodes. +// +TIntermAggregate* TIntermediate::growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc line) +{ + if (left == 0 && right == 0) + return 0; + + TIntermAggregate* aggNode = 0; + if (left) + aggNode = left->getAsAggregate(); + if (!aggNode || aggNode->getOp() != EOpNull) { + aggNode = new TIntermAggregate; + if (left) + aggNode->getSequence().push_back(left); + } + + if (right) + aggNode->getSequence().push_back(right); + + if (line != 0) + aggNode->setLine(line); + + return aggNode; +} + +// +// Turn an existing node into an aggregate. +// +// Returns an aggregate, unless 0 was passed in for the existing node. +// +TIntermAggregate* TIntermediate::makeAggregate(TIntermNode* node, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggNode = new TIntermAggregate; + aggNode->getSequence().push_back(node); + + if (line != 0) + aggNode->setLine(line); + else + aggNode->setLine(node->getLine()); + + return aggNode; +} + +// +// For "if" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are in the +// nodePair. +// +// Returns the selection node created. +// +TIntermNode* TIntermediate::addSelection(TIntermTyped* cond, TIntermNodePair nodePair, TSourceLoc line) +{ + // + // For compile time constant selections, prune the code and + // test now. + // + + if (cond->getAsTyped() && cond->getAsTyped()->getAsConstantUnion()) { + if (cond->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getBConst()) + return nodePair.node1; + else + return nodePair.node2; + } + + TIntermSelection* node = new TIntermSelection(cond, nodePair.node1, nodePair.node2); + node->setLine(line); + + return node; +} + + +TIntermTyped* TIntermediate::addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc line) +{ + if (left->getType().getQualifier() == EvqConst && right->getType().getQualifier() == EvqConst) { + return right; + } else { + TIntermTyped *commaAggregate = growAggregate(left, right, line); + commaAggregate->getAsAggregate()->setOperator(EOpComma); + commaAggregate->setType(right->getType()); + commaAggregate->getTypePointer()->changeQualifier(EvqTemporary); + return commaAggregate; + } +} + +// +// For "?:" test nodes. There are three children; a condition, +// a true path, and a false path. The two paths are specified +// as separate parameters. +// +// Returns the selection node created, or 0 if one could not be. +// +TIntermTyped* TIntermediate::addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc line) +{ + // + // Get compatible types. + // + TIntermTyped* child = addConversion(EOpSequence, trueBlock->getType(), falseBlock); + if (child) + falseBlock = child; + else { + child = addConversion(EOpSequence, falseBlock->getType(), trueBlock); + if (child) + trueBlock = child; + else + return 0; + } + + // + // See if all the operands are constant, then fold it otherwise not. + // + + if (cond->getAsConstantUnion() && trueBlock->getAsConstantUnion() && falseBlock->getAsConstantUnion()) { + if (cond->getAsConstantUnion()->getUnionArrayPointer()->getBConst()) + return trueBlock; + else + return falseBlock; + } + + // + // Make a selection node. + // + TIntermSelection* node = new TIntermSelection(cond, trueBlock, falseBlock, trueBlock->getType()); + node->setLine(line); + + return node; +} + +// +// Constant terminal nodes. Has a union that contains bool, float or int constants +// +// Returns the constant union node created. +// + +TIntermConstantUnion* TIntermediate::addConstantUnion(constUnion* unionArrayPointer, const TType& t, TSourceLoc line) +{ + TIntermConstantUnion* node = new TIntermConstantUnion(unionArrayPointer, t); + node->setLine(line); + + return node; +} + +TIntermTyped* TIntermediate::addSwizzle(TVectorFields& fields, TSourceLoc line) +{ + + TIntermAggregate* node = new TIntermAggregate(EOpSequence); + + node->setLine(line); + TIntermConstantUnion* constIntNode; + TIntermSequence &sequenceVector = node->getSequence(); + constUnion* unionArray; + + for (int i = 0; i < fields.num; i++) { + unionArray = new constUnion[1]; + unionArray->setIConst(fields.offsets[i]); + constIntNode = addConstantUnion(unionArray, TType(EbtInt, EvqConst), line); + sequenceVector.push_back(constIntNode); + } + + return node; +} + +// +// Create loop nodes. +// +TIntermNode* TIntermediate::addLoop(TIntermNode *init, TIntermNode* body, TIntermTyped* test, TIntermTyped* terminal, bool testFirst, TSourceLoc line) +{ + TIntermNode* node = new TIntermLoop(init, body, test, terminal, testFirst); + node->setLine(line); + + return node; +} + +// +// Add branches. +// +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TSourceLoc line) +{ + return addBranch(branchOp, 0, line); +} + +TIntermBranch* TIntermediate::addBranch(TOperator branchOp, TIntermTyped* expression, TSourceLoc line) +{ + TIntermBranch* node = new TIntermBranch(branchOp, expression); + node->setLine(line); + + return node; +} + +// +// This is to be executed once the final root is put on top by the parsing +// process. +// +bool TIntermediate::postProcess(TIntermNode* root, EShLanguage language) +{ + if (root == 0) + return true; + + // + // First, finish off the top level sequence, if any + // + TIntermAggregate* aggRoot = root->getAsAggregate(); + if (aggRoot && aggRoot->getOp() == EOpNull) + aggRoot->setOperator(EOpSequence); + + return true; +} + +// +// This deletes the tree. +// +void TIntermediate::remove(TIntermNode* root) +{ + if (root) + RemoveAllTreeNodes(root); +} + +//////////////////////////////////////////////////////////////// +// +// Member functions of the nodes used for building the tree. +// +//////////////////////////////////////////////////////////////// + +// +// Say whether or not an operation node changes the value of a variable. +// +// Returns true if state is modified. +// +bool TIntermOperator::modifiesState() const +{ + switch (op) { + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + case EOpAssign: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpVectorTimesMatrixAssign: + case EOpVectorTimesScalarAssign: + case EOpMatrixTimesScalarAssign: + case EOpMatrixTimesMatrixAssign: + case EOpDivAssign: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + return true; + default: + return false; + } +} + +// +// returns true if the operator is for one of the constructors +// +bool TIntermOperator::isConstructor() const +{ + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + case EOpConstructStruct: + return true; + default: + return false; + } +} +// +// Make sure the type of a unary operator is appropriate for its +// combination of operation and operand type. +// +// Returns false in nothing makes sense. +// +bool TIntermUnary::promote(TInfoSink&) +{ + switch (op) { + case EOpLogicalNot: + if (operand->getBasicType() != EbtBool) + return false; + break; + case EOpBitwiseNot: + if (operand->getBasicType() != EbtInt) + return false; + break; + case EOpNegative: + case EOpPostIncrement: + case EOpPostDecrement: + case EOpPreIncrement: + case EOpPreDecrement: + if (operand->getBasicType() == EbtBool) + return false; + break; + + // operators for built-ins are already type checked against their prototype + case EOpAny: + case EOpAll: + case EOpVectorLogicalNot: + return true; + + default: + if (operand->getBasicType() != EbtFloat) + return false; + } + + setType(operand->getType()); + + return true; +} + +// +// Establishes the type of the resultant operation, as well as +// makes the operator the correct one for the operands. +// +// Returns false if operator can't work on operands. +// +bool TIntermBinary::promote(TInfoSink& infoSink) +{ + int size = left->getNominalSize(); + if (right->getNominalSize() > size) + size = right->getNominalSize(); + + TBasicType type = left->getBasicType(); + + // + // Arrays have to be exact matches. + // + if ((left->isArray() || right->isArray()) && (left->getType() != right->getType())) + return false; + + // + // Base assumption: just make the type the same as the left + // operand. Then only deviations from this need be coded. + // + setType(TType(type, EvqTemporary, left->getNominalSize(), left->isMatrix())); + + // + // Array operations. + // + if (left->isArray()) { + + switch (op) { + + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + setType(TType(EbtBool)); + break; + + // + // Set array information. + // + case EOpAssign: + case EOpInitialize: + getType().setArraySize(left->getType().getArraySize()); + getType().setArrayInformationType(left->getType().getArrayInformationType()); + break; + + default: + return false; + } + + return true; + } + + // + // All scalars. Code after this test assumes this case is removed! + // + if (size == 1) { + + switch (op) { + + // + // Promote to conditional + // + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + setType(TType(EbtBool)); + break; + + // + // And and Or operate on conditionals + // + case EOpLogicalAnd: + case EOpLogicalOr: + if (left->getBasicType() != EbtBool || right->getBasicType() != EbtBool) + return false; + setType(TType(EbtBool)); + break; + + // + // Check for integer only operands. + // + case EOpMod: + case EOpRightShift: + case EOpLeftShift: + case EOpAnd: + case EOpInclusiveOr: + case EOpExclusiveOr: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + break; + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (left->getBasicType() != EbtInt || right->getBasicType() != EbtInt) + return false; + // fall through + + // + // Everything else should have matching types + // + default: + if (left->getBasicType() != right->getBasicType() || + left->isMatrix() != right->isMatrix()) + return false; + } + + return true; + } + + // + // Are the sizes compatible? + // + if ( left->getNominalSize() != size && left->getNominalSize() != 1 || + right->getNominalSize() != size && right->getNominalSize() != 1) + return false; + + // + // Can these two operands be combined? + // + switch (op) { + case EOpMul: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrix; + else { + op = EOpMatrixTimesScalar; + setType(TType(type, EvqTemporary, size, true)); + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + op = EOpMatrixTimesVector; + setType(TType(type, EvqTemporary, size, false)); + } else { + op = EOpMatrixTimesScalar; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrix; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + op = EOpVectorTimesScalar; + setType(TType(type, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpMulAssign: + if (!left->isMatrix() && right->isMatrix()) { + if (left->isVector()) + op = EOpVectorTimesMatrixAssign; + else { + return false; + } + } else if (left->isMatrix() && !right->isMatrix()) { + if (right->isVector()) { + return false; + } else { + op = EOpMatrixTimesScalarAssign; + } + } else if (left->isMatrix() && right->isMatrix()) { + op = EOpMatrixTimesMatrixAssign; + } else if (!left->isMatrix() && !right->isMatrix()) { + if (left->isVector() && right->isVector()) { + // leave as component product + } else if (left->isVector() || right->isVector()) { + if (! left->isVector()) + return false; + op = EOpVectorTimesScalarAssign; + setType(TType(type, EvqTemporary, size, false)); + } + } else { + infoSink.info.message(EPrefixInternalError, "Missing elses", getLine()); + return false; + } + break; + case EOpAssign: + case EOpInitialize: + if (left->getNominalSize() != right->getNominalSize()) + return false; + // fall through + case EOpAdd: + case EOpSub: + case EOpDiv: + case EOpMod: + case EOpAddAssign: + case EOpSubAssign: + case EOpDivAssign: + case EOpModAssign: + if (left->isMatrix() && right->isVector() || + left->isVector() && right->isMatrix() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(type, EvqTemporary, size, left->isMatrix() || right->isMatrix())); + break; + + case EOpEqual: + case EOpNotEqual: + case EOpLessThan: + case EOpGreaterThan: + case EOpLessThanEqual: + case EOpGreaterThanEqual: + if (left->isMatrix() && right->isVector() || + left->isVector() && right->isMatrix() || + left->getBasicType() != right->getBasicType()) + return false; + setType(TType(EbtBool)); + break; + +default: + return false; + } + + // + // One more check for assignment. The Resulting type has to match the left operand. + // + switch (op) { + case EOpAssign: + case EOpInitialize: + case EOpAddAssign: + case EOpSubAssign: + case EOpMulAssign: + case EOpDivAssign: + case EOpModAssign: + case EOpAndAssign: + case EOpInclusiveOrAssign: + case EOpExclusiveOrAssign: + case EOpLeftShiftAssign: + case EOpRightShiftAssign: + if (getType() != left->getType()) + return false; + break; + default: + break; + } + + return true; +} + +bool CompareStruct(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray) +{ + TTypeList* fields = leftNodeType.getStruct(); + + size_t structSize = fields->size(); + int index = 0; + + for (size_t j = 0; j < structSize; j++) { + int size = (*fields)[j].type->getObjectSize(); + for (int i = 0; i < size; i++) { + if ((*fields)[j].type->getBasicType() == EbtStruct) { + if (!CompareStructure(*(*fields)[j].type, &rightUnionArray[index], &leftUnionArray[index])) + return false; + } else { + if (leftUnionArray[index] != rightUnionArray[index]) + return false; + index++; + } + + } + } + return true; +} + +bool CompareStructure(const TType& leftNodeType, constUnion* rightUnionArray, constUnion* leftUnionArray) +{ + if (leftNodeType.isArray()) { + TType typeWithoutArrayness = leftNodeType; + typeWithoutArrayness.clearArrayness(); + + int arraySize = leftNodeType.getArraySize(); + + for (int i = 0; i < arraySize; ++i) { + int offset = typeWithoutArrayness.getObjectSize() * i; + if (!CompareStruct(typeWithoutArrayness, &rightUnionArray[offset], &leftUnionArray[offset])) + return false; + } + } else + return CompareStruct(leftNodeType, rightUnionArray, leftUnionArray); + + return true; +} + +// +// The fold functions see if an operation on a constant can be done in place, +// without generating run-time code. +// +// Returns the node to keep using, which may or may not be the node passed in. +// + +TIntermTyped* TIntermConstantUnion::fold(TOperator op, TIntermTyped* constantNode, TInfoSink& infoSink) +{ + constUnion *unionArray = getUnionArrayPointer(); + int objectSize = getType().getObjectSize(); + + if (constantNode) { // binary operations + TIntermConstantUnion *node = constantNode->getAsConstantUnion(); + constUnion *rightUnionArray = node->getUnionArrayPointer(); + TType returnType = getType(); + + // for a case like float f = 1.2 + vec4(2,3,4,5); + if (constantNode->getType().getObjectSize() == 1 && objectSize > 1) { + rightUnionArray = new constUnion[objectSize]; + for (int i = 0; i < objectSize; ++i) + rightUnionArray[i] = *node->getUnionArrayPointer(); + returnType = getType(); + } else if (constantNode->getType().getObjectSize() > 1 && objectSize == 1) { + // for a case like float f = vec4(2,3,4,5) + 1.2; + unionArray = new constUnion[constantNode->getType().getObjectSize()]; + for (int i = 0; i < constantNode->getType().getObjectSize(); ++i) + unionArray[i] = *getUnionArrayPointer(); + returnType = node->getType(); + objectSize = constantNode->getType().getObjectSize(); + } + + constUnion* tempConstArray = 0; + TIntermConstantUnion *tempNode; + + bool boolNodeFlag = false; + switch(op) { + case EOpAdd: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] + rightUnionArray[i]; + } + break; + case EOpSub: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] - rightUnionArray[i]; + } + break; + + case EOpMul: + case EOpVectorTimesScalar: + case EOpMatrixTimesScalar: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] * rightUnionArray[i]; + } + break; + case EOpMatrixTimesMatrix: + if (getType().getBasicType() != EbtFloat || node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix multiply", getLine()); + return 0; + } + {// support MSVC++6.0 + int size = getNominalSize(); + tempConstArray = new constUnion[size*size]; + for (int row = 0; row < size; row++) { + for (int column = 0; column < size; column++) { + tempConstArray[size * column + row].setFConst(0.0f); + for (int i = 0; i < size; i++) { + tempConstArray[size * column + row].setFConst(tempConstArray[size * column + row].getFConst() + unionArray[i * size + row].getFConst() * (rightUnionArray[column * size + i].getFConst())); + } + } + } + } + break; + case EOpDiv: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) { + switch (getType().getBasicType()) { + case EbtFloat: + if (rightUnionArray[i] == 0.0f) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setFConst(FLT_MAX); + } else + tempConstArray[i].setFConst(unionArray[i].getFConst() / rightUnionArray[i].getFConst()); + break; + + case EbtInt: + if (rightUnionArray[i] == 0) { + infoSink.info.message(EPrefixWarning, "Divide by zero error during constant folding", getLine()); + tempConstArray[i].setIConst(INT_MAX); + } else + tempConstArray[i].setIConst(unionArray[i].getIConst() / rightUnionArray[i].getIConst()); + break; + default: + infoSink.info.message(EPrefixInternalError, "Constant folding cannot be done for \"/\"", getLine()); + return 0; + } + } + } + break; + + case EOpMatrixTimesVector: + if (node->getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for matrix times vector", getLine()); + return 0; + } + tempConstArray = new constUnion[getNominalSize()]; + + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j*size + i].getFConst()) * rightUnionArray[j].getFConst())); + } + } + } + + tempNode = new TIntermConstantUnion(tempConstArray, node->getType()); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpVectorTimesMatrix: + if (getType().getBasicType() != EbtFloat) { + infoSink.info.message(EPrefixInternalError, "Constant Folding cannot be done for vector times matrix", getLine()); + return 0; + } + + tempConstArray = new constUnion[getNominalSize()]; + {// support MSVC++6.0 + for (int size = getNominalSize(), i = 0; i < size; i++) { + tempConstArray[i].setFConst(0.0f); + for (int j = 0; j < size; j++) { + tempConstArray[i].setFConst(tempConstArray[i].getFConst() + ((unionArray[j].getFConst()) * rightUnionArray[i*size + j].getFConst())); + } + } + } + break; + + case EOpMod: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] % rightUnionArray[i]; + } + break; + + case EOpRightShift: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] >> rightUnionArray[i]; + } + break; + + case EOpLeftShift: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] << rightUnionArray[i]; + } + break; + + case EOpAnd: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] & rightUnionArray[i]; + } + break; + case EOpInclusiveOr: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] | rightUnionArray[i]; + } + break; + case EOpExclusiveOr: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] ^ rightUnionArray[i]; + } + break; + + case EOpLogicalAnd: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] && rightUnionArray[i]; + } + break; + + case EOpLogicalOr: // this code is written for possible future use, will not get executed currently + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + tempConstArray[i] = unionArray[i] || rightUnionArray[i]; + } + break; + + case EOpLogicalXor: + tempConstArray = new constUnion[objectSize]; + {// support MSVC++6.0 + for (int i = 0; i < objectSize; i++) + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst((unionArray[i] == rightUnionArray[i]) ? false : true); break; + default: assert(false && "Default missing"); + } + } + break; + + case EOpLessThan: + assert(objectSize == 1); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(*unionArray < *rightUnionArray); + returnType = TType(EbtBool, EvqConst); + break; + case EOpGreaterThan: + assert(objectSize == 1); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(*unionArray > *rightUnionArray); + returnType = TType(EbtBool, EvqConst); + break; + case EOpLessThanEqual: + { + assert(objectSize == 1); + constUnion constant; + constant.setBConst(*unionArray > *rightUnionArray); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EvqConst); + break; + } + case EOpGreaterThanEqual: + { + assert(objectSize == 1); + constUnion constant; + constant.setBConst(*unionArray < *rightUnionArray); + tempConstArray = new constUnion[1]; + tempConstArray->setBConst(!constant.getBConst()); + returnType = TType(EbtBool, EvqConst); + break; + } + + case EOpEqual: + if (getType().getBasicType() == EbtStruct) { + if (!CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] != rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + case EOpNotEqual: + if (getType().getBasicType() == EbtStruct) { + if (CompareStructure(node->getType(), node->getUnionArrayPointer(), unionArray)) + boolNodeFlag = true; + } else { + for (int i = 0; i < objectSize; i++) { + if (unionArray[i] == rightUnionArray[i]) { + boolNodeFlag = true; + break; // break out of for loop + } + } + } + + tempConstArray = new constUnion[1]; + if (!boolNodeFlag) { + tempConstArray->setBConst(true); + } + else { + tempConstArray->setBConst(false); + } + + tempNode = new TIntermConstantUnion(tempConstArray, TType(EbtBool, EvqConst)); + tempNode->setLine(getLine()); + + return tempNode; + + default: + infoSink.info.message(EPrefixInternalError, "Invalid operator for constant folding", getLine()); + return 0; + } + tempNode = new TIntermConstantUnion(tempConstArray, returnType); + tempNode->setLine(getLine()); + + return tempNode; + } else { + // + // Do unary operations + // + TIntermConstantUnion *newNode = 0; + constUnion* tempConstArray = new constUnion[objectSize]; + for (int i = 0; i < objectSize; i++) { + switch(op) { + case EOpNegative: + switch (getType().getBasicType()) { + case EbtFloat: tempConstArray[i].setFConst(-unionArray[i].getFConst()); break; + case EbtInt: tempConstArray[i].setIConst(-unionArray[i].getIConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + case EOpLogicalNot: // this code is written for possible future use, will not get executed currently + switch (getType().getBasicType()) { + case EbtBool: tempConstArray[i].setBConst(!unionArray[i].getBConst()); break; + default: + infoSink.info.message(EPrefixInternalError, "Unary operation not folded into constant", getLine()); + return 0; + } + break; + default: + return 0; + } + } + newNode = new TIntermConstantUnion(tempConstArray, getType()); + newNode->setLine(getLine()); + return newNode; + } + + return this; +} + +TIntermTyped* TIntermediate::promoteConstantUnion(TBasicType promoteTo, TIntermConstantUnion* node) +{ + constUnion *rightUnionArray = node->getUnionArrayPointer(); + int size = node->getType().getObjectSize(); + + constUnion *leftUnionArray = new constUnion[size]; + + for (int i=0; i < size; i++) { + + switch (promoteTo) { + case EbtFloat: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setFConst(static_cast(rightUnionArray[i].getIConst())); + break; + case EbtBool: + leftUnionArray[i].setFConst(static_cast(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i] = rightUnionArray[i]; + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtInt: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtBool: + leftUnionArray[i].setIConst(static_cast(rightUnionArray[i].getBConst())); + break; + case EbtFloat: + leftUnionArray[i].setIConst(static_cast(rightUnionArray[i].getFConst())); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + break; + case EbtBool: + switch (node->getType().getBasicType()) { + case EbtInt: + leftUnionArray[i].setBConst(rightUnionArray[i].getIConst() != 0); + break; + case EbtBool: + leftUnionArray[i] = rightUnionArray[i]; + break; + case EbtFloat: + leftUnionArray[i].setBConst(rightUnionArray[i].getFConst() != 0.0f); + break; + default: + infoSink.info.message(EPrefixInternalError, "Cannot promote", node->getLine()); + return 0; + } + + break; + default: + infoSink.info.message(EPrefixInternalError, "Incorrect data type found", node->getLine()); + return 0; + } + + } + + const TType& t = node->getType(); + + return addConstantUnion(leftUnionArray, TType(promoteTo, t.getQualifier(), t.getNominalSize(), t.isMatrix(), t.isArray()), node->getLine()); +} + +void TIntermAggregate::addToPragmaTable(const TPragmaTable& pTable) +{ + assert(!pragmaTable); + pragmaTable = new TPragmaTable(); + *pragmaTable = pTable; +} + diff --git a/Compiler/Link.cpp b/Compiler/Link.cpp new file mode 100644 index 000000000..9f5819bac --- /dev/null +++ b/Compiler/Link.cpp @@ -0,0 +1,63 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// The top level algorithms for linking multiple +// shaders together. +// +#include "Common.h" +#include "ShHandle.h" + +// +// Actual link object, derived from the shader handle base classes. +// +class TGenericLinker : public TLinker { +public: + TGenericLinker(EShExecutable e, int dOptions) : TLinker(e, infoSink), debugOptions(dOptions) { } + bool link(TCompilerList&, TUniformMap*) { return true; } + void getAttributeBindings(ShBindingTable const **t) const { } + TInfoSink infoSink; + int debugOptions; +}; + +// +// The internal view of a uniform/float object exchanged with the driver. +// +class TUniformLinkedMap : public TUniformMap { +public: + TUniformLinkedMap() { } + virtual int getLocation(const char* name) { return 0; } +}; + +TShHandleBase* ConstructLinker(EShExecutable executable, int debugOptions) +{ + return new TGenericLinker(executable, debugOptions); +} + +void DeleteLinker(TShHandleBase* linker) +{ + delete linker; +} + +TUniformMap* ConstructUniformMap() +{ + return new TUniformLinkedMap(); +} + +void DeleteUniformMap(TUniformMap* map) +{ + delete map; +} + +TShHandleBase* ConstructBindings() +{ + return 0; +} + +void DeleteBindingList(TShHandleBase* bindingList) +{ + delete bindingList; +} diff --git a/Compiler/MMap.h b/Compiler/MMap.h new file mode 100644 index 000000000..a30867151 --- /dev/null +++ b/Compiler/MMap.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2010 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 _MMAP_INCLUDED_ +#define _MMAP_INCLUDED_ + +// +// Encapsulate memory mapped files +// + +class TMMap { +public: + TMMap(const char* fileName) : + fSize(-1), // -1 is the error value returned by GetFileSize() + fp(NULL), + fBuff(0) // 0 is the error value returned by MapViewOfFile() + { + if ((fp = fopen(fileName, "r")) == NULL) + return; + char c = getc(fp); + fSize = 0; + while (c != EOF) { + fSize++; + c = getc(fp); + } + if (c == EOF) + fSize++; + rewind(fp); + fBuff = (char*)malloc(sizeof(char) * fSize); + int count = 0; + c = getc(fp); + while (c != EOF) { + fBuff[count++] = c; + c = getc(fp); + } + fBuff[count++] = c; + } + + char* getData() { return fBuff; } + int getSize() { return fSize; } + + ~TMMap() { + if (fp != NULL) + fclose(fp); + } + +private: + int fSize; // size of file to map in + FILE *fp; + char* fBuff; // the actual data; +}; + +#endif // _MMAP_INCLUDED_ diff --git a/Compiler/OutputHLSL.cpp b/Compiler/OutputHLSL.cpp new file mode 100644 index 000000000..eaa158902 --- /dev/null +++ b/Compiler/OutputHLSL.cpp @@ -0,0 +1,1184 @@ +// +// Copyright (c) 2002-2010 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 "OutputHLSL.h" + +#include "InfoSink.h" +#include "debug.h" + +namespace sh +{ +OutputHLSL::OutputHLSL(TParseContext &context) : TIntermTraverser(true, true, true), context(context) +{ +} + +void OutputHLSL::header() +{ + EShLanguage language = context.language; + TInfoSinkBase &out = context.infoSink.obj; + + if (language == EShLangFragment) + { + TString uniforms; + TString varyingInput; + TString varyingGlobals; + + TSymbolTableLevel *symbols = context.symbolTable.getGlobalLevel(); + int semanticIndex = 0; + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if (qualifier == EvqUniform) + { + uniforms += "uniform " + typeString(type) + " " + name + arrayString(type) + ";\n"; + } + else if (qualifier == EvqVaryingIn || qualifier == EvqInvariantVaryingIn) + { + char semantic[100]; + sprintf(semantic, " : TEXCOORD%d", semanticIndex); + semanticIndex += type.isArray() ? type.getArraySize() : 1; + + varyingInput += " " + typeString(type) + " " + name + arrayString(type) + semantic + ";\n"; + varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n"; + } + } + } + + out << uniforms; + out << "\n"; + out << "struct PS_INPUT\n" // FIXME: Prevent name clashes + "{\n"; + out << varyingInput; + out << "};\n" + "\n"; + out << varyingGlobals; + out << "\n" + "struct PS_OUTPUT\n" // FIXME: Prevent name clashes + "{\n" + " float4 gl_Color[1] : COLOR;\n" + "};\n" + "\n" + "static float4 gl_Color[1] = {float4(0, 0, 0, 0)};\n" + "\n" + "float4 gl_texture2D(sampler2D s, float2 t)\n" + "{\n" + " return tex2D(s, t);\n" + "}\n" + "\n" + "float4 gl_texture2DProj(sampler2D s, float3 t)\n" + "{\n" + " return tex2Dproj(s, float4(t.x, t.y, 0, t.z));\n" + "}\n" + "float4 gl_texture2DBias(sampler2D s, float2 t, float bias)\n" + "{\n" + " return tex2Dbias(s, float4(t.x, t.y, 0, bias));\n" + "}\n" + "\n" + "float4 gl_textureCube(samplerCUBE s, float3 t)\n" + "{\n" + " return texCUBE(s, t);\n" + "}\n" + "\n"; + } + else + { + TString uniforms; + TString attributeInput; + TString attributeGlobals; + TString varyingOutput; + TString varyingGlobals; + TString globals; + + TSymbolTableLevel *symbols = context.symbolTable.getGlobalLevel(); + int semanticIndex = 0; + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if (qualifier == EvqUniform) + { + uniforms += "uniform " + typeString(type) + " " + name + arrayString(type) + ";\n"; + } + else if (qualifier == EvqAttribute) + { + char semantic[100]; + sprintf(semantic, " : TEXCOORD%d", semanticIndex); + semanticIndex += type.isArray() ? type.getArraySize() : 1; + + attributeInput += " " + typeString(type) + " " + name + arrayString(type) + semantic + ";\n"; + attributeGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n"; + } + else if (qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut) + { + varyingOutput += " " + typeString(type) + " " + name + arrayString(type) + " : TEXCOORD0;\n"; // Actual semantic index assigned during link + varyingGlobals += "static " + typeString(type) + " " + name + arrayString(type) + " = " + initializer(type) + ";\n"; + } + else if (qualifier == EvqGlobal) + { + globals += typeString(type) + " " + name + arrayString(type) + ";\n"; + } + else UNREACHABLE(); + } + } + + out << "uniform float2 gl_HalfPixelSize;\n"; + out << "\n"; + out << uniforms; + out << "\n"; + out << globals; + out << "\n"; + out << "struct VS_INPUT\n" // FIXME: Prevent name clashes + "{\n"; + out << attributeInput; + out << "};\n" + "\n"; + out << attributeGlobals; + out << "\n" + "struct VS_OUTPUT\n" // FIXME: Prevent name clashes + "{\n" + " float4 gl_Position : POSITION;\n" + " float gl_PointSize : PSIZE;\n"; + out << varyingOutput; + out << "};\n" + "\n" + "static float4 gl_Position = float4(0, 0, 0, 0);\n" + "static float gl_PointSize = float(0);\n"; + out << varyingGlobals; + out << "\n"; + } + + out << "float vec1(float x)\n" // FIXME: Prevent name clashes + "{\n" + " return x;\n" + "}\n" + "\n" + "float vec1(float2 xy)\n" // FIXME: Prevent name clashes + "{\n" + " return xy[0];\n" + "}\n" + "\n" + "float vec1(float3 xyz)\n" // FIXME: Prevent name clashes + "{\n" + " return xyz[0];\n" + "}\n" + "\n" + "float vec1(float4 xyzw)\n" // FIXME: Prevent name clashes + "{\n" + " return xyzw[0];\n" + "}\n" + "\n" + "float2 vec2(float x)\n" // FIXME: Prevent name clashes + "{\n" + " return float2(x, x);\n" + "}\n" + "\n" + "float2 vec2(float x, float y)\n" // FIXME: Prevent name clashes + "{\n" + " return float2(x, y);\n" + "}\n" + "\n" + "float2 vec2(float2 xy)\n" // FIXME: Prevent name clashes + "{\n" + " return xy;\n" + "}\n" + "\n" + "float2 vec2(float3 xyz)\n" // FIXME: Prevent name clashes + "{\n" + " return float2(xyz[0], xyz[1]);\n" + "}\n" + "\n" + "float2 vec2(float4 xyzw)\n" // FIXME: Prevent name clashes + "{\n" + " return float2(xyzw[0], xyzw[1]);\n" + "}\n" + "\n" + "float3 vec3(float x)\n" // FIXME: Prevent name clashes + "{\n" + " return float3(x, x, x);\n" + "}\n" + "\n" + "float3 vec3(float x, float y, float z)\n" // FIXME: Prevent name clashes + "{\n" + " return float3(x, y, z);\n" + "}\n" + "\n" + "float3 vec3(float2 xy, float z)\n" // FIXME: Prevent name clashes + "{\n" + " return float3(xy[0], xy[1], z);\n" + "}\n" + "\n" + "float3 vec3(float x, float2 yz)\n" // FIXME: Prevent name clashes + "{\n" + " return float3(x, yz[0], yz[1]);\n" + "}\n" + "\n" + "float3 vec3(float3 xyz)\n" // FIXME: Prevent name clashes + "{\n" + " return xyz;\n" + "}\n" + "\n" + "float3 vec3(float4 xyzw)\n" // FIXME: Prevent name clashes + "{\n" + " return float3(xyzw[0], xyzw[1], xyzw[2]);\n" + "}\n" + "\n" + "float4 vec4(float x)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(x, x, x, x);\n" + "}\n" + "\n" + "float4 vec4(float x, float y, float z, float w)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(x, y, z, w);\n" + "}\n" + "\n" + "float4 vec4(float2 xy, float z, float w)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(xy[0], xy[1], z, w);\n" + "}\n" + "\n" + "float4 vec4(float x, float2 yz, float w)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(x, yz[0], yz[1], w);\n" + "}\n" + "\n" + "float4 vec4(float x, float y, float2 zw)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(x, y, zw[0], zw[1]);\n" + "}\n" + "\n" + "float4 vec4(float2 xy, float2 zw)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(xy[0], xy[1], zw[0], zw[1]);\n" + "}\n" + "\n" + "float4 vec4(float3 xyz, float w)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(xyz[0], xyz[1], xyz[2], w);\n" + "}\n" + "\n" + "float4 vec4(float x, float3 yzw)\n" // FIXME: Prevent name clashes + "{\n" + " return float4(x, yzw[0], yzw[1], yzw[2]);\n" + "}\n" + "\n" + "float4 vec4(float4 xyzw)\n" // FIXME: Prevent name clashes + "{\n" + " return xyzw;\n" + "}\n" + "\n" + "bool xor(bool p, bool q)\n" // FIXME: Prevent name clashes + "{\n" + " return (p || q) && !(p && q);\n" + "}\n" + "\n" + "float mod(float x, float y)\n" // FIXME: Prevent name clashes + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "float2 mod(float2 x, float y)\n" // FIXME: Prevent name clashes + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "float3 mod(float3 x, float y)\n" // FIXME: Prevent name clashes + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "float4 mod(float4 x, float y)\n" // FIXME: Prevent name clashes + "{\n" + " return x - y * floor(x / y);\n" + "}\n" + "\n"; +} + +void OutputHLSL::visitSymbol(TIntermSymbol *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + TString name = node->getSymbol(); + + if (name == "gl_FragColor") + { + out << "gl_Color[0]"; + } + else if (name == "gl_FragData") + { + out << "gl_Color"; + } + else + { + out << name; + } +} + +bool OutputHLSL::visitBinary(Visit visit, TIntermBinary *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + switch (node->getOp()) + { + case EOpAssign: outputTriplet(visit, "(", " = ", ")"); break; + case EOpInitialize: outputTriplet(visit, NULL, " = ", NULL); break; + case EOpAddAssign: outputTriplet(visit, NULL, " += ", NULL); break; + case EOpSubAssign: outputTriplet(visit, NULL, " -= ", NULL); break; + case EOpMulAssign: outputTriplet(visit, NULL, " *= ", NULL); break; + case EOpVectorTimesMatrixAssign: UNIMPLEMENTED(); /* FIXME */ out << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: outputTriplet(visit, NULL, " *= ", NULL); break; + case EOpMatrixTimesScalarAssign: UNIMPLEMENTED(); /* FIXME */ out << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: UNIMPLEMENTED(); /* FIXME */ out << "matrix mult second child into first child"; break; + case EOpDivAssign: outputTriplet(visit, NULL, " /= ", NULL); break; + case EOpModAssign: UNIMPLEMENTED(); /* FIXME */ out << "mod second child into first child"; break; + case EOpAndAssign: UNIMPLEMENTED(); /* FIXME */ out << "and second child into first child"; break; + case EOpInclusiveOrAssign: UNIMPLEMENTED(); /* FIXME */ out << "or second child into first child"; break; + case EOpExclusiveOrAssign: UNIMPLEMENTED(); /* FIXME */ out << "exclusive or second child into first child"; break; + case EOpLeftShiftAssign: UNIMPLEMENTED(); /* FIXME */ out << "left shift second child into first child"; break; + case EOpRightShiftAssign: UNIMPLEMENTED(); /* FIXME */ out << "right shift second child into first child"; break; + case EOpIndexDirect: outputTriplet(visit, NULL, "[", "]"); break; + case EOpIndexIndirect: outputTriplet(visit, NULL, "[", "]"); break; + case EOpIndexDirectStruct: UNIMPLEMENTED(); /* FIXME */ out << "direct index for structure"; break; + case EOpVectorSwizzle: + if (visit == InVisit) + { + out << "."; + + TIntermAggregate *swizzle = node->getRight()->getAsAggregate(); + + if (swizzle) + { + TIntermSequence &sequence = swizzle->getSequence(); + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermConstantUnion *element = (*sit)->getAsConstantUnion(); + + if (element) + { + int i = element->getUnionArrayPointer()[0].getIConst(); + + switch (i) + { + case 0: out << "x"; break; + case 1: out << "y"; break; + case 2: out << "z"; break; + case 3: out << "w"; break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); + } + } + else UNREACHABLE(); + + return false; // Fully processed + } + break; + case EOpAdd: outputTriplet(visit, "(", " + ", ")"); break; + case EOpSub: outputTriplet(visit, "(", " - ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + case EOpDiv: outputTriplet(visit, "(", " / ", ")"); break; + case EOpMod: UNIMPLEMENTED(); /* FIXME */ out << "mod"; break; + case EOpRightShift: UNIMPLEMENTED(); /* FIXME */ out << "right-shift"; break; + case EOpLeftShift: UNIMPLEMENTED(); /* FIXME */ out << "left-shift"; break; + case EOpAnd: UNIMPLEMENTED(); /* FIXME */ out << "bitwise and"; break; + case EOpInclusiveOr: UNIMPLEMENTED(); /* FIXME */ out << "inclusive-or"; break; + case EOpExclusiveOr: UNIMPLEMENTED(); /* FIXME */ out << "exclusive-or"; break; + case EOpEqual: outputTriplet(visit, "(", " == ", ")"); break; + case EOpNotEqual: outputTriplet(visit, "(", " != ", ")"); break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorTimesScalar: outputTriplet(visit, "(", " * ", ")"); break; + case EOpVectorTimesMatrix: UNIMPLEMENTED(); /* FIXME */ out << "vector-times-matrix"; break; + case EOpMatrixTimesVector: outputTriplet(visit, "mul(", ", ", ")"); break; + case EOpMatrixTimesScalar: UNIMPLEMENTED(); /* FIXME */ out << "matrix-scale"; break; + case EOpMatrixTimesMatrix: UNIMPLEMENTED(); /* FIXME */ out << "matrix-multiply"; break; + case EOpLogicalOr: outputTriplet(visit, "(", " || ", ")"); break; + case EOpLogicalXor: outputTriplet(visit, "xor(", ", ", ")"); break; // FIXME: Prevent name clashes + case EOpLogicalAnd: outputTriplet(visit, "(", " && ", ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitUnary(Visit visit, TIntermUnary *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + switch (node->getOp()) + { + case EOpNegative: outputTriplet(visit, "(-", NULL, ")"); break; + case EOpVectorLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break; + case EOpLogicalNot: outputTriplet(visit, "(!", NULL, ")"); break; + case EOpBitwiseNot: outputTriplet(visit, "(~", NULL, ")"); break; + case EOpPostIncrement: outputTriplet(visit, "(", NULL, "++)"); break; + case EOpPostDecrement: outputTriplet(visit, "(", NULL, "--)"); break; + case EOpPreIncrement: outputTriplet(visit, "(++", NULL, ")"); break; + case EOpPreDecrement: outputTriplet(visit, "(--", NULL, ")"); break; + case EOpConvIntToBool: + case EOpConvFloatToBool: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "bool(", NULL, ")"); break; + case 2: outputTriplet(visit, "bool2(", NULL, ")"); break; + case 3: outputTriplet(visit, "bool3(", NULL, ")"); break; + case 4: outputTriplet(visit, "bool4(", NULL, ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvBoolToFloat: + case EOpConvIntToFloat: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "float(", NULL, ")"); break; + case 2: outputTriplet(visit, "float2(", NULL, ")"); break; + case 3: outputTriplet(visit, "float3(", NULL, ")"); break; + case 4: outputTriplet(visit, "float4(", NULL, ")"); break; + default: UNREACHABLE(); + } + break; + case EOpConvFloatToInt: + case EOpConvBoolToInt: + switch (node->getOperand()->getType().getNominalSize()) + { + case 1: outputTriplet(visit, "int(", NULL, ")"); break; + case 2: outputTriplet(visit, "int2(", NULL, ")"); break; + case 3: outputTriplet(visit, "int3(", NULL, ")"); break; + case 4: outputTriplet(visit, "int4(", NULL, ")"); break; + default: UNREACHABLE(); + } + break; + case EOpRadians: outputTriplet(visit, "radians(", NULL, ")"); break; + case EOpDegrees: outputTriplet(visit, "degrees(", NULL, ")"); break; + case EOpSin: outputTriplet(visit, "sin(", NULL, ")"); break; + case EOpCos: outputTriplet(visit, "cos(", NULL, ")"); break; + case EOpTan: outputTriplet(visit, "tan(", NULL, ")"); break; + case EOpAsin: outputTriplet(visit, "asin(", NULL, ")"); break; + case EOpAcos: outputTriplet(visit, "acos(", NULL, ")"); break; + case EOpAtan: outputTriplet(visit, "atan(", NULL, ")"); break; + case EOpExp: outputTriplet(visit, "exp(", NULL, ")"); break; + case EOpLog: outputTriplet(visit, "log(", NULL, ")"); break; + case EOpExp2: outputTriplet(visit, "exp2(", NULL, ")"); break; + case EOpLog2: outputTriplet(visit, "log2(", NULL, ")"); break; + case EOpSqrt: outputTriplet(visit, "sqrt(", NULL, ")"); break; + case EOpInverseSqrt: outputTriplet(visit, "rsqrt(", NULL, ")"); break; + case EOpAbs: outputTriplet(visit, "abs(", NULL, ")"); break; + case EOpSign: outputTriplet(visit, "sign(", NULL, ")"); break; + case EOpFloor: outputTriplet(visit, "floor(", NULL, ")"); break; + case EOpCeil: outputTriplet(visit, "ceil(", NULL, ")"); break; + case EOpFract: outputTriplet(visit, "frac(", NULL, ")"); break; + case EOpLength: outputTriplet(visit, "length(", NULL, ")"); break; + case EOpNormalize: outputTriplet(visit, "normalize(", NULL, ")"); break; +// case EOpDPdx: outputTriplet(visit, "ddx(", NULL, ")"); break; +// case EOpDPdy: outputTriplet(visit, "ddy(", NULL, ")"); break; +// case EOpFwidth: outputTriplet(visit, "fwidth(", NULL, ")"); break; + case EOpAny: outputTriplet(visit, "any(", NULL, ")"); break; + case EOpAll: outputTriplet(visit, "all(", NULL, ")"); break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitAggregate(Visit visit, TIntermAggregate *node) +{ + EShLanguage language = context.language; + TInfoSinkBase &out = context.infoSink.obj; + + if (node->getOp() == EOpNull) + { + out.message(EPrefixError, "node is still EOpNull!"); + return true; + } + + switch (node->getOp()) + { + case EOpSequence: outputTriplet(visit, NULL, ";\n", ";\n"); break; + case EOpDeclaration: + if (visit == PreVisit) + { + TIntermSequence &sequence = node->getSequence(); + TIntermTyped *variable = sequence[0]->getAsTyped(); + bool visit = true; + + if (variable && variable->getQualifier() == EvqTemporary) + { + out << typeString(variable->getType()) + " "; + + for (TIntermSequence::iterator sit = sequence.begin(); sit != sequence.end(); sit++) + { + TIntermSymbol *symbol = (*sit)->getAsSymbolNode(); + + if (symbol) + { + symbol->traverse(this); + + out << arrayString(symbol->getType()); + } + else + { + (*sit)->traverse(this); + } + + if (visit && this->inVisit) + { + if (*sit != sequence.back()) + { + visit = this->visitAggregate(InVisit, node); + } + } + } + + if (visit && this->postVisit) + { + this->visitAggregate(PostVisit, node); + } + } + + return false; + } + else if (visit == InVisit) + { + out << ", "; + } + break; + case EOpComma: UNIMPLEMENTED(); /* FIXME */ out << "Comma\n"; return true; + case EOpFunction: + { + const TString &mangledName = node->getName(); + TString name = TString(mangledName.c_str(), mangledName.find_first_of('(')); + + if (visit == PreVisit) + { + if (name == "main") + { + TSymbolTableLevel *symbols = context.symbolTable.getGlobalLevel(); + + if (language == EShLangFragment) + { + out << "PS_OUTPUT main(PS_INPUT input)\n" // FIXME: Prevent name clashes + "{\n"; + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if(qualifier == EvqVaryingIn) + { + out << " " + name + " = input." + name + ";\n"; // FIXME: Prevent name clashes + } + } + } + } + else + { + out << "VS_OUTPUT main(VS_INPUT input)\n" // FIXME: Prevent name clashes + "{\n"; + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + const TType &type = variable->getType(); + TQualifier qualifier = type.getQualifier(); + + if (qualifier == EvqAttribute) + { + out << " " + name + " = input." + name + ";\n"; // FIXME: Prevent name clashes + } + } + } + } + + // Erase the (empty) argument list + TIntermSequence &sequence = node->getSequence(); + sequence.erase(sequence.begin()); + } + else + { + out << typeString(node->getType()) << " " << name << "("; + + TIntermSequence &sequence = node->getSequence(); + TIntermSequence &arguments = sequence[0]->getAsAggregate()->getSequence(); + + for (unsigned int i = 0; i < arguments.size(); i++) + { + TIntermSymbol *symbol = arguments[i]->getAsSymbolNode(); + + if (symbol) + { + const TType &type = symbol->getType(); + const TString &name = symbol->getSymbol(); + + out << typeString(type) + " " + name; + + if(i < arguments.size() - 1) + { + out << ", "; + } + } + else UNREACHABLE(); + } + + sequence.erase(sequence.begin()); + + out << ")\n" + "{\n"; + } + } + else if (visit == PostVisit) + { + if (name == "main") + { + if (language == EShLangFragment) + { + out << " PS_OUTPUT output;\n" // FIXME: Prevent name clashes + " output.gl_Color[0] = gl_Color[0];\n"; // FIXME: Prevent name clashes + + TSymbolTableLevel *symbols = context.symbolTable.getGlobalLevel(); + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + } + } + else + { + out << " VS_OUTPUT output;\n" // FIXME: Prevent name clashes + " output.gl_Position.x = gl_Position.x - gl_HalfPixelSize.x * gl_Position.w;\n" + " output.gl_Position.y = -(gl_Position.y - gl_HalfPixelSize.y * gl_Position.w);\n" + " output.gl_Position.z = (gl_Position.z + gl_Position.w) * 0.5;\n" + " output.gl_Position.w = gl_Position.w;\n" + " output.gl_PointSize = gl_PointSize;\n"; + + TSymbolTableLevel *symbols = context.symbolTable.getGlobalLevel(); + + for (TSymbolTableLevel::const_iterator namedSymbol = symbols->begin(); namedSymbol != symbols->end(); namedSymbol++) + { + const TSymbol *symbol = (*namedSymbol).second; + const TString &name = symbol->getName(); + + if (symbol->isVariable()) + { + const TVariable *variable = static_cast(symbol); + TQualifier qualifier = variable->getType().getQualifier(); + + if(qualifier == EvqVaryingOut || qualifier == EvqInvariantVaryingOut) + { + out << " output." + name + " = " + name + ";\n"; // FIXME: Prevent name clashes + } + } + } + } + + out << " return output;\n" // FIXME: Prevent name clashes + "}\n"; + } + else + { + out << "}\n"; + } + } + } + break; + case EOpFunctionCall: + { + if (visit == PreVisit) + { + const TString &mangledName = node->getName(); + TString name = TString(mangledName.c_str(), mangledName.find_first_of('(')); + + if (node->isUserDefined()) + { + out << name << "("; + } + else + { + if (name == "texture2D") + { + if (node->getSequence().size() == 2) + { + out << "gl_texture2D("; + } + else if (node->getSequence().size() == 3) + { + out << "gl_texture2DBias("; + } + else UNREACHABLE(); + } + else if (name == "texture2DProj") + { + out << "gl_texture2DProj("; + } + else if (name == "texture2DLod") + { + out << "gl_texture2DLod("; + UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component + } + else if (name == "texture2DProjLod") + { + out << "gl_texture2DProjLod("; + UNIMPLEMENTED(); // FIXME: Move lod to last texture coordinate component + } + else if (name == "textureCube") + { + out << "gl_textureCube("; // FIXME: Incorrect sampling location + } + else + { + UNIMPLEMENTED(); // FIXME + } + } + } + else if (visit == InVisit) + { + out << ", "; + } + else + { + out << ")"; + } + } + break; + case EOpParameters: outputTriplet(visit, "(", ", ", ")\n{\n"); break; + case EOpConstructFloat: outputTriplet(visit, "vec1(", NULL, ")"); break; + case EOpConstructVec2: outputTriplet(visit, "vec2(", ", ", ")"); break; + case EOpConstructVec3: outputTriplet(visit, "vec3(", ", ", ")"); break; + case EOpConstructVec4: outputTriplet(visit, "vec4(", ", ", ")"); break; + case EOpConstructBool: UNIMPLEMENTED(); /* FIXME */ out << "Construct bool"; break; + case EOpConstructBVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec2"; break; + case EOpConstructBVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec3"; break; + case EOpConstructBVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct bvec4"; break; + case EOpConstructInt: UNIMPLEMENTED(); /* FIXME */ out << "Construct int"; break; + case EOpConstructIVec2: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec2"; break; + case EOpConstructIVec3: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec3"; break; + case EOpConstructIVec4: UNIMPLEMENTED(); /* FIXME */ out << "Construct ivec4"; break; + case EOpConstructMat2: outputTriplet(visit, "float2x2(", ", ", ")"); break; + case EOpConstructMat3: outputTriplet(visit, "float3x3(", ", ", ")"); break; + case EOpConstructMat4: UNIMPLEMENTED(); /* FIXME */ out << "Construct mat4"; break; + case EOpConstructStruct: UNIMPLEMENTED(); /* FIXME */ out << "Construct structure"; break; + case EOpLessThan: outputTriplet(visit, "(", " < ", ")"); break; + case EOpGreaterThan: outputTriplet(visit, "(", " > ", ")"); break; + case EOpLessThanEqual: outputTriplet(visit, "(", " <= ", ")"); break; + case EOpGreaterThanEqual: outputTriplet(visit, "(", " >= ", ")"); break; + case EOpVectorEqual: outputTriplet(visit, "(", " == ", ")"); break; + case EOpVectorNotEqual: outputTriplet(visit, "(", " != ", ")"); break; + case EOpMod: outputTriplet(visit, "mod(", ", ", ")"); break; // FIXME: Prevent name clashes + case EOpPow: outputTriplet(visit, "pow(", ", ", ")"); break; + case EOpAtan: + if (node->getSequence().size() == 1) + { + outputTriplet(visit, "atan(", ", ", ")"); + } + else if (node->getSequence().size() == 2) + { + outputTriplet(visit, "atan2(", ", ", ")"); + } + else UNREACHABLE(); + break; + case EOpMin: outputTriplet(visit, "min(", ", ", ")"); break; + case EOpMax: outputTriplet(visit, "max(", ", ", ")"); break; + case EOpClamp: outputTriplet(visit, "clamp(", ", ", ")"); break; + case EOpMix: outputTriplet(visit, "lerp(", ", ", ")"); break; + case EOpStep: outputTriplet(visit, "step(", ", ", ")"); break; + case EOpSmoothStep: outputTriplet(visit, "smoothstep(", ", ", ")"); break; + case EOpDistance: outputTriplet(visit, "distance(", ", ", ")"); break; + case EOpDot: outputTriplet(visit, "dot(", ", ", ")"); break; + case EOpCross: outputTriplet(visit, "cross(", ", ", ")"); break; + case EOpFaceForward: UNIMPLEMENTED(); /* FIXME */ out << "face-forward"; break; + case EOpReflect: outputTriplet(visit, "reflect(", ", ", ")"); break; + case EOpRefract: outputTriplet(visit, "refract(", ", ", ")"); break; + case EOpMul: outputTriplet(visit, "(", " * ", ")"); break; + case EOpItof: UNIMPLEMENTED(); /* FIXME */ out << "itof"; break; + case EOpFtoi: UNIMPLEMENTED(); /* FIXME */ out << "ftoi"; break; + case EOpSkipPixels: UNIMPLEMENTED(); /* FIXME */ out << "skipPixels"; break; + case EOpReadInput: UNIMPLEMENTED(); /* FIXME */ out << "readInput"; break; + case EOpWritePixel: UNIMPLEMENTED(); /* FIXME */ out << "writePixel"; break; + case EOpBitmapLsb: UNIMPLEMENTED(); /* FIXME */ out << "bitmapLSB"; break; + case EOpBitmapMsb: UNIMPLEMENTED(); /* FIXME */ out << "bitmapMSB"; break; + case EOpWriteOutput: UNIMPLEMENTED(); /* FIXME */ out << "writeOutput"; break; + case EOpReadPixel: UNIMPLEMENTED(); /* FIXME */ out << "readPixel"; break; + default: UNREACHABLE(); + } + + return true; +} + +bool OutputHLSL::visitSelection(Visit visit, TIntermSelection *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + out << "if("; + + node->getCondition()->traverse(this); + + out << ")\n" + "{\n"; + + node->getTrueBlock()->traverse(this); + + out << ";}\n"; + + if (node->getFalseBlock()) + { + out << "else\n" + "{\n"; + + node->getFalseBlock()->traverse(this); + + out << ";}\n"; + } + + return false; +} + +void OutputHLSL::visitConstantUnion(TIntermConstantUnion *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + int size = node->getType().getObjectSize(); + bool matrix = node->getType().isMatrix(); + TBasicType type = node->getUnionArrayPointer()[0].getType(); + + switch (type) + { + case EbtBool: + if (!matrix) + { + switch (size) + { + case 1: out << "bool("; break; + case 2: out << "bool2("; break; + case 3: out << "bool3("; break; + case 4: out << "bool4("; break; + default: UNREACHABLE(); + } + } + else + { + UNIMPLEMENTED(); + } + break; + case EbtFloat: + if (!matrix) + { + switch (size) + { + case 1: out << "float("; break; + case 2: out << "float2("; break; + case 3: out << "float3("; break; + case 4: out << "float4("; break; + default: UNREACHABLE(); + } + } + else + { + switch (size) + { + case 4: out << "float2x2("; break; + case 9: out << "float3x3("; break; + case 16: out << "float4x4("; break; + default: UNREACHABLE(); + } + } + break; + case EbtInt: + if (!matrix) + { + switch (size) + { + case 1: out << "int("; break; + case 2: out << "int2("; break; + case 3: out << "int3("; break; + case 4: out << "int4("; break; + default: UNREACHABLE(); + } + } + else + { + UNIMPLEMENTED(); + } + break; + default: + UNIMPLEMENTED(); // FIXME + } + + for (int i = 0; i < size; i++) + { + switch (type) + { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + { + out << "true"; + } + else + { + out << "false"; + } + break; + case EbtFloat: + out << node->getUnionArrayPointer()[i].getFConst(); + break; + case EbtInt: + out << node->getUnionArrayPointer()[i].getIConst(); + break; + default: + UNIMPLEMENTED(); // FIXME + } + + if (i != size - 1) + { + out << ", "; + } + } + + out << ")"; +} + +bool OutputHLSL::visitLoop(Visit visit, TIntermLoop *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + if (!node->testFirst()) + { + out << "do\n" + "{\n"; + } + else + { + out << "for("; + + if (node->getInit()) + { + node->getInit()->traverse(this); + } + + out << "; "; + + if (node->getTest()) + { + node->getTest()->traverse(this); + } + + out << "; "; + + if (node->getTerminal()) + { + node->getTerminal()->traverse(this); + } + + out << ")\n" + "{\n"; + } + + if (node->getBody()) + { + node->getBody()->traverse(this); + } + + out << "}\n"; + + if (!node->testFirst()) + { + out << "while(\n"; + + node->getTest()->traverse(this); + + out << ")"; + } + + out << ";\n"; + + return false; +} + +bool OutputHLSL::visitBranch(Visit visit, TIntermBranch *node) +{ + TInfoSinkBase &out = context.infoSink.obj; + + switch (node->getFlowOp()) + { + case EOpKill: outputTriplet(visit, "discard", NULL, NULL); break; + case EOpBreak: UNIMPLEMENTED(); /* FIXME */ break; + case EOpContinue: UNIMPLEMENTED(); /* FIXME */ break; + case EOpReturn: + if (visit == PreVisit) + { + if (node->getExpression()) + { + out << "return "; + } + else + { + out << "return;\n"; + } + } + else if (visit == PostVisit) + { + out << ";\n"; + } + break; + default: UNREACHABLE(); + } + + return true; +} + +void OutputHLSL::outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString) +{ + TInfoSinkBase &out = context.infoSink.obj; + + if (visit == PreVisit && preString) + { + out << preString; + } + else if (visit == InVisit && inString) + { + out << inString; + } + else if (visit == PostVisit && postString) + { + out << postString; + } +} + +TString OutputHLSL::typeString(const TType &type) +{ + if (type.isMatrix()) + { + switch (type.getNominalSize()) + { + case 2: return "float2x2"; + case 3: return "float3x3"; + case 4: return "float4x4"; + } + } + else + { + switch (type.getBasicType()) + { + case EbtFloat: + switch (type.getNominalSize()) + { + case 1: return "float"; + case 2: return "float2"; + case 3: return "float3"; + case 4: return "float4"; + } + case EbtInt: + switch (type.getNominalSize()) + { + case 1: return "int"; + case 2: return "int2"; + case 3: return "int3"; + case 4: return "int4"; + } + case EbtBool: + switch (type.getNominalSize()) + { + case 1: return "bool"; + case 2: return "bool2"; + case 3: return "bool3"; + case 4: return "bool4"; + } + case EbtVoid: + return "void"; + case EbtSampler2D: + return "sampler2D"; + case EbtSamplerCube: + return "samplerCUBE"; + } + } + + UNIMPLEMENTED(); // FIXME + return ""; +} + +TString OutputHLSL::arrayString(const TType &type) +{ + if (!type.isArray()) + { + return ""; + } + + char buffer[100]; + sprintf(buffer, "[%d]", type.getArraySize()); + + return buffer; +} + +TString OutputHLSL::initializer(const TType &type) +{ + TString string; + + int arraySize = type.isArray() ? type.getArraySize() : 1; + + if (type.isArray()) + { + string += "{"; + } + + for (int element = 0; element < arraySize; element++) + { + string += typeString(type) + "("; + + for (int component = 0; component < type.getNominalSize(); component++) + { + string += "0"; + + if (component < type.getNominalSize() - 1) + { + string += ", "; + } + } + + string += ")"; + + if (element < arraySize - 1) + { + string += ", "; + } + } + + if (type.isArray()) + { + string += "}"; + } + + return string; +} +} diff --git a/Compiler/OutputHLSL.h b/Compiler/OutputHLSL.h new file mode 100644 index 000000000..a54e00673 --- /dev/null +++ b/Compiler/OutputHLSL.h @@ -0,0 +1,42 @@ +// +// Copyright (c) 2002-2010 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_OUTPUTHLSL_H_ +#define COMPILER_OUTPUTHLSL_H_ + +#include "intermediate.h" +#include "ParseHelper.h" + +namespace sh +{ +class OutputHLSL : public TIntermTraverser +{ + public: + OutputHLSL(TParseContext &context); + + void header(); + + protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + void outputTriplet(Visit visit, const char *preString, const char *inString, const char *postString); + + static TString typeString(const TType &type); + static TString arrayString(const TType &type); + static TString initializer(const TType &type); + + TParseContext &context; +}; +} + +#endif // COMPILER_OUTPUTHLSL_H_ diff --git a/Compiler/ParseHelper.cpp b/Compiler/ParseHelper.cpp new file mode 100644 index 000000000..4062a5636 --- /dev/null +++ b/Compiler/ParseHelper.cpp @@ -0,0 +1,1436 @@ +// +// Copyright (c) 2002-2010 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 "ParseHelper.h" +#include "InitializeParseContext.h" +#include "osinclude.h" +#include +/////////////////////////////////////////////////////////////////////// +// +// Sub- vector and matrix fields +// +//////////////////////////////////////////////////////////////////////// + +// +// Look at a '.' field selector string and change it into offsets +// for a vector. +// +bool TParseContext::parseVectorFields(const TString& compString, int vecSize, TVectorFields& fields, int line) +{ + fields.num = (int) compString.size(); + if (fields.num > 4) { + error(line, "illegal vector field selection", compString.c_str(), ""); + return false; + } + + enum { + exyzw, + ergba, + estpq, + } fieldSet[4]; + + for (int i = 0; i < fields.num; ++i) { + switch (compString[i]) { + case 'x': + fields.offsets[i] = 0; + fieldSet[i] = exyzw; + break; + case 'r': + fields.offsets[i] = 0; + fieldSet[i] = ergba; + break; + case 's': + fields.offsets[i] = 0; + fieldSet[i] = estpq; + break; + case 'y': + fields.offsets[i] = 1; + fieldSet[i] = exyzw; + break; + case 'g': + fields.offsets[i] = 1; + fieldSet[i] = ergba; + break; + case 't': + fields.offsets[i] = 1; + fieldSet[i] = estpq; + break; + case 'z': + fields.offsets[i] = 2; + fieldSet[i] = exyzw; + break; + case 'b': + fields.offsets[i] = 2; + fieldSet[i] = ergba; + break; + case 'p': + fields.offsets[i] = 2; + fieldSet[i] = estpq; + break; + + case 'w': + fields.offsets[i] = 3; + fieldSet[i] = exyzw; + break; + case 'a': + fields.offsets[i] = 3; + fieldSet[i] = ergba; + break; + case 'q': + fields.offsets[i] = 3; + fieldSet[i] = estpq; + break; + default: + error(line, "illegal vector field selection", compString.c_str(), ""); + return false; + } + } + + for (int i = 0; i < fields.num; ++i) { + if (fields.offsets[i] >= vecSize) { + error(line, "vector field selection out of range", compString.c_str(), ""); + return false; + } + + if (i > 0) { + if (fieldSet[i] != fieldSet[i-1]) { + error(line, "illegal - vector component fields not from the same set", compString.c_str(), ""); + return false; + } + } + } + + return true; +} + + +// +// Look at a '.' field selector string and change it into offsets +// for a matrix. +// +bool TParseContext::parseMatrixFields(const TString& compString, int matSize, TMatrixFields& fields, int line) +{ + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = -1; + fields.col = -1; + + if (compString.size() != 2) { + error(line, "illegal length of matrix field selection", compString.c_str(), ""); + return false; + } + + if (compString[0] == '_') { + if (compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str(), ""); + return false; + } + fields.wholeCol = true; + fields.col = compString[1] - '0'; + } else if (compString[1] == '_') { + if (compString[0] < '0' || compString[0] > '3') { + error(line, "illegal matrix field selection", compString.c_str(), ""); + return false; + } + fields.wholeRow = true; + fields.row = compString[0] - '0'; + } else { + if (compString[0] < '0' || compString[0] > '3' || + compString[1] < '0' || compString[1] > '3') { + error(line, "illegal matrix field selection", compString.c_str(), ""); + return false; + } + fields.row = compString[0] - '0'; + fields.col = compString[1] - '0'; + } + + if (fields.row >= matSize || fields.col >= matSize) { + error(line, "matrix field selection out of range", compString.c_str(), ""); + return false; + } + + return true; +} + +/////////////////////////////////////////////////////////////////////// +// +// Errors +// +//////////////////////////////////////////////////////////////////////// + +// +// Track whether errors have occurred. +// +void TParseContext::recover() +{ + recoveredFromError = true; +} + +// +// Used by flex/bison to output all syntax and parsing errors. +// +void C_DECL TParseContext::error(TSourceLoc nLine, const char *szReason, const char *szToken, + const char *szExtraInfoFormat, ...) +{ + char szExtraInfo[400]; + va_list marker; + + va_start(marker, szExtraInfoFormat); + + _vsnprintf(szExtraInfo, sizeof(szExtraInfo), szExtraInfoFormat, marker); + + /* VC++ format: file(linenum) : error #: 'token' : extrainfo */ + infoSink.info.prefix(EPrefixError); + infoSink.info.location(nLine); + infoSink.info << "'" << szToken << "' : " << szReason << " " << szExtraInfo << "\n"; + + va_end(marker); + + ++numErrors; +} + +// +// Same error message for all places assignments don't work. +// +void TParseContext::assignError(int line, const char* op, TString left, TString right) +{ + error(line, "", op, "cannot convert from '%s' to '%s'", + right.c_str(), left.c_str()); +} + +// +// Same error message for all places unary operations don't work. +// +void TParseContext::unaryOpError(int line, const char* op, TString operand) +{ + error(line, " wrong operand type", op, + "no operation '%s' exists that takes an operand of type %s (or there is no acceptable conversion)", + op, operand.c_str()); +} + +// +// Same error message for all binary operations don't work. +// +void TParseContext::binaryOpError(int line, const char* op, TString left, TString right) +{ + error(line, " wrong operand types ", op, + "no operation '%s' exists that takes a left-hand operand of type '%s' and " + "a right operand of type '%s' (or there is no acceptable conversion)", + op, left.c_str(), right.c_str()); +} + +// +// Both test and if necessary, spit out an error, to see if the node is really +// an l-value that can be operated on this way. +// +// Returns true if the was an error. +// +bool TParseContext::lValueErrorCheck(int line, const char* op, TIntermTyped* node) +{ + TIntermSymbol* symNode = node->getAsSymbolNode(); + TIntermBinary* binaryNode = node->getAsBinaryNode(); + + if (binaryNode) { + bool errorReturn; + + switch(binaryNode->getOp()) { + case EOpIndexDirect: + case EOpIndexIndirect: + case EOpIndexDirectStruct: + return lValueErrorCheck(line, op, binaryNode->getLeft()); + case EOpVectorSwizzle: + errorReturn = lValueErrorCheck(line, op, binaryNode->getLeft()); + if (!errorReturn) { + int offset[4] = {0,0,0,0}; + + TIntermTyped* rightNode = binaryNode->getRight(); + TIntermAggregate *aggrNode = rightNode->getAsAggregate(); + + for (TIntermSequence::iterator p = aggrNode->getSequence().begin(); + p != aggrNode->getSequence().end(); p++) { + int value = (*p)->getAsTyped()->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); + offset[value]++; + if (offset[value] > 1) { + error(line, " l-value of swizzle cannot have duplicate components", op, "", ""); + + return true; + } + } + } + + return errorReturn; + default: + break; + } + error(line, " l-value required", op, "", ""); + + return true; + } + + + const char* symbol = 0; + if (symNode != 0) + symbol = symNode->getSymbol().c_str(); + + const char* message = 0; + switch (node->getQualifier()) { + case EvqConst: message = "can't modify a const"; break; + case EvqConstReadOnly: message = "can't modify a const"; break; + case EvqAttribute: message = "can't modify an attribute"; break; + case EvqUniform: message = "can't modify a uniform"; break; + case EvqVaryingIn: message = "can't modify a varying"; break; + case EvqInput: message = "can't modify an input"; break; + case EvqFragCoord: message = "can't modify gl_FragCoord"; break; + case EvqFrontFacing: message = "can't modify gl_FrontFacing"; break; + case EvqPointCoord: message = "can't modify gl_PointCoord"; break; + default: + + // + // Type that can't be written to? + // + switch (node->getBasicType()) { + case EbtSampler2D: + case EbtSamplerCube: + message = "can't modify a sampler"; + break; + case EbtVoid: + message = "can't modify void"; + break; + default: + break; + } + } + + if (message == 0 && binaryNode == 0 && symNode == 0) { + error(line, " l-value required", op, "", ""); + + return true; + } + + + // + // Everything else is okay, no error. + // + if (message == 0) + return false; + + // + // If we get here, we have an error and a message. + // + if (symNode) + error(line, " l-value required", op, "\"%s\" (%s)", symbol, message); + else + error(line, " l-value required", op, "(%s)", message); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// a constant. +// +// Returns true if the was an error. +// +bool TParseContext::constErrorCheck(TIntermTyped* node) +{ + if (node->getQualifier() == EvqConst) + return false; + + error(node->getLine(), "constant expression required", "", ""); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if the node is really +// an integer. +// +// Returns true if the was an error. +// +bool TParseContext::integerErrorCheck(TIntermTyped* node, const char* token) +{ + if (node->getBasicType() == EbtInt && node->getNominalSize() == 1) + return false; + + error(node->getLine(), "integer expression required", token, ""); + + return true; +} + +// +// Both test, and if necessary spit out an error, to see if we are currently +// globally scoped. +// +// Returns true if the was an error. +// +bool TParseContext::globalErrorCheck(int line, bool global, const char* token) +{ + if (global) + return false; + + error(line, "only allowed at global scope", token, ""); + + return true; +} + +// +// For now, keep it simple: if it starts "gl_", it's reserved, independent +// of scope. Except, if the symbol table is at the built-in push-level, +// which is when we are parsing built-ins. +// +// Returns true if there was an error. +// +bool TParseContext::reservedErrorCheck(int line, const TString& identifier) +{ + if (!symbolTable.atBuiltInLevel()) { + if (identifier.substr(0, 3) == TString("gl_")) { + error(line, "reserved built-in name", "gl_", ""); + return true; + } + if (identifier.find("__") != TString::npos) { + //error(line, "Two consecutive underscores are reserved for future use.", identifier.c_str(), "", ""); + //return true; + infoSink.info.message(EPrefixWarning, "Two consecutive underscores are reserved for future use.", line); + return false; + } + } + + return false; +} + +// +// Make sure there is enough data provided to the constructor to build +// something of the type of the constructor. Also returns the type of +// the constructor. +// +// Returns true if there was an error in construction. +// +bool TParseContext::constructorErrorCheck(int line, TIntermNode* node, TFunction& function, TOperator op, TType* type) +{ + *type = function.getReturnType(); + + bool constructingMatrix = false; + switch(op) { + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + constructingMatrix = true; + break; + default: + break; + } + + // + // Note: It's okay to have too many components available, but not okay to have unused + // arguments. 'full' will go to true when enough args have been seen. If we loop + // again, there is an extra argument, so 'overfull' will become true. + // + + int size = 0; + bool constType = true; + bool full = false; + bool overFull = false; + bool matrixInMatrix = false; + bool arrayArg = false; + for (int i = 0; i < function.getParamCount(); ++i) { + size += function[i].type->getObjectSize(); + + if (constructingMatrix && function[i].type->isMatrix()) + matrixInMatrix = true; + if (full) + overFull = true; + if (op != EOpConstructStruct && !type->isArray() && size >= type->getObjectSize()) + full = true; + if (function[i].type->getQualifier() != EvqConst) + constType = false; + if (function[i].type->isArray()) + arrayArg = true; + } + + if (constType) + type->changeQualifier(EvqConst); + + if (type->isArray() && type->getArraySize() != function.getParamCount()) { + error(line, "array constructor needs one argument per array element", "constructor", ""); + return true; + } + + if (arrayArg && op != EOpConstructStruct) { + error(line, "constructing from a non-dereferenced array", "constructor", ""); + return true; + } + + if (matrixInMatrix && !type->isArray()) { + error(line, "constructing matrix from matrix", "constructor", "(reserved)"); + return true; + } + + if (overFull) { + error(line, "too many arguments", "constructor", ""); + return true; + } + + if (op == EOpConstructStruct && !type->isArray() && type->getStruct()->size() != function.getParamCount()) { + error(line, "Number of constructor parameters does not match the number of structure fields", "constructor", ""); + return true; + } + + if ((op != EOpConstructStruct && size != 1 && size < type->getObjectSize()) || + (op == EOpConstructStruct && size < type->getObjectSize())) { + error(line, "not enough data provided for construction", "constructor", ""); + return true; + } + + TIntermTyped* typed = node->getAsTyped(); + if (typed == 0) { + error(line, "constructor argument does not have a type", "constructor", ""); + return true; + } + if (op != EOpConstructStruct && IsSampler(typed->getBasicType())) { + error(line, "cannot convert a sampler", "constructor", ""); + return true; + } + if (typed->getBasicType() == EbtVoid) { + error(line, "cannot convert a void", "constructor", ""); + return true; + } + + return false; +} + +// This function checks to see if a void variable has been declared and raise an error message for such a case +// +// returns true in case of an error +// +bool TParseContext::voidErrorCheck(int line, const TString& identifier, const TPublicType& pubType) +{ + if (pubType.type == EbtVoid) { + error(line, "illegal use of type 'void'", identifier.c_str(), ""); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TIntermTyped* type) +{ + if (type->getBasicType() != EbtBool || type->isArray() || type->isMatrix() || type->isVector()) { + error(line, "boolean expression expected", "", ""); + return true; + } + + return false; +} + +// This function checks to see if the node (for the expression) contains a scalar boolean expression or not +// +// returns true in case of an error +// +bool TParseContext::boolErrorCheck(int line, const TPublicType& pType) +{ + if (pType.type != EbtBool || pType.array || pType.matrix || (pType.size > 1)) { + error(line, "boolean expression expected", "", ""); + return true; + } + + return false; +} + +bool TParseContext::samplerErrorCheck(int line, const TPublicType& pType, const char* reason) +{ + if (pType.type == EbtStruct) { + if (containsSampler(*pType.userDef)) { + error(line, reason, TType::getBasicString(pType.type), "(structure contains a sampler)"); + + return true; + } + + return false; + } else if (IsSampler(pType.type)) { + error(line, reason, TType::getBasicString(pType.type), ""); + + return true; + } + + return false; +} + +bool TParseContext::structQualifierErrorCheck(int line, const TPublicType& pType) +{ + if ((pType.qualifier == EvqVaryingIn || pType.qualifier == EvqVaryingOut || pType.qualifier == EvqAttribute) && + pType.type == EbtStruct) { + error(line, "cannot be used with a structure", getQualifierString(pType.qualifier), ""); + + return true; + } + + if (pType.qualifier != EvqUniform && samplerErrorCheck(line, pType, "samplers must be uniform")) + return true; + + return false; +} + +bool TParseContext::parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type) +{ + if ((qualifier == EvqOut || qualifier == EvqInOut) && + type.getBasicType() != EbtStruct && IsSampler(type.getBasicType())) { + error(line, "samplers cannot be output parameters", type.getBasicString(), ""); + return true; + } + + return false; +} + +bool TParseContext::containsSampler(TType& type) +{ + if (IsSampler(type.getBasicType())) + return true; + + if (type.getBasicType() == EbtStruct) { + TTypeList& structure = *type.getStruct(); + for (unsigned int i = 0; i < structure.size(); ++i) { + if (containsSampler(*structure[i].type)) + return true; + } + } + + return false; +} + +// +// Do size checking for an array type's size. +// +// Returns true if there was an error. +// +bool TParseContext::arraySizeErrorCheck(int line, TIntermTyped* expr, int& size) +{ + TIntermConstantUnion* constant = expr->getAsConstantUnion(); + if (constant == 0 || constant->getBasicType() != EbtInt) { + error(line, "array size must be a constant integer expression", "", ""); + return true; + } + + size = constant->getUnionArrayPointer()->getIConst(); + + if (size <= 0) { + error(line, "array size must be a positive integer", "", ""); + size = 1; + return true; + } + + return false; +} + +// +// See if this qualifier can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayQualifierErrorCheck(int line, TPublicType type) +{ + if (type.qualifier == EvqAttribute) { + error(line, "cannot declare arrays of this qualifier", TType(type).getCompleteString().c_str(), ""); + return true; + } + + if (type.qualifier == EvqConst && extensionErrorCheck(line, "GL_3DL_array_objects")) + return true; + + return false; +} + +// +// See if this type can be an array. +// +// Returns true if there is an error. +// +bool TParseContext::arrayTypeErrorCheck(int line, TPublicType type) +{ + // + // Can the type be an array? + // + if (type.array) { + error(line, "cannot declare arrays of arrays", TType(type).getCompleteString().c_str(), ""); + return true; + } + + return false; +} + +// +// Do all the semantic checking for declaring an array, with and +// without a size, and make the right changes to the symbol table. +// +// size == 0 means no specified size. +// +// Returns true if there was an error. +// +bool TParseContext::arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable) +{ + // + // Don't check for reserved word use until after we know it's not in the symbol table, + // because reserved arrays can be redeclared. + // + + bool builtIn = false; + bool sameScope = false; + TSymbol* symbol = symbolTable.find(identifier, &builtIn, &sameScope); + if (symbol == 0 || !sameScope) { + if (reservedErrorCheck(line, identifier)) + return true; + + variable = new TVariable(&identifier, TType(type)); + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + + if (! symbolTable.insert(*variable)) { + delete variable; + error(line, "INTERNAL ERROR inserting new symbol", identifier.c_str(), ""); + return true; + } + } else { + if (! symbol->isVariable()) { + error(line, "variable expected", identifier.c_str(), ""); + return true; + } + + variable = static_cast(symbol); + if (! variable->getType().isArray()) { + error(line, "redeclaring non-array as array", identifier.c_str(), ""); + return true; + } + if (variable->getType().getArraySize() > 0) { + error(line, "redeclaration of array with size", identifier.c_str(), ""); + return true; + } + + if (! variable->getType().sameElementType(TType(type))) { + error(line, "redeclaration of array with a different type", identifier.c_str(), ""); + return true; + } + + TType* t = variable->getArrayInformationType(); + while (t != 0) { + if (t->getMaxArraySize() > type.arraySize) { + error(line, "higher index value already used for the array", identifier.c_str(), ""); + return true; + } + t->setArraySize(type.arraySize); + t = t->getArrayInformationType(); + } + + if (type.arraySize) + variable->getType().setArraySize(type.arraySize); + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::arraySetMaxSize(TIntermSymbol *node, TType* type, int size, bool updateFlag, TSourceLoc line) +{ + bool builtIn = false; + TSymbol* symbol = symbolTable.find(node->getSymbol(), &builtIn); + if (symbol == 0) { + error(line, " undeclared identifier", node->getSymbol().c_str(), ""); + return true; + } + TVariable* variable = static_cast(symbol); + + type->setArrayInformationType(variable->getArrayInformationType()); + variable->updateArrayInformationType(type); + + // special casing to test index value of gl_FragData. If the accessed index is >= gl_MaxDrawBuffers + // its an error + if (node->getSymbol() == "gl_FragData") { + TSymbol* fragData = symbolTable.find("gl_MaxDrawBuffers", &builtIn); + if (fragData == 0) { + infoSink.info.message(EPrefixInternalError, "gl_MaxDrawBuffers not defined", line); + return true; + } + + int fragDataValue = static_cast(fragData)->getConstPointer()[0].getIConst(); + if (fragDataValue <= size) { + error(line, "", "[", "gl_FragData can only have a max array size of up to gl_MaxDrawBuffers", ""); + return true; + } + } + + // we dont want to update the maxArraySize when this flag is not set, we just want to include this + // node type in the chain of node types so that its updated when a higher maxArraySize comes in. + if (!updateFlag) + return false; + + size++; + variable->getType().setMaxArraySize(size); + type->setMaxArraySize(size); + TType* tt = type; + + while(tt->getArrayInformationType() != 0) { + tt = tt->getArrayInformationType(); + tt->setMaxArraySize(size); + } + + return false; +} + +// +// Enforce non-initializer type/qualifier rules. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type) +{ + // + // Make the qualifier make sense. + // + if (type.qualifier == EvqConst) { + type.qualifier = EvqTemporary; + error(line, "variables with qualifier 'const' must be initialized", identifier.c_str(), ""); + return true; + } + + return false; +} + +// +// Do semantic checking for a variable declaration that has no initializer, +// and update the symbol table. +// +// Returns true if there was an error. +// +bool TParseContext::nonInitErrorCheck(int line, TString& identifier, TPublicType& type) +{ + if (reservedErrorCheck(line, identifier)) + recover(); + + TVariable* variable = new TVariable(&identifier, TType(type)); + + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str(), ""); + delete variable; + return true; + } + + if (voidErrorCheck(line, identifier, type)) + return true; + + return false; +} + +bool TParseContext::paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type) +{ + if (qualifier != EvqConst && qualifier != EvqTemporary) { + error(line, "qualifier not allowed on function parameter", getQualifierString(qualifier), ""); + return true; + } + if (qualifier == EvqConst && paramQualifier != EvqIn) { + error(line, "qualifier not allowed with ", getQualifierString(qualifier), getQualifierString(paramQualifier)); + return true; + } + + if (qualifier == EvqConst) + type->changeQualifier(EvqConstReadOnly); + else + type->changeQualifier(paramQualifier); + + return false; +} + +bool TParseContext::extensionErrorCheck(int line, const char* extension) +{ + if (extensionBehavior[extension] == EBhWarn) { + infoSink.info.message(EPrefixWarning, ("extension " + TString(extension) + " is being used").c_str(), line); + return false; + } + if (extensionBehavior[extension] == EBhDisable) { + error(line, "extension", extension, "is disabled"); + return true; + } + + return false; +} + +///////////////////////////////////////////////////////////////////////////////// +// +// Non-Errors. +// +///////////////////////////////////////////////////////////////////////////////// + +// +// Look up a function name in the symbol table, and make sure it is a function. +// +// Return the function symbol if found, otherwise 0. +// +const TFunction* TParseContext::findFunction(int line, TFunction* call, bool *builtIn) +{ + const TSymbol* symbol = symbolTable.find(call->getMangledName(), builtIn); + + if (symbol == 0) { + error(line, "no matching overloaded function found", call->getName().c_str(), ""); + return 0; + } + + if (! symbol->isFunction()) { + error(line, "function name expected", call->getName().c_str(), ""); + return 0; + } + + const TFunction* function = static_cast(symbol); + + return function; +} + +// +// Initializers show up in several places in the grammar. Have one set of +// code to handle them here. +// +bool TParseContext::executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable) +{ + TType type = TType(pType); + + if (variable == 0) { + if (reservedErrorCheck(line, identifier)) + return true; + + if (voidErrorCheck(line, identifier, pType)) + return true; + + // + // add variable to symbol table + // + variable = new TVariable(&identifier, type); + if (! symbolTable.insert(*variable)) { + error(line, "redefinition", variable->getName().c_str(), ""); + return true; + // don't delete variable, it's used by error recovery, and the pool + // pop will take care of the memory + } + } + + // + // identifier must be of type constant, a global, or a temporary + // + TQualifier qualifier = variable->getType().getQualifier(); + if ((qualifier != EvqTemporary) && (qualifier != EvqGlobal) && (qualifier != EvqConst)) { + error(line, " cannot initialize this type of qualifier ", variable->getType().getQualifierString(), ""); + return true; + } + // + // test for and propagate constant + // + + if (qualifier == EvqConst) { + if (qualifier != initializer->getType().getQualifier()) { + error(line, " assigning non-constant to", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + if (type != initializer->getType()) { + error(line, " non-matching types for const initializer ", + variable->getType().getQualifierString(), ""); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + if (initializer->getAsConstantUnion()) { + constUnion* unionArray = variable->getConstPointer(); + + if (type.getObjectSize() == 1 && type.getBasicType() != EbtStruct) { + *unionArray = (initializer->getAsConstantUnion()->getUnionArrayPointer())[0]; + } else { + variable->shareConstPointer(initializer->getAsConstantUnion()->getUnionArrayPointer()); + } + } else if (initializer->getAsSymbolNode()) { + const TSymbol* symbol = symbolTable.find(initializer->getAsSymbolNode()->getSymbol()); + const TVariable* tVar = static_cast(symbol); + + constUnion* constArray = tVar->getConstPointer(); + variable->shareConstPointer(constArray); + } else { + error(line, " cannot assign to", "=", "'%s'", variable->getType().getCompleteString().c_str()); + variable->getType().changeQualifier(EvqTemporary); + return true; + } + } + + if (qualifier != EvqConst) { + TIntermSymbol* intermSymbol = intermediate.addSymbol(variable->getUniqueId(), variable->getName(), variable->getType(), line); + intermNode = intermediate.addAssign(EOpInitialize, intermSymbol, initializer, line); + if (intermNode == 0) { + assignError(line, "=", intermSymbol->getCompleteString(), initializer->getCompleteString()); + return true; + } + } else + intermNode = 0; + + return false; +} + +bool TParseContext::areAllChildConst(TIntermAggregate* aggrNode) +{ + if (!aggrNode->isConstructor()) + return false; + + bool allConstant = true; + + // check if all the child nodes are constants so that they can be inserted into + // the parent node + if (aggrNode) { + TIntermSequence &childSequenceVector = aggrNode->getSequence() ; + for (TIntermSequence::iterator p = childSequenceVector.begin(); + p != childSequenceVector.end(); p++) { + if (!(*p)->getAsTyped()->getAsConstantUnion()) + return false; + } + } + + return allConstant; +} + +// This function is used to test for the correctness of the parameters passed to various constructor functions +// and also convert them to the right datatype if it is allowed and required. +// +// Returns 0 for an error or the constructed node (aggregate or typed) for no error. +// +TIntermTyped* TParseContext::addConstructor(TIntermNode* node, const TType* type, TOperator op, TFunction* fnCall, TSourceLoc line) +{ + if (node == 0) + return 0; + + TIntermAggregate* aggrNode = node->getAsAggregate(); + + TTypeList::iterator memberTypes; + if (op == EOpConstructStruct) + memberTypes = type->getStruct()->begin(); + + TType elementType = *type; + if (type->isArray()) + elementType.clearArrayness(); + + bool singleArg; + if (aggrNode) { + if (aggrNode->getOp() != EOpNull || aggrNode->getSequence().size() == 1) + singleArg = true; + else + singleArg = false; + } else + singleArg = true; + + TIntermTyped *newNode; + if (singleArg) { + // If structure constructor or array constructor is being called + // for only one parameter inside the structure, we need to call constructStruct function once. + if (type->isArray()) + newNode = constructStruct(node, &elementType, 1, node->getLine(), false); + else if (op == EOpConstructStruct) + newNode = constructStruct(node, (*memberTypes).type, 1, node->getLine(), false); + else + newNode = constructBuiltIn(type, op, node, node->getLine(), false); + + if (newNode && newNode->getAsAggregate()) { + TIntermTyped* constConstructor = foldConstConstructor(newNode->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + } + + return newNode; + } + + // + // Handle list of arguments. + // + TIntermSequence &sequenceVector = aggrNode->getSequence() ; // Stores the information about the parameter to the constructor + // if the structure constructor contains more than one parameter, then construct + // each parameter + + int paramCount = 0; // keeps a track of the constructor parameter number being checked + + // for each parameter to the constructor call, check to see if the right type is passed or convert them + // to the right type if possible (and allowed). + // for structure constructors, just check if the right type is passed, no conversion is allowed. + + for (TIntermSequence::iterator p = sequenceVector.begin(); + p != sequenceVector.end(); p++, paramCount++) { + if (type->isArray()) + newNode = constructStruct(*p, &elementType, paramCount+1, node->getLine(), true); + else if (op == EOpConstructStruct) + newNode = constructStruct(*p, (memberTypes[paramCount]).type, paramCount+1, node->getLine(), true); + else + newNode = constructBuiltIn(type, op, *p, node->getLine(), true); + + if (newNode) { + *p = newNode; + } + } + + TIntermTyped* constructor = intermediate.setAggregateOperator(aggrNode, op, line); + TIntermTyped* constConstructor = foldConstConstructor(constructor->getAsAggregate(), *type); + if (constConstructor) + return constConstructor; + + return constructor; +} + +TIntermTyped* TParseContext::foldConstConstructor(TIntermAggregate* aggrNode, const TType& type) +{ + bool canBeFolded = areAllChildConst(aggrNode); + aggrNode->setType(type); + if (canBeFolded) { + bool returnVal = false; + constUnion* unionArray = new constUnion[type.getObjectSize()]; + if (aggrNode->getSequence().size() == 1) { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type, true); + } + else { + returnVal = intermediate.parseConstTree(aggrNode->getLine(), aggrNode, unionArray, aggrNode->getOp(), symbolTable, type); + } + if (returnVal) + return 0; + + return intermediate.addConstantUnion(unionArray, type, aggrNode->getLine()); + } + + return 0; +} + +// Function for constructor implementation. Calls addUnaryMath with appropriate EOp value +// for the parameter to the constructor (passed to this function). Essentially, it converts +// the parameter types correctly. If a constructor expects an int (like ivec2) and is passed a +// float, then float is converted to int. +// +// Returns 0 for an error or the constructed node. +// +TIntermTyped* TParseContext::constructBuiltIn(const TType* type, TOperator op, TIntermNode* node, TSourceLoc line, bool subset) +{ + TIntermTyped* newNode; + TOperator basicOp; + + // + // First, convert types as needed. + // + switch (op) { + case EOpConstructVec2: + case EOpConstructVec3: + case EOpConstructVec4: + case EOpConstructMat2: + case EOpConstructMat3: + case EOpConstructMat4: + case EOpConstructFloat: + basicOp = EOpConstructFloat; + break; + + case EOpConstructIVec2: + case EOpConstructIVec3: + case EOpConstructIVec4: + case EOpConstructInt: + basicOp = EOpConstructInt; + break; + + case EOpConstructBVec2: + case EOpConstructBVec3: + case EOpConstructBVec4: + case EOpConstructBool: + basicOp = EOpConstructBool; + break; + + default: + error(line, "unsupported construction", "", ""); + recover(); + + return 0; + } + newNode = intermediate.addUnaryMath(basicOp, node, node->getLine(), symbolTable); + if (newNode == 0) { + error(line, "can't convert", "constructor", ""); + return 0; + } + + // + // Now, if there still isn't an operation to do the construction, and we need one, add one. + // + + // Otherwise, skip out early. + if (subset || (newNode != node && newNode->getType() == *type)) + return newNode; + + // setAggregateOperator will insert a new node for the constructor, as needed. + return intermediate.setAggregateOperator(newNode, op, line); +} + +// This function tests for the type of the parameters to the structures constructors. Raises +// an error message if the expected type does not match the parameter passed to the constructor. +// +// Returns 0 for an error or the input node itself if the expected and the given parameter types match. +// +TIntermTyped* TParseContext::constructStruct(TIntermNode* node, TType* type, int paramCount, TSourceLoc line, bool subset) +{ + if (*type == node->getAsTyped()->getType()) { + if (subset) + return node->getAsTyped(); + else + return intermediate.setAggregateOperator(node->getAsTyped(), EOpConstructStruct, line); + } else { + error(line, "", "constructor", "cannot convert parameter %d from '%s' to '%s'", paramCount, + node->getAsTyped()->getType().getBasicString(), type->getBasicString()); + recover(); + } + + return 0; +} + +// +// This function returns the tree representation for the vector field(s) being accessed from contant vector. +// If only one component of vector is accessed (v.x or v[0] where v is a contant vector), then a contant node is +// returned, else an aggregate node is returned (for v.xy). The input to this function could either be the symbol +// node or it could be the intermediate tree representation of accessing fields in a constant structure or column of +// a constant matrix. +// +TIntermTyped* TParseContext::addConstVectorNode(TVectorFields& fields, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + constUnion *unionArray; + if (tempConstantNode) { + unionArray = tempConstantNode->getUnionArrayPointer(); + + if (!unionArray) { // this error message should never be raised + infoSink.info.message(EPrefixInternalError, "constUnion not initialized in addConstVectorNode function", line); + recover(); + + return node; + } + } else { // The node has to be either a symbol node or an aggregate node or a tempConstant node, else, its an error + error(line, "Cannot offset into the vector", "Error", ""); + recover(); + + return 0; + } + + constUnion* constArray = new constUnion[fields.num]; + + for (int i = 0; i < fields.num; i++) { + if (fields.offsets[i] >= node->getType().getObjectSize()) { + error(line, "", "[", "vector field selection out of range '%d'", fields.offsets[i]); + recover(); + fields.offsets[i] = 0; + } + + constArray[i] = unionArray[fields.offsets[i]]; + + } + typedNode = intermediate.addConstantUnion(constArray, node->getType(), line); + return typedNode; +} + +// +// This function returns the column being accessed from a constant matrix. The values are retrieved from +// the symbol table and parse-tree is built for a vector (each column of a matrix is a vector). The input +// to the function could either be a symbol node (m[0] where m is a constant matrix)that represents a +// constant matrix or it could be the tree representation of the constant matrix (s.m1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstMatrixNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + + if (index >= node->getType().getNominalSize()) { + error(line, "", "[", "matrix field selection out of range '%d'", index); + recover(); + index = 0; + } + + if (tempConstantNode) { + constUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + int size = tempConstantNode->getType().getNominalSize(); + typedNode = intermediate.addConstantUnion(&unionArray[size*index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the matrix", "Error", ""); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns an element of an array accessed from a constant array. The values are retrieved from +// the symbol table and parse-tree is built for the type of the element. The input +// to the function could either be a symbol node (a[0] where a is a constant array)that represents a +// constant array or it could be the tree representation of the constant array (s.a1[0] where s is a constant structure) +// +TIntermTyped* TParseContext::addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line) +{ + TIntermTyped* typedNode; + TIntermConstantUnion* tempConstantNode = node->getAsConstantUnion(); + TType arrayElementType = node->getType(); + arrayElementType.clearArrayness(); + + if (index >= node->getType().getArraySize()) { + error(line, "", "[", "array field selection out of range '%d'", index); + recover(); + index = 0; + } + + int arrayElementSize = arrayElementType.getObjectSize(); + + if (tempConstantNode) { + constUnion* unionArray = tempConstantNode->getUnionArrayPointer(); + typedNode = intermediate.addConstantUnion(&unionArray[arrayElementSize * index], tempConstantNode->getType(), line); + } else { + error(line, "Cannot offset into the array", "Error", ""); + recover(); + + return 0; + } + + return typedNode; +} + + +// +// This function returns the value of a particular field inside a constant structure from the symbol table. +// If there is an embedded/nested struct, it appropriately calls addConstStructNested or addConstStructFromAggr +// function and returns the parse-tree with the values of the embedded/nested struct. +// +TIntermTyped* TParseContext::addConstStruct(TString& identifier, TIntermTyped* node, TSourceLoc line) +{ + TTypeList* fields = node->getType().getStruct(); + TIntermTyped *typedNode; + int instanceSize = 0; + unsigned int index = 0; + TIntermConstantUnion *tempConstantNode = node->getAsConstantUnion(); + + for ( index = 0; index < fields->size(); ++index) { + if ((*fields)[index].type->getFieldName() == identifier) { + break; + } else { + instanceSize += (*fields)[index].type->getObjectSize(); + } + } + + if (tempConstantNode) { + constUnion* constArray = tempConstantNode->getUnionArrayPointer(); + + typedNode = intermediate.addConstantUnion(constArray+instanceSize, tempConstantNode->getType(), line); // type will be changed in the calling function + } else { + error(line, "Cannot offset into the structure", "Error", ""); + recover(); + + return 0; + } + + return typedNode; +} + +// +// Initialize all supported extensions to disable +// +void TParseContext::initializeExtensionBehavior() +{ + // + // example code: extensionBehavior["test"] = EBhDisable; // where "test" is the name of + // supported extension + // + extensionBehavior["GL_ARB_texture_rectangle"] = EBhRequire; + extensionBehavior["GL_3DL_array_objects"] = EBhDisable; +} + +OS_TLSIndex GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + +bool InitializeParseContextIndex() +{ + if (GlobalParseContextIndex != OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + return false; + } + + // + // Allocate a TLS index. + // + GlobalParseContextIndex = OS_AllocTLSIndex(); + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + return false; + } + + return true; +} + +bool InitializeGlobalParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "InitializeGlobalParseContext(): Parse Context index not initalised"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext != 0) { + assert(0 && "InitializeParseContextIndex(): Parse Context already initalised"); + return false; + } + + TThreadParseContext *lpThreadData = new TThreadParseContext(); + if (lpThreadData == 0) { + assert(0 && "InitializeGlobalParseContext(): Unable to create thread parse context"); + return false; + } + + lpThreadData->lpGlobalParseContext = 0; + OS_SetTLSValue(GlobalParseContextIndex, lpThreadData); + + return true; +} + +TParseContextPointer& GetGlobalParseContext() +{ + // + // Minimal error checking for speed + // + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + + return lpParseContext->lpGlobalParseContext; +} + +bool FreeParseContext() +{ + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContext(): Parse Context index not initalised"); + return false; + } + + TThreadParseContext *lpParseContext = static_cast(OS_GetTLSValue(GlobalParseContextIndex)); + if (lpParseContext) + delete lpParseContext; + + return true; +} + +bool FreeParseContextIndex() +{ + OS_TLSIndex tlsiIndex = GlobalParseContextIndex; + + if (GlobalParseContextIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "FreeParseContextIndex(): Parse Context index not initalised"); + return false; + } + + GlobalParseContextIndex = OS_INVALID_TLS_INDEX; + + return OS_FreeTLSIndex(tlsiIndex); +} diff --git a/Compiler/ParseHelper.h b/Compiler/ParseHelper.h new file mode 100644 index 000000000..bb61220f7 --- /dev/null +++ b/Compiler/ParseHelper.h @@ -0,0 +1,121 @@ +// +// Copyright (c) 2002-2010 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 _PARSER_HELPER_INCLUDED_ +#define _PARSER_HELPER_INCLUDED_ + +#include "ShHandle.h" +#include "SymbolTable.h" +#include "localintermediate.h" + +struct TMatrixFields { + bool wholeRow; + bool wholeCol; + int row; + int col; +}; + +typedef enum { + EBhRequire, + EBhEnable, + EBhWarn, + EBhDisable +} TBehavior; + +struct TPragma { + TPragma(bool o, bool d) : optimize(o), debug(d) { } + bool optimize; + bool debug; + TPragmaTable pragmaTable; +}; + +// +// The following are extra variables needed during parsing, grouped together so +// they can be passed to the parser without needing a global. +// +struct TParseContext { + TParseContext(TSymbolTable& symt, TIntermediate& interm, EShLanguage L, TInfoSink& is) : + intermediate(interm), symbolTable(symt), infoSink(is), language(L), treeRoot(0), + recoveredFromError(false), numErrors(0), lexAfterType(false), loopNestingLevel(0), + inTypeParen(false), contextPragma(true, false) { } + TIntermediate& intermediate; // to hold and build a parse tree + TSymbolTable& symbolTable; // symbol table that goes with the language currently being parsed + TInfoSink& infoSink; + EShLanguage language; // vertex or fragment language (future: pack or unpack) + TIntermNode* treeRoot; // root of parse tree being created + bool recoveredFromError; // true if a parse error has occurred, but we continue to parse + int numErrors; + bool lexAfterType; // true if we've recognized a type, so can only be looking for an identifier + int loopNestingLevel; // 0 if outside all loops + bool inTypeParen; // true if in parentheses, looking only for an identifier + const TType* currentFunctionType; // the return type of the function that's currently being parsed + bool functionReturnsValue; // true if a non-void function has a return + TMap extensionBehavior; + void initializeExtensionBehavior(); + + void C_DECL error(TSourceLoc, const char *szReason, const char *szToken, + const char *szExtraInfoFormat, ...); + bool reservedErrorCheck(int line, const TString& identifier); + void recover(); + + bool parseVectorFields(const TString&, int vecSize, TVectorFields&, int line); + bool parseMatrixFields(const TString&, int matSize, TMatrixFields&, int line); + void assignError(int line, const char* op, TString left, TString right); + void unaryOpError(int line, const char* op, TString operand); + void binaryOpError(int line, const char* op, TString left, TString right); + bool lValueErrorCheck(int line, const char* op, TIntermTyped*); + bool constErrorCheck(TIntermTyped* node); + bool integerErrorCheck(TIntermTyped* node, const char* token); + bool globalErrorCheck(int line, bool global, const char* token); + bool constructorErrorCheck(int line, TIntermNode*, TFunction&, TOperator, TType*); + bool arraySizeErrorCheck(int line, TIntermTyped* expr, int& size); + bool arrayQualifierErrorCheck(int line, TPublicType type); + bool arrayTypeErrorCheck(int line, TPublicType type); + bool arrayErrorCheck(int line, TString& identifier, TPublicType type, TVariable*& variable); + bool voidErrorCheck(int, const TString&, const TPublicType&); + bool boolErrorCheck(int, const TIntermTyped*); + bool boolErrorCheck(int, const TPublicType&); + bool samplerErrorCheck(int line, const TPublicType& pType, const char* reason); + bool structQualifierErrorCheck(int line, const TPublicType& pType); + bool parameterSamplerErrorCheck(int line, TQualifier qualifier, const TType& type); + bool containsSampler(TType& type); + bool nonInitConstErrorCheck(int line, TString& identifier, TPublicType& type); + bool nonInitErrorCheck(int line, TString& identifier, TPublicType& type); + bool paramErrorCheck(int line, TQualifier qualifier, TQualifier paramQualifier, TType* type); + bool extensionErrorCheck(int line, const char*); + const TFunction* findFunction(int line, TFunction* pfnCall, bool *builtIn = 0); + bool executeInitializer(TSourceLoc line, TString& identifier, TPublicType& pType, + TIntermTyped* initializer, TIntermNode*& intermNode, TVariable* variable = 0); + bool areAllChildConst(TIntermAggregate* aggrNode); + TIntermTyped* addConstructor(TIntermNode*, const TType*, TOperator, TFunction*, TSourceLoc); + TIntermTyped* foldConstConstructor(TIntermAggregate* aggrNode, const TType& type); + TIntermTyped* constructStruct(TIntermNode*, TType*, int, TSourceLoc, bool subset); + TIntermTyped* constructBuiltIn(const TType*, TOperator, TIntermNode*, TSourceLoc, bool subset); + TIntermTyped* addConstVectorNode(TVectorFields&, TIntermTyped*, TSourceLoc); + TIntermTyped* addConstMatrixNode(int , TIntermTyped*, TSourceLoc); + TIntermTyped* addConstArrayNode(int index, TIntermTyped* node, TSourceLoc line); + TIntermTyped* addConstStruct(TString& , TIntermTyped*, TSourceLoc); + bool arraySetMaxSize(TIntermSymbol*, TType*, int, bool, TSourceLoc); + struct TPragma contextPragma; + TString HashErrMsg; + bool AfterEOF; +}; + +int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext&); +void PaReservedWord(); +int PaIdentOrType(TString& id, TParseContext&, TSymbol*&); +int PaParseComment(int &lineno, TParseContext&); +void setInitialState(); + +typedef TParseContext* TParseContextPointer; +extern TParseContextPointer& GetGlobalParseContext(); +#define GlobalParseContext GetGlobalParseContext() + +typedef struct TThreadParseContextRec +{ + TParseContext *lpGlobalParseContext; +} TThreadParseContext; + +#endif // _PARSER_HELPER_INCLUDED_ diff --git a/Compiler/PoolAlloc.cpp b/Compiler/PoolAlloc.cpp new file mode 100644 index 000000000..013e75258 --- /dev/null +++ b/Compiler/PoolAlloc.cpp @@ -0,0 +1,314 @@ +// +// Copyright (c) 2002-2010 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 "PoolAlloc.h" +#include "Common.h" + +#include "InitializeGlobals.h" +#include "osinclude.h" + +OS_TLSIndex PoolIndex = TLS_OUT_OF_INDEXES; + +void InitializeGlobalPools() +{ + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (globalPools) + return; + + TPoolAllocator *globalPoolAllocator = new TPoolAllocator(true); + + TThreadGlobalPools* threadData = new TThreadGlobalPools(); + + threadData->globalPoolAllocator = globalPoolAllocator; + + OS_SetTLSValue(PoolIndex, threadData); + globalPoolAllocator->push(); +} + +void FreeGlobalPools() +{ + // Release the allocated memory for this thread. + TThreadGlobalPools* globalPools= static_cast(OS_GetTLSValue(PoolIndex)); + if (!globalPools) + return; + + GlobalPoolAllocator.popAll(); + delete &GlobalPoolAllocator; + delete globalPools; +} + +bool InitializePoolIndex() +{ + // Allocate a TLS index. + if ((PoolIndex = OS_AllocTLSIndex()) == OS_INVALID_TLS_INDEX) + return false; + + return true; +} + +void FreePoolIndex() +{ + // Release the TLS index. + OS_FreeTLSIndex(PoolIndex); +} + +TPoolAllocator& GetGlobalPoolAllocator() +{ + TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); + + return *threadData->globalPoolAllocator; +} + +void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator) +{ + TThreadGlobalPools* threadData = static_cast(OS_GetTLSValue(PoolIndex)); + + threadData->globalPoolAllocator = poolAllocator; +} + +// +// Implement the functionality of the TPoolAllocator class, which +// is documented in PoolAlloc.h. +// +TPoolAllocator::TPoolAllocator(bool g, int growthIncrement, int allocationAlignment) : + global(g), + pageSize(growthIncrement), + alignment(allocationAlignment), + freeList(0), + inUseList(0), + numCalls(0) +{ + // + // Don't allow page sizes we know are smaller than all common + // OS page sizes. + // + if (pageSize < 4*1024) + pageSize = 4*1024; + + // + // A large currentPageOffset indicates a new page needs to + // be obtained to allocate memory. + // + currentPageOffset = pageSize; + + // + // Adjust alignment to be at least pointer aligned and + // power of 2. + // + size_t minAlign = sizeof(void*); + alignment &= ~(minAlign - 1); + if (alignment < minAlign) + alignment = minAlign; + size_t a = 1; + while (a < alignment) + a <<= 1; + alignment = a; + alignmentMask = a - 1; + + // + // Align header skip + // + headerSkip = minAlign; + if (headerSkip < sizeof(tHeader)) { + headerSkip = (sizeof(tHeader) + alignmentMask) & ~alignmentMask; + } +} + +TPoolAllocator::~TPoolAllocator() +{ + if (!global) { + // + // Then we know that this object is not being + // allocated after other, globally scoped objects + // that depend on it. So we can delete the "in use" memory. + // + while (inUseList) { + tHeader* next = inUseList->nextPage; + inUseList->~tHeader(); + delete [] reinterpret_cast(inUseList); + inUseList = next; + } + } + + // + // Always delete the free list memory - it can't be being + // (correctly) referenced, whether the pool allocator was + // global or not. We should not check the guard blocks + // here, because we did it already when the block was + // placed into the free list. + // + while (freeList) { + tHeader* next = freeList->nextPage; + delete [] reinterpret_cast(freeList); + freeList = next; + } +} + +// Support MSVC++ 6.0 +const unsigned char TAllocation::guardBlockBeginVal = 0xfb; +const unsigned char TAllocation::guardBlockEndVal = 0xfe; +const unsigned char TAllocation::userDataFill = 0xcd; + +# ifdef GUARD_BLOCKS + const size_t TAllocation::guardBlockSize = 16; +# else + const size_t TAllocation::guardBlockSize = 0; +# endif + +// +// Check a single guard block for damage +// +void TAllocation::checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const +{ + for (size_t x = 0; x < guardBlockSize; x++) { + if (blockMem[x] != val) { + char assertMsg[80]; + + // We don't print the assert message. It's here just to be helpful. + sprintf(assertMsg, "PoolAlloc: Damage %s %lu byte allocation at 0x%p\n", + locText, size, data()); + assert(0 && "PoolAlloc: Damage in guard block"); + } + } +} + + +void TPoolAllocator::push() +{ + tAllocState state = { currentPageOffset, inUseList }; + + stack.push_back(state); + + // + // Indicate there is no current page to allocate from. + // + currentPageOffset = pageSize; +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred since the last push(), or since the +// last pop(), or since the object's creation. +// +// The deallocated pages are saved for future allocations. +// +void TPoolAllocator::pop() +{ + if (stack.size() < 1) + return; + + tHeader* page = stack.back().page; + currentPageOffset = stack.back().offset; + + while (inUseList != page) { + // invoke destructor to free allocation list + inUseList->~tHeader(); + + tHeader* nextInUse = inUseList->nextPage; + if (inUseList->pageCount > 1) + delete [] reinterpret_cast(inUseList); + else { + inUseList->nextPage = freeList; + freeList = inUseList; + } + inUseList = nextInUse; + } + + stack.pop_back(); +} + +// +// Do a mass-deallocation of all the individual allocations +// that have occurred. +// +void TPoolAllocator::popAll() +{ + while (stack.size() > 0) + pop(); +} + +void* TPoolAllocator::allocate(size_t numBytes) +{ + // If we are using guard blocks, all allocations are bracketed by + // them: [guardblock][allocation][guardblock]. numBytes is how + // much memory the caller asked for. allocationSize is the total + // size including guard blocks. In release build, + // guardBlockSize=0 and this all gets optimized away. + size_t allocationSize = TAllocation::allocationSize(numBytes); + + // + // Just keep some interesting statistics. + // + ++numCalls; + totalBytes += numBytes; + + // + // Do the allocation, most likely case first, for efficiency. + // This step could be moved to be inline sometime. + // + if (currentPageOffset + allocationSize <= pageSize) { + // + // Safe to allocate from currentPageOffset. + // + unsigned char* memory = reinterpret_cast(inUseList) + currentPageOffset; + currentPageOffset += allocationSize; + currentPageOffset = (currentPageOffset + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, memory, numBytes); + } + + if (allocationSize + headerSkip > pageSize) { + // + // Do a multi-page allocation. Don't mix these with the others. + // The OS is efficient and allocating and free-ing multiple pages. + // + size_t numBytesToAlloc = allocationSize + headerSkip; + tHeader* memory = reinterpret_cast(::new char[numBytesToAlloc]); + if (memory == 0) + return 0; + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, (numBytesToAlloc + pageSize - 1) / pageSize); + inUseList = memory; + + currentPageOffset = pageSize; // make next allocation come from a new page + + // No guard blocks for multi-page allocations (yet) + return reinterpret_cast(reinterpret_cast(memory) + headerSkip); + } + + // + // Need a simple page to allocate from. + // + tHeader* memory; + if (freeList) { + memory = freeList; + freeList = freeList->nextPage; + } else { + memory = reinterpret_cast(::new char[pageSize]); + if (memory == 0) + return 0; + } + + // Use placement-new to initialize header + new(memory) tHeader(inUseList, 1); + inUseList = memory; + + unsigned char* ret = reinterpret_cast(inUseList) + headerSkip; + currentPageOffset = (headerSkip + allocationSize + alignmentMask) & ~alignmentMask; + + return initializeAllocation(inUseList, ret, numBytes); +} + + +// +// Check all allocations in a list for damage by calling check on each. +// +void TAllocation::checkAllocList() const +{ + for (const TAllocation* alloc = this; alloc != 0; alloc = alloc->prevAlloc) + alloc->check(); +} diff --git a/Compiler/PoolAlloc.h b/Compiler/PoolAlloc.h new file mode 100644 index 000000000..bd417b7c1 --- /dev/null +++ b/Compiler/PoolAlloc.h @@ -0,0 +1,321 @@ +// +// Copyright (c) 2002-2010 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 _POOLALLOC_INCLUDED_ +#define _POOLALLOC_INCLUDED_ + +#ifdef _DEBUG +# define GUARD_BLOCKS // define to enable guard block sanity checking +#endif + +// +// This header defines an allocator that can be used to efficiently +// allocate a large number of small requests for heap memory, with the +// intention that they are not individually deallocated, but rather +// collectively deallocated at one time. +// +// This simultaneously +// +// * Makes each individual allocation much more efficient; the +// typical allocation is trivial. +// * Completely avoids the cost of doing individual deallocation. +// * Saves the trouble of tracking down and plugging a large class of leaks. +// +// Individual classes can use this allocator by supplying their own +// new and delete methods. +// +// STL containers can use this allocator by using the pool_allocator +// class as the allocator (second) template argument. +// + +#include +#include + +// If we are using guard blocks, we must track each indivual +// allocation. If we aren't using guard blocks, these +// never get instantiated, so won't have any impact. +// + +class TAllocation { +public: + TAllocation(size_t size, unsigned char* mem, TAllocation* prev = 0) : + size(size), mem(mem), prevAlloc(prev) { + // Allocations are bracketed: + // [allocationHeader][initialGuardBlock][userData][finalGuardBlock] + // This would be cleaner with if (guardBlockSize)..., but that + // makes the compiler print warnings about 0 length memsets, + // even with the if() protecting them. +# ifdef GUARD_BLOCKS + memset(preGuard(), guardBlockBeginVal, guardBlockSize); + memset(data(), userDataFill, size); + memset(postGuard(), guardBlockEndVal, guardBlockSize); +# endif + } + + void check() const { + checkGuardBlock(preGuard(), guardBlockBeginVal, "before"); + checkGuardBlock(postGuard(), guardBlockEndVal, "after"); + } + + void checkAllocList() const; + + // Return total size needed to accomodate user buffer of 'size', + // plus our tracking data. + inline static size_t allocationSize(size_t size) { + return size + 2 * guardBlockSize + headerSize(); + } + + // Offset from surrounding buffer to get to user data buffer. + inline static unsigned char* offsetAllocation(unsigned char* m) { + return m + guardBlockSize + headerSize(); + } + +private: + void checkGuardBlock(unsigned char* blockMem, unsigned char val, const char* locText) const; + + // Find offsets to pre and post guard blocks, and user data buffer + unsigned char* preGuard() const { return mem + headerSize(); } + unsigned char* data() const { return preGuard() + guardBlockSize; } + unsigned char* postGuard() const { return data() + size; } + + size_t size; // size of the user data area + unsigned char* mem; // beginning of our allocation (pts to header) + TAllocation* prevAlloc; // prior allocation in the chain + + // Support MSVC++ 6.0 + const static unsigned char guardBlockBeginVal; + const static unsigned char guardBlockEndVal; + const static unsigned char userDataFill; + + const static size_t guardBlockSize; +# ifdef GUARD_BLOCKS + inline static size_t headerSize() { return sizeof(TAllocation); } +# else + inline static size_t headerSize() { return 0; } +# endif +}; + +// +// There are several stacks. One is to track the pushing and popping +// of the user, and not yet implemented. The others are simply a +// repositories of free pages or used pages. +// +// Page stacks are linked together with a simple header at the beginning +// of each allocation obtained from the underlying OS. Multi-page allocations +// are returned to the OS. Individual page allocations are kept for future +// re-use. +// +// The "page size" used is not, nor must it match, the underlying OS +// page size. But, having it be about that size or equal to a set of +// pages is likely most optimal. +// +class TPoolAllocator { +public: + TPoolAllocator(bool global = false, int growthIncrement = 8*1024, int allocationAlignment = 16); + + // + // Don't call the destructor just to free up the memory, call pop() + // + ~TPoolAllocator(); + + // + // Call push() to establish a new place to pop memory too. Does not + // have to be called to get things started. + // + void push(); + + // + // Call pop() to free all memory allocated since the last call to push(), + // or if no last call to push, frees all memory since first allocation. + // + void pop(); + + // + // Call popAll() to free all memory allocated. + // + void popAll(); + + // + // Call allocate() to actually acquire memory. Returns 0 if no memory + // available, otherwise a properly aligned pointer to 'numBytes' of memory. + // + void* allocate(size_t numBytes); + + // + // There is no deallocate. The point of this class is that + // deallocation can be skipped by the user of it, as the model + // of use is to simultaneously deallocate everything at once + // by calling pop(), and to not have to solve memory leak problems. + // + +protected: + friend struct tHeader; + + struct tHeader { + tHeader(tHeader* nextPage, size_t pageCount) : +#ifdef GUARD_BLOCKS + lastAllocation(0), +#endif + nextPage(nextPage), pageCount(pageCount) { } + + ~tHeader() { +#ifdef GUARD_BLOCKS + if (lastAllocation) + lastAllocation->checkAllocList(); +#endif + } + + tHeader* nextPage; + size_t pageCount; +#ifdef GUARD_BLOCKS + TAllocation* lastAllocation; +#endif + }; + + struct tAllocState { + size_t offset; + tHeader* page; + }; + typedef std::vector tAllocStack; + + // Track allocations if and only if we're using guard blocks + void* initializeAllocation(tHeader* block, unsigned char* memory, size_t numBytes) { +# ifdef GUARD_BLOCKS + new(memory) TAllocation(numBytes, memory, block->lastAllocation); + block->lastAllocation = reinterpret_cast(memory); +# endif + + // This is optimized entirely away if GUARD_BLOCKS is not defined. + return TAllocation::offsetAllocation(memory); + } + + bool global; // should be true if this object is globally scoped + size_t pageSize; // granularity of allocation from the OS + size_t alignment; // all returned allocations will be aligned at + // this granularity, which will be a power of 2 + size_t alignmentMask; + size_t headerSkip; // amount of memory to skip to make room for the + // header (basically, size of header, rounded + // up to make it aligned + size_t currentPageOffset; // next offset in top of inUseList to allocate from + tHeader* freeList; // list of popped memory + tHeader* inUseList; // list of all memory currently being used + tAllocStack stack; // stack of where to allocate from, to partition pool + + int numCalls; // just an interesting statistic + size_t totalBytes; // just an interesting statistic +private: + TPoolAllocator& operator=(const TPoolAllocator&); // dont allow assignment operator + TPoolAllocator(const TPoolAllocator&); // dont allow default copy constructor +}; + + +// +// There could potentially be many pools with pops happening at +// different times. But a simple use is to have a global pop +// with everyone using the same global allocator. +// +typedef TPoolAllocator* PoolAllocatorPointer; +extern TPoolAllocator& GetGlobalPoolAllocator(); +#define GlobalPoolAllocator GetGlobalPoolAllocator() + + +struct TThreadGlobalPools +{ + TPoolAllocator* globalPoolAllocator; +}; + +void SetGlobalPoolAllocatorPtr(TPoolAllocator* poolAllocator); + +// +// This STL compatible allocator is intended to be used as the allocator +// parameter to templatized STL containers, like vector and map. +// +// It will use the pools for allocation, and not +// do any deallocation, but will still do destruction. +// +template +class pool_allocator { +public: + typedef size_t size_type; + typedef ptrdiff_t difference_type; + typedef T *pointer; + typedef const T *const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + template + struct rebind { + typedef pool_allocator other; + }; + pointer address(reference x) const { return &x; } + const_pointer address(const_reference x) const { return &x; } + +#ifdef USING_SGI_STL + pool_allocator() { } +#else + pool_allocator() : allocator(GlobalPoolAllocator) { } + pool_allocator(TPoolAllocator& a) : allocator(a) { } + pool_allocator(const pool_allocator& p) : allocator(p.allocator) { } +#endif + +#if defined(_MSC_VER) && _MSC_VER >= 1300 + template +#ifdef USING_SGI_STL + pool_allocator(const pool_allocator& p) /*: allocator(p.getAllocator())*/ { } +#else + pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } +#endif +#endif + +#ifndef _WIN32 + template + pool_allocator(const pool_allocator& p) : allocator(p.getAllocator()) { } +#endif + +#ifdef USING_SGI_STL + static pointer allocate(size_type n) { + return reinterpret_cast(getAllocator().allocate(n)); } + pointer allocate(size_type n, const void*) { + return reinterpret_cast(getAllocator().allocate(n)); } + + static void deallocate(void*, size_type) { } + static void deallocate(pointer, size_type) { } +#else + pointer allocate(size_type n) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } + pointer allocate(size_type n, const void*) { + return reinterpret_cast(getAllocator().allocate(n * sizeof(T))); } + + void deallocate(void*, size_type) { } + void deallocate(pointer, size_type) { } +#endif + + pointer _Charalloc(size_t n) { + return reinterpret_cast(getAllocator().allocate(n)); } + + void construct(pointer p, const T& val) { new ((void *)p) T(val); } + void destroy(pointer p) { p->T::~T(); } + + bool operator==(const pool_allocator& rhs) const { return &getAllocator() == &rhs.getAllocator(); } + bool operator!=(const pool_allocator& rhs) const { return &getAllocator() != &rhs.getAllocator(); } + + size_type max_size() const { return static_cast(-1) / sizeof(T); } + size_type max_size(int size) const { return static_cast(-1) / size; } + +#ifdef USING_SGI_STL + //void setAllocator(TPoolAllocator* a) { allocator = a; } + static TPoolAllocator& getAllocator() { return GlobalPoolAllocator; } +#else + void setAllocator(TPoolAllocator* a) { allocator = *a; } + TPoolAllocator& getAllocator() const { return allocator; } + +protected: + TPoolAllocator& allocator; +#endif +}; + +#endif // _POOLALLOC_INCLUDED_ diff --git a/Compiler/Preprocessor/atom.c b/Compiler/Preprocessor/atom.c new file mode 100644 index 000000000..204fb0df2 --- /dev/null +++ b/Compiler/Preprocessor/atom.c @@ -0,0 +1,740 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +// +// atom.c +// + +#include +#include +#include +#include + +#include "slglobals.h" + +#undef malloc +#undef realloc +#undef free + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static const struct { + int val; + const char *str; +} tokens[] = { + { CPP_AND_OP, "&&" }, + { CPP_AND_ASSIGN, "&=" }, + { CPP_SUB_ASSIGN, "-=" }, + { CPP_MOD_ASSIGN, "%=" }, + { CPP_ADD_ASSIGN, "+=" }, + { CPP_DIV_ASSIGN, "/=" }, + { CPP_MUL_ASSIGN, "*=" }, + { CPP_RIGHT_BRACKET, ":>" }, + { CPP_EQ_OP, "==" }, + { CPP_XOR_OP, "^^" }, + { CPP_XOR_ASSIGN, "^=" }, + { CPP_FLOATCONSTANT, "" }, + { CPP_GE_OP, ">=" }, + { CPP_RIGHT_OP, ">>" }, + { CPP_RIGHT_ASSIGN, ">>=" }, + { CPP_IDENTIFIER, "" }, + { CPP_INTCONSTANT, "" }, + { CPP_LE_OP, "<=" }, + { CPP_LEFT_OP, "<<" }, + { CPP_LEFT_ASSIGN, "<<=" }, + { CPP_LEFT_BRACKET, "<:" }, + { CPP_LEFT_BRACE, "<%" }, + { CPP_DEC_OP, "--" }, + { CPP_RIGHT_BRACE, "%>" }, + { CPP_NE_OP, "!=" }, + { CPP_OR_OP, "||" }, + { CPP_OR_ASSIGN, "|=" }, + { CPP_INC_OP, "++" }, + { CPP_STRCONSTANT, "" }, + { CPP_TYPEIDENTIFIER, "" }, +}; + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////////// String table: ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_STRING_TABLE_SIZE 16384 + +typedef struct StringTable_Rec { + char *strings; + int nextFree; + int size; +} StringTable; + +/* + * InitStringTable() - Initialize the string table. + * + */ + +static int InitStringTable(StringTable *stable) +{ + stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE); + if (!stable->strings) + return 0; + // Zero-th offset means "empty" so don't use it. + stable->nextFree = 1; + stable->size = INIT_STRING_TABLE_SIZE; + return 1; +} // InitStringTable + +/* + * FreeStringTable() - Free the string table. + * + */ + +static void FreeStringTable(StringTable *stable) +{ + if (stable->strings) + free(stable->strings); + stable->strings = NULL; + stable->nextFree = 0; + stable->size = 0; +} // FreeStringTable + +/* + * HashString() - Hash a string with the base hash function. + * + */ + +static int HashString(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*13507 + *s*197) ^ (hval >> 2); + s++; + } + return hval & 0x7fffffff; +} // HashString + +/* + * HashString2() - Hash a string with the incrimenting hash function. + * + */ + +static int HashString2(const char *s) +{ + int hval = 0; + + while (*s) { + hval = (hval*729 + *s*37) ^ (hval >> 1); + s++; + } + return hval; +} // HashString2 + +/* + * AddString() - Add a string to a string table. Return it's offset. + * + */ + +static int AddString(StringTable *stable, const char *s) +{ + int len, loc; + char *str; + + len = (int) strlen(s); + if (stable->nextFree + len + 1 >= stable->size) { + assert(stable->size < 1000000); + str = (char *) malloc(stable->size*2); + memcpy(str, stable->strings, stable->size); + free(stable->strings); + stable->strings = str; + } + loc = stable->nextFree; + strcpy(&stable->strings[loc], s); + stable->nextFree += len + 1; + return loc; +} // AddString + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Hash table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_HASH_TABLE_SIZE 2047 +#define HASH_TABLE_MAX_COLLISIONS 3 + +typedef struct HashEntry_Rec { + int index; // String table offset of string representation + int value; // Atom (symbol) value +} HashEntry; + +typedef struct HashTable_Rec { + HashEntry *entry; + int size; + int entries; + int counts[HASH_TABLE_MAX_COLLISIONS + 1]; +} HashTable; + +/* + * InitHashTable() - Initialize the hash table. + * + */ + +static int InitHashTable(HashTable *htable, int fsize) +{ + int ii; + + htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize); + if (!htable->entry) + return 0; + htable->size = fsize; + for (ii = 0; ii < fsize; ii++) { + htable->entry[ii].index = 0; + htable->entry[ii].value = 0; + } + htable->entries = 0; + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) + htable->counts[ii] = 0; + return 1; +} // InitHashTable + +/* + * FreeHashTable() - Free the hash table. + * + */ + +static void FreeHashTable(HashTable *htable) +{ + if (htable->entry) + free(htable->entry); + htable->entry = NULL; + htable->size = 0; + htable->entries = 0; +} // FreeHashTable + +/* + * Empty() - See if a hash table entry is empty. + * + */ + +static int Empty(HashTable *htable, int hashloc) +{ + assert(hashloc >= 0 && hashloc < htable->size); + if (htable->entry[hashloc].index == 0) { + return 1; + } else { + return 0; + } +} // Empty + +/* + * Match() - See if a hash table entry is matches a string. + * + */ + +static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc) +{ + int strloc; + + strloc = htable->entry[hashloc].index; + if (!strcmp(s, &stable->strings[strloc])) { + return 1; + } else { + return 0; + } +} // Match + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////// Atom table: /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +#define INIT_ATOM_TABLE_SIZE 1024 + + +struct AtomTable_Rec { + StringTable stable; // String table. + HashTable htable; // Hashes string to atom number and token value. Multiple strings can + // have the same token value but each unique string is a unique atom. + int *amap; // Maps atom value to offset in string table. Atoms all map to unique + // strings except for some undefined values in the lower, fixed part + // of the atom table that map to "". The lowest 256 atoms + // correspond to single character ASCII values except for alphanumeric + // characters and '_', which can be other tokens. Next come the + // language tokens with their atom values equal to the token value. + // Then come predefined atoms, followed by user specified identifiers. + int *arev; // Reversed atom for symbol table use. + int nextFree; + int size; +}; + +static AtomTable latable = { { 0 } }; +AtomTable *atable = &latable; + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom); + +/* + * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller. + * + */ + +static int GrowAtomTable(AtomTable *atable, int size) +{ + int *newmap, *newrev; + + if (atable->size < size) { + if (atable->amap) { + newmap = realloc(atable->amap, sizeof(int)*size); + newrev = realloc(atable->arev, sizeof(int)*size); + } else { + newmap = malloc(sizeof(int)*size); + newrev = malloc(sizeof(int)*size); + atable->size = 0; + } + if (!newmap || !newrev) { + /* failed to grow -- error */ + if (newmap) + atable->amap = newmap; + if (newrev) + atable->amap = newrev; + return -1; + } + memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int)); + memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int)); + atable->amap = newmap; + atable->arev = newrev; + atable->size = size; + } + return 0; +} // GrowAtomTable + +/* + * lReverse() - Reverse the bottom 20 bits of a 32 bit int. + * + */ + +static int lReverse(int fval) +{ + unsigned int in = fval; + int result = 0, cnt = 0; + + while(in) { + result <<= 1; + result |= in&1; + in >>= 1; + cnt++; + } + + // Don't use all 31 bits. One million atoms is plenty and sometimes the + // upper bits are used for other things. + + if (cnt < 20) + result <<= 20 - cnt; + return result; +} // lReverse + +/* + * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1. + * + */ + +static int AllocateAtom(AtomTable *atable) +{ + if (atable->nextFree >= atable->size) + GrowAtomTable(atable, atable->nextFree*2); + atable->amap[atable->nextFree] = -1; + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + return atable->nextFree - 1; +} // AllocateAtom + +/* + * SetAtomValue() - Allocate a new atom associated with "hashindex". + * + */ + +static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex) +{ + atable->amap[atomnumber] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atomnumber; +} // SetAtomValue + +/* + * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full. + * + */ + +static int FindHashLoc(AtomTable *atable, const char *s) +{ + int hashloc, hashdelta, count; + int FoundEmptySlot = 0; + int collision[HASH_TABLE_MAX_COLLISIONS + 1]; + + hashloc = HashString(s) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) + return hashloc; + collision[0] = hashloc; + hashdelta = HashString2(s); + count = 0; + while (count < HASH_TABLE_MAX_COLLISIONS) { + hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size; + if (!Empty(&atable->htable, hashloc)) { + if (Match(&atable->htable, &atable->stable, s, hashloc)) { + return hashloc; + } + } else { + FoundEmptySlot = 1; + break; + } + count++; + collision[count] = hashloc; + } + + if (!FoundEmptySlot) { + if (cpp->options.DumpAtomTable) { + int ii; + char str[200]; + sprintf(str, "*** Hash failed with more than %d collisions. Must increase hash table size. ***", + HASH_TABLE_MAX_COLLISIONS); + CPPShInfoLogMsg(str); + + sprintf(str, "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta); + CPPShInfoLogMsg(str); + for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) { + sprintf(str, "*** Collides on try %d at hash entry %04x with \"%s\"", + ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value)); + CPPShInfoLogMsg(str); + } + } + return -1; + } else { + atable->htable.counts[count]++; + } + } + return hashloc; +} // FindHashLoc + +/* + * IncreaseHashTableSize() + * + */ + +static int IncreaseHashTableSize(AtomTable *atable) +{ + int ii, strloc, oldhashloc, value, size; + AtomTable oldtable; + char *s; + + // Save the old atom table and create a new one: + + oldtable = *atable; + size = oldtable.htable.size*2 + 1; + if (!InitAtomTable(atable, size)) + return 0; + + // Add all the existing values to the new atom table preserving their atom values: + + for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) { + strloc = oldtable.amap[ii]; + s = &oldtable.stable.strings[strloc]; + oldhashloc = FindHashLoc(&oldtable, s); + assert(oldhashloc >= 0); + value = oldtable.htable.entry[oldhashloc].value; + AddAtomFixed(atable, s, value); + } + FreeAtomTable(&oldtable); + return 1; +} // IncreaseHashTableSize + +/* + * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to 0. Return the hash table index. + */ + +static int LookUpAddStringHash(AtomTable *atable, const char *s) +{ + int hashloc, strloc; + + while(1) { + hashloc = FindHashLoc(atable, s); + if (hashloc >= 0) + break; + IncreaseHashTableSize(atable); + } + + if (Empty(&atable->htable, hashloc)) { + atable->htable.entries++; + strloc = AddString(&atable->stable, s); + atable->htable.entry[hashloc].index = strloc; + atable->htable.entry[hashloc].value = 0; + } + return hashloc; +} // LookUpAddStringHash + +/* + * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and + * initialize the atom value in the hash table to the next atom number. + * Return the atom value of string. + */ + +int LookUpAddString(AtomTable *atable, const char *s) +{ + int hashindex, atom; + + hashindex = LookUpAddStringHash(atable, s); + atom = atable->htable.entry[hashindex].value; + if (atom == 0) { + atom = AllocateAtom(atable); + SetAtomValue(atable, atom, hashindex); + } + return atom; +} // LookUpAddString + +/* + * GetAtomString() + * + */ + +const char *GetAtomString(AtomTable *atable, int atom) +{ + int soffset; + + if (atom > 0 && atom < atable->nextFree) { + soffset = atable->amap[atom]; + if (soffset > 0 && soffset < atable->stable.nextFree) { + return &atable->stable.strings[soffset]; + } else { + return ""; + } + } else { + if (atom == 0) { + return ""; + } else { + if (atom == EOF) { + return ""; + } else { + return ""; + } + } + } +} // GetAtomString + +/* + * GetReversedAtom() + * + */ + +int GetReversedAtom(AtomTable *atable, int atom) +{ + if (atom > 0 && atom < atable->nextFree) { + return atable->arev[atom]; + } else { + return 0; + } +} // GetReversedAtom + +/* + * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there. + * Return it's atom index. + */ + +int AddAtom(AtomTable *atable, const char *s) +{ + int atom; + + atom = LookUpAddString(atable, s); + return atom; +} // AddAtom + +/* + * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there. + * Assign it the atom value of "atom". + */ + +static int AddAtomFixed(AtomTable *atable, const char *s, int atom) +{ + int hashindex, lsize; + + hashindex = LookUpAddStringHash(atable, s); + if (atable->nextFree >= atable->size || atom >= atable->size) { + lsize = atable->size*2; + if (lsize <= atom) + lsize = atom + 1; + GrowAtomTable(atable, lsize); + } + atable->amap[atom] = atable->htable.entry[hashindex].index; + atable->htable.entry[hashindex].value = atom; + //if (atom >= atable->nextFree) + // atable->nextFree = atom + 1; + while (atom >= atable->nextFree) { + atable->arev[atable->nextFree] = lReverse(atable->nextFree); + atable->nextFree++; + } + return atom; +} // AddAtomFixed + +/* + * InitAtomTable() - Initialize the atom table. + * + */ + +int InitAtomTable(AtomTable *atable, int htsize) +{ + int ii; + + htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize; + if (!InitStringTable(&atable->stable)) + return 0; + if (!InitHashTable(&atable->htable, htsize)) + return 0; + + atable->nextFree = 0; + atable->amap = NULL; + atable->size = 0; + GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE); + if (!atable->amap) + return 0; + + // Initialize lower part of atom table to "" atom: + + AddAtomFixed(atable, "", 0); + for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++) + atable->amap[ii] = atable->amap[0]; + + // Add single character tokens to the atom table: + + { + const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#"; + char t[2]; + + t[1] = '\0'; + while (*s) { + t[0] = *s; + AddAtomFixed(atable, t, s[0]); + s++; + } + } + + // Add multiple character scanner tokens : + + for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++) + AddAtomFixed(atable, tokens[ii].str, tokens[ii].val); + + // Add error symbol if running in error mode: + + if (cpp->options.ErrorMode) + AddAtomFixed(atable, "error", ERROR_SY); + + AddAtom(atable, "<*** end fixed atoms ***>"); + + return 1; +} // InitAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////// Debug Printing Functions: ////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * PrintAtomTable() + * + */ + +void PrintAtomTable(AtomTable *atable) +{ + int ii; + char str[200]; + + for (ii = 0; ii < atable->nextFree; ii++) { + sprintf(str, "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]); + CPPDebugLogMsg(str); + } + sprintf(str, "Hash table: size=%d, entries=%d, collisions=", + atable->htable.size, atable->htable.entries); + CPPDebugLogMsg(str); + for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) { + sprintf(str, " %d", atable->htable.counts[ii]); + CPPDebugLogMsg(str); + } + +} // PrintAtomTable + + +/* + * GetStringOfAtom() + * + */ + +char* GetStringOfAtom(AtomTable *atable, int atom) +{ + char* chr_str; + chr_str=&atable->stable.strings[atable->amap[atom]]; + return chr_str; +} // GetStringOfAtom + +/* + * FreeAtomTable() - Free the atom table and associated memory + * + */ + +void FreeAtomTable(AtomTable *atable) +{ + FreeStringTable(&atable->stable); + FreeHashTable(&atable->htable); + if (atable->amap) + free(atable->amap); + if (atable->arev) + free(atable->arev); + atable->amap = NULL; + atable->arev = NULL; + atable->nextFree = 0; + atable->size = 0; +} // FreeAtomTable + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// End of atom.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/Compiler/Preprocessor/atom.h b/Compiler/Preprocessor/atom.h new file mode 100644 index 000000000..9d4203791 --- /dev/null +++ b/Compiler/Preprocessor/atom.h @@ -0,0 +1,68 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// atom.h +// + +#if !defined(__ATOM_H) +#define __ATOM_H 1 + +typedef struct AtomTable_Rec AtomTable; + +extern AtomTable *atable; + +int InitAtomTable(AtomTable *atable, int htsize); +void FreeAtomTable(AtomTable *atable); +int AddAtom(AtomTable *atable, const char *s); +void PrintAtomTable(AtomTable *atable); +int LookUpAddString(AtomTable *atable, const char *s); +const char *GetAtomString(AtomTable *atable, int atom); +int GetReversedAtom(AtomTable *atable, int atom); +char* GetStringOfAtom(AtomTable *atable, int atom); +#endif // !defined(__ATOM_H) diff --git a/Compiler/Preprocessor/compile.h b/Compiler/Preprocessor/compile.h new file mode 100644 index 000000000..9e87afcfb --- /dev/null +++ b/Compiler/Preprocessor/compile.h @@ -0,0 +1,104 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// compile.h +// + +#if !defined(__COMPILE_H) +#define __COMPILE_H 1 + +int InitCPPStruct(void); + +typedef struct Options_Rec{ + const char *profileString; + int ErrorMode; + int Quiet; + + // Debug The Compiler options: + int DumpAtomTable; +} Options; + +struct CPPStruct_Rec { + // Public members + SourceLoc *pLastSourceLoc; // Set at the start of each statement by the tree walkers + Options options; // Compile options and parameters + + // Private members + SourceLoc lastSourceLoc; + + // Scanner data: + + SourceLoc *tokenLoc; // Source location of most recent token seen by the scanner + int mostRecentToken; // Most recent token seen by the scanner + InputSrc *currentInput; + int previous_token; + int notAVersionToken; // used to make sure that #version is the first token seen in the file, if present + + void *pC; // storing the parseContext of the compile object in cpp. + + // Private members: + SourceLoc ltokenLoc; + int ifdepth; //current #if-#else-#endif nesting in the cpp.c file (pre-processor) + int elsedepth[64]; //Keep a track of #if depth..Max allowed is 64. + int elsetracker; //#if-#else and #endif constructs...Counter. + const char *ErrMsg; + int CompileError; //Indicate compile error when #error, #else,#elif mismatch. + + // + // Globals used to communicate between PaParseStrings() and yy_input()and + // also across the files.(gen_glslang.cpp and scanner.c) + // + int PaWhichStr; // which string we're parsing + int* PaStrLen; // array of lengths of the PaArgv strings + int PaArgc; // count of strings in the array + char** PaArgv; // our array of strings to parse + unsigned int tokensBeforeEOF : 1; +}; + +#endif // !defined(__COMPILE_H) diff --git a/Compiler/Preprocessor/cpp.c b/Compiler/Preprocessor/cpp.c new file mode 100644 index 000000000..d852fd4ed --- /dev/null +++ b/Compiler/Preprocessor/cpp.c @@ -0,0 +1,1009 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.c +// + +#include +#include +#include +#include +#include + +#include "slglobals.h" + +static int CPPif(yystypepp * yylvalpp); + +/* Don't use memory.c's replacements, as we clean up properly here */ +#undef malloc +#undef free + +static int bindAtom = 0; +static int constAtom = 0; +static int defaultAtom = 0; +static int defineAtom = 0; +static int definedAtom = 0; +static int elseAtom = 0; +static int elifAtom = 0; +static int endifAtom = 0; +static int ifAtom = 0; +static int ifdefAtom = 0; +static int ifndefAtom = 0; +static int includeAtom = 0; +static int lineAtom = 0; +static int pragmaAtom = 0; +static int texunitAtom = 0; +static int undefAtom = 0; +static int errorAtom = 0; +static int __LINE__Atom = 0; +static int __FILE__Atom = 0; +static int __VERSION__Atom = 0; +static int versionAtom = 0; +static int extensionAtom = 0; + +static Scope *macros = 0; +#define MAX_MACRO_ARGS 64 +#define MAX_IF_NESTING 64 + +static SourceLoc ifloc; /* outermost #if */ + +int InitCPP(void) +{ + char buffer[64], *t; + const char *f; + // Add various atoms needed by the CPP line scanner: + bindAtom = LookUpAddString(atable, "bind"); + constAtom = LookUpAddString(atable, "const"); + defaultAtom = LookUpAddString(atable, "default"); + defineAtom = LookUpAddString(atable, "define"); + definedAtom = LookUpAddString(atable, "defined"); + elifAtom = LookUpAddString(atable, "elif"); + elseAtom = LookUpAddString(atable, "else"); + endifAtom = LookUpAddString(atable, "endif"); + ifAtom = LookUpAddString(atable, "if"); + ifdefAtom = LookUpAddString(atable, "ifdef"); + ifndefAtom = LookUpAddString(atable, "ifndef"); + includeAtom = LookUpAddString(atable, "include"); + lineAtom = LookUpAddString(atable, "line"); + pragmaAtom = LookUpAddString(atable, "pragma"); + texunitAtom = LookUpAddString(atable, "texunit"); + undefAtom = LookUpAddString(atable, "undef"); + errorAtom = LookUpAddString(atable, "error"); + __LINE__Atom = LookUpAddString(atable, "__LINE__"); + __FILE__Atom = LookUpAddString(atable, "__FILE__"); + __VERSION__Atom = LookUpAddString(atable, "__VERSION__"); + versionAtom = LookUpAddString(atable, "version"); + extensionAtom = LookUpAddString(atable, "extension"); + macros = NewScopeInPool(mem_CreatePool(0, 0)); + strcpy(buffer, "PROFILE_"); + t = buffer + strlen(buffer); + f = cpp->options.profileString; + while ((isalnum(*f) || *f == '_') && t < buffer + sizeof(buffer) - 1) + *t++ = toupper(*f++); + *t = 0; + return 1; +} // InitCPP + +int FreeCPP(void) +{ + if (macros) + { + mem_FreePool(macros->pool); + macros = 0; + } + + return 1; +} + +int FinalCPP(void) +{ + if (cpp->ifdepth) + CPPErrorToInfoLog("#if mismatch"); + return 1; +} + +static int CPPdefine(yystypepp * yylvalpp) +{ + int token, name, args[MAX_MACRO_ARGS], argc; + const char *message; + MacroSymbol mac; + Symbol *symb; + SourceLoc dummyLoc; + memset(&mac, 0, sizeof(mac)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + name = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(' && !yylvalpp->sc_int) { + // gather arguments + argc = 0; + do { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (argc == 0 && token == ')') break; + if (token != CPP_IDENTIFIER) { + CPPErrorToInfoLog("#define"); + return token; + } + if (argc < MAX_MACRO_ARGS) + args[argc++] = yylvalpp->sc_ident; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } while (token == ','); + if (token != ')') { + CPPErrorToInfoLog("#define"); + return token; + } + mac.argc = argc; + mac.args = mem_Alloc(macros->pool, argc * sizeof(int)); + memcpy(mac.args, args, argc * sizeof(int)); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + mac.body = NewTokenStream(GetAtomString(atable, name), macros->pool); + while (token != '\n') { + while (token == '\\') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + else + RecordToken(mac.body, '\\', yylvalpp); + } + RecordToken(mac.body, token, yylvalpp); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + }; + + symb = LookUpSymbol(macros, name); + if (symb) { + if (!symb->details.mac.undef) { + // already defined -- need to make sure they are identical + if (symb->details.mac.argc != mac.argc) goto error; + for (argc=0; argc < mac.argc; argc++) + if (symb->details.mac.args[argc] != mac.args[argc]) + goto error; + RewindTokenStream(symb->details.mac.body); + RewindTokenStream(mac.body); + do { + int old_lval, old_token; + old_token = ReadToken(symb->details.mac.body, yylvalpp); + old_lval = yylvalpp->sc_int; + token = ReadToken(mac.body, yylvalpp); + if (token != old_token || yylvalpp->sc_int != old_lval) { + error: + StoreStr("Macro Redefined"); + StoreStr(GetStringOfAtom(atable,name)); + message=GetStrfromTStr(); + DecLineNumber(); + CPPShInfoLogMsg(message); + IncLineNumber(); + ResetTString(); + break; } + } while (token > 0); + } + //FreeMacro(&symb->details.mac); + } else { + dummyLoc.file = 0; + dummyLoc.line = 0; + symb = AddSymbol(&dummyLoc, macros, name, MACRO_S); + } + symb->details.mac = mac; + return '\n'; +} // CPPdefine + +static int CPPundef(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + Symbol *symb; + if(token == '\n'){ + CPPErrorToInfoLog("#undef"); + return token; + } + if (token != CPP_IDENTIFIER) + goto error; + symb = LookUpSymbol(macros, yylvalpp->sc_ident); + if (symb) { + symb->details.mac.undef = 1; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + error: + CPPErrorToInfoLog("#undef"); + } + return token; +} // CPPundef + +/* CPPelse -- skip forward to appropriate spot. This is actually used +** to skip to and #endif after seeing an #else, AND to skip to a #else, +** #elif, or #endif after a #if/#ifdef/#ifndef/#elif test was false +*/ + +static int CPPelse(int matchelse, yystypepp * yylvalpp) +{ + int atom,depth=0; + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + while (token > 0) { + if (token != '#') { + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + continue; + } + if ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) != CPP_IDENTIFIER) + continue; + atom = yylvalpp->sc_ident; + if (atom == ifAtom || atom == ifdefAtom || atom == ifndefAtom){ + depth++; cpp->ifdepth++; cpp->elsetracker++; + } + else if (atom == endifAtom) { + if(--depth<=0){ + cpp->elsedepth[cpp->elsetracker]=0; + --cpp->elsetracker; + if (cpp->ifdepth) + --cpp->ifdepth; + break; + } + --cpp->elsetracker; + --cpp->ifdepth; + } + else if (((int)(matchelse) != 0)&& depth==0) { + if (atom == elseAtom ) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + break; + } + else if (atom == elifAtom) { + /* we decrement cpp->ifdepth here, because CPPif will increment + * it and we really want to leave it alone */ + if (cpp->ifdepth){ + --cpp->ifdepth; + --cpp->elsetracker; + } + return CPPif(yylvalpp); + } + } + else if((atom==elseAtom) && (!ChkCorrectElseNesting())){ + CPPErrorToInfoLog("#else after a #else"); + cpp->CompileError=1; + } + }; + return token; +} + +enum eval_prec { + MIN_PREC, + COND, LOGOR, LOGAND, OR, XOR, AND, EQUAL, RELATION, SHIFT, ADD, MUL, UNARY, + MAX_PREC +}; + +static int op_logor(int a, int b) { return a || b; } +static int op_logand(int a, int b) { return a && b; } +static int op_or(int a, int b) { return a | b; } +static int op_xor(int a, int b) { return a ^ b; } +static int op_and(int a, int b) { return a & b; } +static int op_eq(int a, int b) { return a == b; } +static int op_ne(int a, int b) { return a != b; } +static int op_ge(int a, int b) { return a >= b; } +static int op_le(int a, int b) { return a <= b; } +static int op_gt(int a, int b) { return a > b; } +static int op_lt(int a, int b) { return a < b; } +static int op_shl(int a, int b) { return a << b; } +static int op_shr(int a, int b) { return a >> b; } +static int op_add(int a, int b) { return a + b; } +static int op_sub(int a, int b) { return a - b; } +static int op_mul(int a, int b) { return a * b; } +static int op_div(int a, int b) { return a / b; } +static int op_mod(int a, int b) { return a % b; } +static int op_pos(int a) { return a; } +static int op_neg(int a) { return -a; } +static int op_cmpl(int a) { return ~a; } +static int op_not(int a) { return !a; } + +struct { + int token, prec, (*op)(int, int); +} binop[] = { + { CPP_OR_OP, LOGOR, op_logor }, + { CPP_AND_OP, LOGAND, op_logand }, + { '|', OR, op_or }, + { '^', XOR, op_xor }, + { '&', AND, op_and }, + { CPP_EQ_OP, EQUAL, op_eq }, + { CPP_NE_OP, EQUAL, op_ne }, + { '>', RELATION, op_gt }, + { CPP_GE_OP, RELATION, op_ge }, + { '<', RELATION, op_lt }, + { CPP_LE_OP, RELATION, op_le }, + { CPP_LEFT_OP, SHIFT, op_shl }, + { CPP_RIGHT_OP, SHIFT, op_shr }, + { '+', ADD, op_add }, + { '-', ADD, op_sub }, + { '*', MUL, op_mul }, + { '/', MUL, op_div }, + { '%', MUL, op_mod }, +}; + +struct { + int token, (*op)(int); +} unop[] = { + { '+', op_pos }, + { '-', op_neg }, + { '~', op_cmpl }, + { '!', op_not }, +}; + +#define ALEN(A) (sizeof(A)/sizeof(A[0])) + +static int eval(int token, int prec, int *res, int *err, yystypepp * yylvalpp) +{ + int i, val; + Symbol *s; + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == definedAtom) { + int needclose = 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') { + needclose = 1; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (token != CPP_IDENTIFIER) + goto error; + *res = (s = LookUpSymbol(macros, yylvalpp->sc_ident)) + ? !s->details.mac.undef : 0; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (needclose) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else if (MacroExpand(yylvalpp->sc_ident, yylvalpp)) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + return eval(token, prec, res, err, yylvalpp); + } else { + goto error; + } + } else if (token == CPP_INTCONSTANT) { + *res = yylvalpp->sc_int; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } else if (token == '(') { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, MIN_PREC, res, err, yylvalpp); + if (!*err) { + if (token != ')') + goto error; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } else { + for (i = ALEN(unop) - 1; i >= 0; i--) { + if (unop[i].token == token) + break; + } + if (i >= 0) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, UNARY, res, err, yylvalpp); + *res = unop[i].op(*res); + } else { + goto error; + } + } + while (!*err) { + if (token == ')' || token == '\n') break; + for (i = ALEN(binop) - 1; i >= 0; i--) { + if (binop[i].token == token) + break; + } + if (i < 0 || binop[i].prec <= prec) + break; + val = *res; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = eval(token, binop[i].prec, res, err, yylvalpp); + *res = binop[i].op(val, *res); + } + return token; +error: + CPPErrorToInfoLog("incorrect preprocessor directive"); + *err = 1; + *res = 0; + return token; +} // eval + +static int CPPif(yystypepp * yylvalpp) { + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int res = 0, err = 0; + cpp->elsetracker++; + if (!cpp->ifdepth++) + ifloc = *cpp->tokenLoc; + if(cpp->ifdepth >MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + return 0; + } + token = eval(token, MIN_PREC, &res, &err, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following the preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (!res && !err) { + token = CPPelse(1, yylvalpp); + } + + return token; +} // CPPif + +static int CPPifdef(int defined, yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + int name = yylvalpp->sc_ident; + if(++cpp->ifdepth >MAX_IF_NESTING){ + CPPErrorToInfoLog("max #if nesting depth exceeded"); + return 0; + } + cpp->elsetracker++; + if (token != CPP_IDENTIFIER) { + defined ? CPPErrorToInfoLog("ifdef"):CPPErrorToInfoLog("ifndef"); + } else { + Symbol *s = LookUpSymbol(macros, name); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #ifdef preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + if (((s && !s->details.mac.undef) ? 1 : 0) != defined) + token = CPPelse(1, yylvalpp); + } + return token; +} // CPPifdef + +static int CPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#line"); + IncLineNumber(); + return token; + } + else if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetLineNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == CPP_INTCONSTANT) { + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + SetStringNumber(yylvalpp->sc_int); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if(token!='\n') + CPPErrorToInfoLog("#line"); + } + else if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#line"); + } + } + else{ + CPPErrorToInfoLog("#line"); + } + return token; +} + +static int CPPerror(yystypepp * yylvalpp) { + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + + while (token != '\n') { + if (token == CPP_FLOATCONSTANT || token == CPP_INTCONSTANT){ + StoreStr(yylvalpp->symbol_name); + }else if(token == CPP_IDENTIFIER || token == CPP_STRCONSTANT){ + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + }else { + StoreStr(GetStringOfAtom(atable,token)); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + DecLineNumber(); + //store this msg into the shader's information log..set the Compile Error flag!!!! + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + cpp->CompileError=1; + IncLineNumber(); + return '\n'; +}//CPPerror + +static int CPPpragma(yystypepp * yylvalpp) +{ + char SrcStrName[2]; + char** allTokens; + int tokenCount = 0; + int maxTokenCount = 10; + const char* SrcStr; + int i; + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token=='\n') { + DecLineNumber(); + CPPErrorToInfoLog("#pragma"); + IncLineNumber(); + return token; + } + + allTokens = (char**)malloc(sizeof(char*) * maxTokenCount); + + while (token != '\n') { + if (tokenCount >= maxTokenCount) { + maxTokenCount *= 2; + allTokens = (char**)realloc((char**)allTokens, sizeof(char*) * maxTokenCount); + } + switch (token) { + case CPP_IDENTIFIER: + SrcStr = GetAtomString(atable, yylvalpp->sc_ident); + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_INTCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case CPP_FLOATCONSTANT: + SrcStr = yylvalpp->symbol_name; + allTokens[tokenCount] = (char*)malloc(strlen(SrcStr) + 1); + strcpy(allTokens[tokenCount++], SrcStr); + break; + case -1: + // EOF + CPPShInfoLogMsg("#pragma directive must end with a newline"); + return token; + default: + SrcStrName[0] = token; + SrcStrName[1] = '\0'; + allTokens[tokenCount] = (char*)malloc(2); + strcpy(allTokens[tokenCount++], SrcStrName); + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + cpp->currentInput->ungetch(cpp->currentInput, token, yylvalpp); + HandlePragma((const char**)allTokens, tokenCount); + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + for (i = 0; i < tokenCount; ++i) { + free (allTokens[i]); + } + free (allTokens); + + return token; +} // CPPpragma + +#define GL2_VERSION_NUMBER 110 + +static int CPPversion(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (cpp->notAVersionToken == 1) + CPPShInfoLogMsg("#version must occur before any other statement in the program"); + + if(token=='\n'){ + DecLineNumber(); + CPPErrorToInfoLog("#version"); + IncLineNumber(); + return token; + } + if (token != CPP_INTCONSTANT) + CPPErrorToInfoLog("#version"); + + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + //SetVersionNumber(yylvalpp->sc_int); + + if (yylvalpp->sc_int != GL2_VERSION_NUMBER) + CPPShInfoLogMsg("Version number not supported by GL2"); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#version"); + } + return token; +} // CPPversion + +static int CPPextension(yystypepp * yylvalpp) +{ + + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + char extensionName[80]; + + if(token=='\n'){ + DecLineNumber(); + CPPShInfoLogMsg("extension name not specified"); + IncLineNumber(); + return token; + } + + if (token != CPP_IDENTIFIER) + CPPErrorToInfoLog("#extension"); + + strcpy(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != ':') { + CPPShInfoLogMsg("':' missing after extension name"); + return token; + } + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != CPP_IDENTIFIER) { + CPPShInfoLogMsg("behavior for extension not specified"); + return token; + } + + updateExtensionBehavior(extensionName, GetAtomString(atable, yylvalpp->sc_ident)); + + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '\n'){ + return token; + } + else{ + CPPErrorToInfoLog("#extension"); + } + return token; +} // CPPextension + +int readCPPline(yystypepp * yylvalpp) +{ + int token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + const char *message; + int isVersion = 0; + + if (token == CPP_IDENTIFIER) { + if (yylvalpp->sc_ident == defineAtom) { + token = CPPdefine(yylvalpp); + } else if (yylvalpp->sc_ident == elseAtom) { + if(ChkCorrectElseNesting()){ + if (!cpp->ifdepth ){ + CPPErrorToInfoLog("#else mismatch"); + cpp->CompileError=1; + } + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '\n') { + CPPWarningToInfoLog("unexpected tokens following #else preprocessor directive - expected a newline"); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + token = CPPelse(0, yylvalpp); + }else{ + CPPErrorToInfoLog("#else after a #else"); + cpp->ifdepth=0; + cpp->notAVersionToken = 1; + return 0; + } + } else if (yylvalpp->sc_ident == elifAtom) { + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#elif mismatch"); + cpp->CompileError=1; + } + // this token is really a dont care, but we still need to eat the tokens + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + while (token != '\n') + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + token = CPPelse(0, yylvalpp); + } else if (yylvalpp->sc_ident == endifAtom) { + cpp->elsedepth[cpp->elsetracker]=0; + --cpp->elsetracker; + if (!cpp->ifdepth){ + CPPErrorToInfoLog("#endif mismatch"); + cpp->CompileError=1; + } + else + --cpp->ifdepth; + } else if (yylvalpp->sc_ident == ifAtom) { + token = CPPif(yylvalpp); + } else if (yylvalpp->sc_ident == ifdefAtom) { + token = CPPifdef(1, yylvalpp); + } else if (yylvalpp->sc_ident == ifndefAtom) { + token = CPPifdef(0, yylvalpp); + } else if (yylvalpp->sc_ident == lineAtom) { + token = CPPline(yylvalpp); + } else if (yylvalpp->sc_ident == pragmaAtom) { + token = CPPpragma(yylvalpp); + } else if (yylvalpp->sc_ident == undefAtom) { + token = CPPundef(yylvalpp); + } else if (yylvalpp->sc_ident == errorAtom) { + token = CPPerror(yylvalpp); + } else if (yylvalpp->sc_ident == versionAtom) { + token = CPPversion(yylvalpp); + isVersion = 1; + } else if (yylvalpp->sc_ident == extensionAtom) { + token = CPPextension(yylvalpp); + } else { + StoreStr("Invalid Directive"); + StoreStr(GetStringOfAtom(atable,yylvalpp->sc_ident)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + } + while (token != '\n' && token != 0 && token != EOF) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + + cpp->notAVersionToken = !isVersion; + + return token; +} // readCPPline + +void FreeMacro(MacroSymbol *s) { + DeleteTokenStream(s->body); +} + +static int eof_scan(InputSrc *in, yystypepp * yylvalpp) { return -1; } +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) { } + +static void PushEofSrc() { + InputSrc *in = malloc(sizeof(InputSrc)); + memset(in, 0, sizeof(InputSrc)); + in->scan = eof_scan; + in->getch = eof_scan; + in->ungetch = noop; + in->prev = cpp->currentInput; + cpp->currentInput = in; +} + +static void PopEofSrc() { + if (cpp->currentInput->scan == eof_scan) { + InputSrc *in = cpp->currentInput; + cpp->currentInput = in->prev; + free(in); + } +} + +static TokenStream *PrescanMacroArg(TokenStream *a, yystypepp * yylvalpp) { + int token; + TokenStream *n; + RewindTokenStream(a); + do { + token = ReadToken(a, yylvalpp); + if (token == CPP_IDENTIFIER && LookUpSymbol(macros, yylvalpp->sc_ident)) + break; + } while (token > 0); + if (token <= 0) return a; + n = NewTokenStream("macro arg", 0); + PushEofSrc(); + ReadFromTokenStream(a, 0, 0); + while ((token = cpp->currentInput->scan(cpp->currentInput, yylvalpp)) > 0) { + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp->sc_ident, yylvalpp)) + continue; + RecordToken(n, token, yylvalpp); + } + PopEofSrc(); + DeleteTokenStream(a); + return n; +} // PrescanMacroArg + +typedef struct MacroInputSrc { + InputSrc base; + MacroSymbol *mac; + TokenStream **args; +} MacroInputSrc; + +/* macro_scan --- +** return the next token for a macro expanion, handling macro args +*/ +static int macro_scan(MacroInputSrc *in, yystypepp * yylvalpp) { + int i; + int token = ReadToken(in->mac->body, yylvalpp); + if (token == CPP_IDENTIFIER) { + for (i = in->mac->argc-1; i>=0; i--) + if (in->mac->args[i] == yylvalpp->sc_ident) break; + if (i >= 0) { + ReadFromTokenStream(in->args[i], yylvalpp->sc_ident, 0); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); + } + } + if (token > 0) return token; + in->mac->busy = 0; + cpp->currentInput = in->base.prev; + if (in->args) { + for (i=in->mac->argc-1; i>=0; i--) + DeleteTokenStream(in->args[i]); + free(in->args); + } + free(in); + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} // macro_scan + +/* MacroExpand +** check an identifier (atom) to see if it a macro that should be expanded. +** If it is, push an InputSrc that will produce the appropriate expansion +** and return TRUE. If not, return FALSE. +*/ + +int MacroExpand(int atom, yystypepp * yylvalpp) +{ + Symbol *sym = LookUpSymbol(macros, atom); + MacroInputSrc *in; + int i,j, token, depth=0; + const char *message; + if (atom == __LINE__Atom) { + yylvalpp->sc_int = GetLineNumber(); + sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __FILE__Atom) { + yylvalpp->sc_int = GetStringNumber(); + sprintf(yylvalpp->symbol_name,"%d",yylvalpp->sc_int); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (atom == __VERSION__Atom) { + strcpy(yylvalpp->symbol_name,"100"); + yylvalpp->sc_int = atoi(yylvalpp->symbol_name); + UngetToken(CPP_INTCONSTANT, yylvalpp); + return 1; + } + if (!sym || sym->details.mac.undef) return 0; + if (sym->details.mac.busy) return 0; // no recursive expansions + in = malloc(sizeof(*in)); + memset(in, 0, sizeof(*in)); + in->base.scan = (void *)macro_scan; + in->base.line = cpp->currentInput->line; + in->base.name = cpp->currentInput->name; + in->mac = &sym->details.mac; + if (sym->details.mac.args) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token != '(') { + UngetToken(token, yylvalpp); + yylvalpp->sc_ident = atom; + return 0; + } + in->args = malloc(in->mac->argc * sizeof(TokenStream *)); + for (i=0; imac->argc; i++) + in->args[i] = NewTokenStream("macro arg", 0); + i=0;j=0; + do{ + depth = 0; + while(1) { + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + if((in->mac->argc==0) && (token!=')')) break; + if (depth == 0 && (token == ',' || token == ')')) break; + if (token == '(') depth++; + if (token == ')') depth--; + RecordToken(in->args[i], token, yylvalpp); + j=1; + } + if (token == ')') { + if((in->mac->argc==1) &&j==0) + break; + i++; + break; + } + i++; + }while(i < in->mac->argc); + + if (i < in->mac->argc) { + StoreStr("Too few args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } else if (token != ')') { + depth=0; + while (token >= 0 && (depth > 0 || token != ')')) { + if (token == ')') depth--; + token = cpp->currentInput->scan(cpp->currentInput, yylvalpp); + if (token == '(') depth++; + } + + if (token <= 0) { + StoreStr("EOF in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + return 1; + } + StoreStr("Too many args in Macro "); + StoreStr(GetStringOfAtom(atable,atom)); + message=GetStrfromTStr(); + CPPShInfoLogMsg(message); + ResetTString(); + } + for (i=0; imac->argc; i++) { + in->args[i] = PrescanMacroArg(in->args[i], yylvalpp); + } + } +#if 0 + printf(" <%s:%d>found macro %s\n", GetAtomString(atable, loc.file), + loc.line, GetAtomString(atable, atom)); + for (i=0; imac->argc; i++) { + printf("\targ %s = '", GetAtomString(atable, in->mac->args[i])); + DumpTokenStream(stdout, in->args[i]); + printf("'\n"); + } +#endif + /*retain the input source*/ + in->base.prev = cpp->currentInput; + sym->details.mac.busy = 1; + RewindTokenStream(sym->details.mac.body); + cpp->currentInput = &in->base; + return 1; +} // MacroExpand + +int ChkCorrectElseNesting(void) +{ + if(cpp->elsedepth[cpp->elsetracker]==0){ + cpp->elsedepth[cpp->elsetracker]=1; + return 1; + } + return 0; +} + + diff --git a/Compiler/Preprocessor/cpp.h b/Compiler/Preprocessor/cpp.h new file mode 100644 index 000000000..85abbb5dd --- /dev/null +++ b/Compiler/Preprocessor/cpp.h @@ -0,0 +1,91 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cpp.h +// + +#if !defined(__CPP_H) +#define __CPP_H 1 + +#include "parser.h" +#include "tokens.h" + +int InitCPP(void); +int FinalCPP(void); +int readCPPline(yystypepp * yylvalpp); +int MacroExpand(int atom, yystypepp * yylvalpp); +int ChkCorrectElseNesting(void); + +typedef struct MacroSymbol { + int argc; + int *args; + TokenStream *body; + unsigned busy:1; + unsigned undef:1; +} MacroSymbol; + +void FreeMacro(MacroSymbol *); +int PredefineMacro(char *); + +void CPPDebugLogMsg(const char *msg); // Prints information into debug log +void CPPShInfoLogMsg(const char*); // Store cpp Err Msg into Sh.Info.Log +void CPPWarningToInfoLog(const char *msg); // Prints warning messages into info log +void HandlePragma(const char**, int numTokens); // #pragma directive container. +void ResetTString(void); // #error Message as TString. +void CPPErrorToInfoLog(char*); // Stick all cpp errors into Sh.Info.log . +void StoreStr(char*); // Store the TString in Parse Context. +void SetLineNumber(int); // Set line number. +void SetStringNumber(int); // Set string number. +int GetLineNumber(void); // Get the current String Number. +int GetStringNumber(void); // Get the current String Number. +const char* GetStrfromTStr(void); // Convert TString to String. +void updateExtensionBehavior(const char* extName, const char* behavior); +int FreeCPP(void); + +#endif // !(defined(__CPP_H) diff --git a/Compiler/Preprocessor/cppstruct.c b/Compiler/Preprocessor/cppstruct.c new file mode 100644 index 000000000..5144b6cc0 --- /dev/null +++ b/Compiler/Preprocessor/cppstruct.c @@ -0,0 +1,157 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// cppstruct.c +// + +#include +#include + +#include "slglobals.h" + +CPPStruct *cpp = NULL; +static int refCount = 0; + +int InitPreprocessor(void); +int ResetPreprocessor(void); +int FreeCPPStruct(void); +int FinalizePreprocessor(void); + +/* + * InitCPPStruct() - Initilaize the CPP structure. + * + */ + +int InitCPPStruct(void) +{ + int len; + char *p; + + cpp = (CPPStruct *) malloc(sizeof(CPPStruct)); + if (cpp == NULL) + return 0; + + refCount++; + + // Initialize public members: + cpp->pLastSourceLoc = &cpp->lastSourceLoc; + + p = (char *) &cpp->options; + len = sizeof(cpp->options); + while (--len >= 0) + p[len] = 0; + + ResetPreprocessor(); + return 1; +} // InitCPPStruct + +int ResetPreprocessor(void) +{ + // Initialize private members: + + cpp->lastSourceLoc.file = 0; + cpp->lastSourceLoc.line = 0; + cpp->pC=0; + cpp->CompileError=0; + cpp->ifdepth=0; + for(cpp->elsetracker=0; cpp->elsetracker<64; cpp->elsetracker++) + cpp->elsedepth[cpp->elsetracker]=0; + cpp->elsetracker=0; + cpp->tokensBeforeEOF = 0; + return 1; +} + +//Intializing the Preprocessor. + +int InitPreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeCPPStruct(); + InitCPPStruct(); + cpp->options.Quiet = 1; + cpp->options.profileString = "generic"; + if (!InitAtomTable(atable, 0)) + return 1; + if (!InitScanner(cpp)) + return 1; + # endif + return 0; +} + +//FreeCPPStruct() - Free the CPP structure. + +int FreeCPPStruct(void) +{ + if (refCount) + { + free(cpp); + refCount--; + } + + return 1; +} + +//Finalizing the Preprocessor. + +int FinalizePreprocessor(void) +{ + # define CPP_STUFF true + # ifdef CPP_STUFF + FreeAtomTable(atable); + FreeCPPStruct(); + FreeScanner(); + # endif + return 0; +} + + +/////////////////////////////////////////////////////////////////////////////////////////////// +////////////////////////////////////// End of cppstruct.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Compiler/Preprocessor/memory.c b/Compiler/Preprocessor/memory.c new file mode 100644 index 000000000..1a70231b9 --- /dev/null +++ b/Compiler/Preprocessor/memory.c @@ -0,0 +1,163 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#include +#include +#include + +#ifdef __STDC99__ +#include +#elif defined (_WIN64) +typedef unsigned __int64 uintptr_t; +#else +typedef unsigned int uintptr_t; +#endif + +#include "memory.h" + +// default alignment and chunksize, if called with 0 arguments +#define CHUNKSIZE (64*1024) +#define ALIGN 8 + +// we need to call the `real' malloc and free, not our replacements +#undef malloc +#undef free + +struct chunk { + struct chunk *next; +}; + +struct cleanup { + struct cleanup *next; + void (*fn)(void *); + void *arg; +}; + +struct MemoryPool_rec { + struct chunk *next; + uintptr_t free, end; + size_t chunksize; + uintptr_t alignmask; + struct cleanup *cleanup; +}; + +MemoryPool *mem_CreatePool(size_t chunksize, unsigned int align) +{ + MemoryPool *pool; + + if (align == 0) align = ALIGN; + if (chunksize == 0) chunksize = CHUNKSIZE; + if (align & (align-1)) return 0; + if (chunksize < sizeof(MemoryPool)) return 0; + if (chunksize & (align-1)) return 0; + if (!(pool = malloc(chunksize))) return 0; + pool->next = 0; + pool->chunksize = chunksize; + pool->alignmask = (uintptr_t)(align)-1; + pool->free = ((uintptr_t)(pool + 1) + pool->alignmask) & ~pool->alignmask; + pool->end = (uintptr_t)pool + chunksize; + pool->cleanup = 0; + return pool; +} + +void mem_FreePool(MemoryPool *pool) +{ + struct cleanup *cleanup; + struct chunk *p, *next; + + for (cleanup = pool->cleanup; cleanup; cleanup = cleanup->next) { + cleanup->fn(cleanup->arg); + } + for (p = (struct chunk *)pool; p; p = next) { + next = p->next; + free(p); + } +} + +void *mem_Alloc(MemoryPool *pool, size_t size) +{ + struct chunk *ch; + void *rv = (void *)pool->free; + size = (size + pool->alignmask) & ~pool->alignmask; + if (size <= 0) size = pool->alignmask; + pool->free += size; + if (pool->free > pool->end || pool->free < (uintptr_t)rv) { + size_t minreq = (size + sizeof(struct chunk) + pool->alignmask) + & ~pool->alignmask; + pool->free = (uintptr_t)rv; + if (minreq >= pool->chunksize) { + // request size is too big for the chunksize, so allocate it as + // a single chunk of the right size + ch = malloc(minreq); + if (!ch) return 0; + } else { + ch = malloc(pool->chunksize); + if (!ch) return 0; + pool->free = (uintptr_t)ch + minreq; + pool->end = (uintptr_t)ch + pool->chunksize; + } + ch->next = pool->next; + pool->next = ch; + rv = (void *)(((uintptr_t)(ch+1) + pool->alignmask) & ~pool->alignmask); + } + return rv; +} + +int mem_AddCleanup(MemoryPool *pool, void (*fn)(void *), void *arg) { + struct cleanup *cleanup; + + pool->free = (pool->free + sizeof(void *) - 1) & ~(sizeof(void *)-1); + cleanup = mem_Alloc(pool, sizeof(struct cleanup)); + if (!cleanup) return -1; + cleanup->next = pool->cleanup; + cleanup->fn = fn; + cleanup->arg = arg; + pool->cleanup = cleanup; + return 0; +} diff --git a/Compiler/Preprocessor/memory.h b/Compiler/Preprocessor/memory.h new file mode 100644 index 000000000..3da798937 --- /dev/null +++ b/Compiler/Preprocessor/memory.h @@ -0,0 +1,61 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +#ifndef __MEMORY_H +#define __MEMORY_H + +typedef struct MemoryPool_rec MemoryPool; + +extern MemoryPool *mem_CreatePool(size_t chunksize, unsigned align); +extern void mem_FreePool(MemoryPool *); +extern void *mem_Alloc(MemoryPool *p, size_t size); +extern void *mem_Realloc(MemoryPool *p, void *old, size_t oldsize, size_t newsize); +extern int mem_AddCleanup(MemoryPool *p, void (*fn)(void *), void *arg); + +#endif /* __MEMORY_H */ diff --git a/Compiler/Preprocessor/parser.h b/Compiler/Preprocessor/parser.h new file mode 100644 index 000000000..91a620080 --- /dev/null +++ b/Compiler/Preprocessor/parser.h @@ -0,0 +1,98 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +#ifndef BISON_PARSER_H +# define BISON_PARSER_H + +#ifndef yystypepp +typedef struct { + int sc_int; + float sc_fval; + int sc_ident; + char symbol_name[MAX_SYMBOL_NAME_LEN+1]; +} yystypepp; + +# define YYSTYPE_IS_TRIVIAL 1 +#endif +# define CPP_AND_OP 257 +# define CPP_SUB_ASSIGN 259 +# define CPP_MOD_ASSIGN 260 +# define CPP_ADD_ASSIGN 261 +# define CPP_DIV_ASSIGN 262 +# define CPP_MUL_ASSIGN 263 +# define CPP_EQ_OP 264 +# define CPP_XOR_OP 265 +# define ERROR_SY 266 +# define CPP_FLOATCONSTANT 267 +# define CPP_GE_OP 268 +# define CPP_RIGHT_OP 269 +# define CPP_IDENTIFIER 270 +# define CPP_INTCONSTANT 271 +# define CPP_LE_OP 272 +# define CPP_LEFT_OP 273 +# define CPP_DEC_OP 274 +# define CPP_NE_OP 275 +# define CPP_OR_OP 276 +# define CPP_INC_OP 277 +# define CPP_STRCONSTANT 278 +# define CPP_TYPEIDENTIFIER 279 + +# define FIRST_USER_TOKEN_SY 289 + +# define CPP_RIGHT_ASSIGN 280 +# define CPP_LEFT_ASSIGN 281 +# define CPP_AND_ASSIGN 282 +# define CPP_OR_ASSIGN 283 +# define CPP_XOR_ASSIGN 284 +# define CPP_LEFT_BRACKET 285 +# define CPP_RIGHT_BRACKET 286 +# define CPP_LEFT_BRACE 287 +# define CPP_RIGHT_BRACE 288 + +#endif /* not BISON_PARSER_H */ diff --git a/Compiler/Preprocessor/preprocess.h b/Compiler/Preprocessor/preprocess.h new file mode 100644 index 000000000..323cd1e1f --- /dev/null +++ b/Compiler/Preprocessor/preprocess.h @@ -0,0 +1,56 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ + +# include "slglobals.h" +extern CPPStruct *cpp; +int InitCPPStruct(void); +int InitScanner(CPPStruct *cpp); +int InitAtomTable(AtomTable *atable, int htsize); +int ScanFromString(char *s); +char* GetStringOfAtom(AtomTable *atable, int atom); diff --git a/Compiler/Preprocessor/scanner.c b/Compiler/Preprocessor/scanner.c new file mode 100644 index 000000000..fcdf75130 --- /dev/null +++ b/Compiler/Preprocessor/scanner.c @@ -0,0 +1,766 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.c +// + +#include +#include +#include +#include + +#if 0 + #include + #else + #define isinff(x) (((*(int *)&(x) & 0x7f800000L)==0x7f800000L) && \ + ((*(int *)&(x) & 0x007fffffL)==0000000000L)) +#endif + +#include "slglobals.h" + + +typedef struct StringInputSrc { + InputSrc base; + char *p; +} StringInputSrc; + +static int eof_scan(InputSrc *is, yystypepp * yylvalpp) +{ + return EOF; +} // eof_scan + +static void noop(InputSrc *in, int ch, yystypepp * yylvalpp) {} + +static InputSrc eof_inputsrc = { 0, &eof_scan, &eof_scan, &noop }; + +static int byte_scan(InputSrc *, yystypepp * yylvalpp); + +#define EOL_SY '\n' + +#if defined(_WIN32) + #define DBG_BREAKPOINT() __asm int 3 + #elif defined(_M_AMD64) + #define DBG_BREAKPOINT() assert(!"Dbg_Breakpoint"); + #else + #define DBG_BREAKPOINT() + #endif + + #if defined(_WIN32) && !defined(_M_AMD64) + __int64 RDTSC ( void ) { + + __int64 v; + + __asm __emit 0x0f + __asm __emit 0x31 + __asm mov dword ptr v, eax + __asm mov dword ptr v+4, edx + + return v; + } +#endif + + +int InitScanner(CPPStruct *cpp) +{ + // Add various atoms needed by the CPP line scanner: + if (!InitCPP()) + return 0; + + cpp->mostRecentToken = 0; + cpp->tokenLoc = &cpp->ltokenLoc; + + cpp->ltokenLoc.file = 0; + cpp->ltokenLoc.line = 0; + + cpp->currentInput = &eof_inputsrc; + cpp->previous_token = '\n'; + cpp->notAVersionToken = 0; + + return 1; +} // InitScanner + +int FreeScanner(void) +{ + return (FreeCPP()); +} + +/* + * str_getch() + * takes care of reading from multiple strings. + * returns the next-char from the input stream. + * returns EOF when the complete shader is parsed. + */ +static int str_getch(StringInputSrc *in) +{ + for(;;){ + if (*in->p){ + if (*in->p == '\n') { + in->base.line++; + IncLineNumber(); + } + return *in->p++; + } + if(++(cpp->PaWhichStr) < cpp->PaArgc){ + free(in); + SetStringNumber(cpp->PaWhichStr); + SetLineNumber(1); + ScanFromString(cpp->PaArgv[cpp->PaWhichStr]); + in=(StringInputSrc*)cpp->currentInput; + continue; + } + else{ + cpp->currentInput = in->base.prev; + cpp->PaWhichStr=0; + free(in); + return EOF; + } + } +} // str_getch + +static void str_ungetch(StringInputSrc *in, int ch, yystypepp *type) { + if (in->p[-1] == ch)in->p--; + else { + *(in->p)='\0'; //this would take care of shifting to the previous string. + cpp->PaWhichStr--; + } + if (ch == '\n') { + in->base.line--; + DecLineNumber(); + } +} // str_ungetch + +int ScanFromString(char *s) +{ + + StringInputSrc *in = malloc(sizeof(StringInputSrc)); + memset(in, 0, sizeof(StringInputSrc)); + in->p = s; + in->base.line = 1; + in->base.scan = byte_scan; + in->base.getch = (int (*)(InputSrc *, yystypepp *))str_getch; + in->base.ungetch = (void (*)(InputSrc *, int, yystypepp *))str_ungetch; + in->base.prev = cpp->currentInput; + cpp->currentInput = &in->base; + + return 1; +} // ScanFromString; + + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Floating point constants: ///////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// +/* + * lBuildFloatValue() - Quick and dirty conversion to floating point. Since all + * we need is single precision this should be quite precise. + */ + +static float lBuildFloatValue(const char *str, int len, int exp) +{ + double val, expval, ten; + int ii, llen, absexp; + float rv; + + val = 0.0; + llen = len; + for (ii = 0; ii < len; ii++) + val = val*10.0 + (str[ii] - '0'); + if (exp != 0) { + absexp = exp > 0 ? exp : -exp; + expval = 1.0f; + ten = 10.0; + while (absexp) { + if (absexp & 1) + expval *= ten; + ten *= ten; + absexp >>= 1; + } + if (exp >= 0) { + val *= expval; + } else { + val /= expval; + } + } + rv = (float)val; + if (isinff(rv)) { + CPPErrorToInfoLog(" ERROR___FP_CONST_OVERFLOW"); + } + return rv; +} // lBuildFloatValue + + +/* + * lFloatConst() - Scan a floating point constant. Assumes that the scanner + * has seen at least one digit, followed by either a decimal '.' or the + * letter 'e'. + */ + +static int lFloatConst(char *str, int len, int ch, yystypepp * yylvalpp) +{ + int HasDecimal, declen, exp, ExpSign; + int str_len; + float lval; + + HasDecimal = 0; + declen = 0; + exp = 0; + + str_len=len; + if (ch == '.') { + str[len++]=ch; + HasDecimal = 1; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + while (ch >= '0' && ch <= '9') { + if (len < MAX_SYMBOL_NAME_LEN) { + declen++; + if (len > 0 || ch != '0') { + str[len] = ch; + len++;str_len++; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else { + CPPErrorToInfoLog("ERROR___FP_CONST_TOO_LONG"); + len = 1,str_len=1; + } + } + } + + // Exponent: + + if (ch == 'e' || ch == 'E') { + ExpSign = 1; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else if (ch == '-') { + ExpSign = -1; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + if (ch >= '0' && ch <= '9') { + while (ch >= '0' && ch <= '9') { + exp = exp*10 + ch - '0'; + str[len++]=ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } else { + CPPErrorToInfoLog("ERROR___ERROR_IN_EXPONENT"); + } + exp *= ExpSign; + } + + if (len == 0) { + lval = 0.0f; + strcpy(str,"0.0"); + } else { + str[len]='\0'; + lval = lBuildFloatValue(str, str_len, exp - declen); + } + // Suffix: + + yylvalpp->sc_fval = lval; + strcpy(yylvalpp->symbol_name,str); + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_FLOATCONSTANT; +} // lFloatConst + +/////////////////////////////////////////////////////////////////////////////////////////////// +///////////////////////////////////////// Normal Scanner ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +static int byte_scan(InputSrc *in, yystypepp * yylvalpp) +{ + char symbol_name[MAX_SYMBOL_NAME_LEN + 1]; + char string_val[MAX_STRING_LEN + 1]; + int AlreadyComplained; + int len, ch, ii, ival = 0; + + for (;;) { + yylvalpp->sc_int = 0; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + + while (ch == ' ' || ch == '\t' || ch == '\r') { + yylvalpp->sc_int = 1; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + + cpp->ltokenLoc.file = cpp->currentInput->name; + cpp->ltokenLoc.line = cpp->currentInput->line; + len = 0; + switch (ch) { + default: + return ch; // Single character token + case EOF: + return -1; + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': case '_': + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + do { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } else { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_'); + if (len >= MAX_SYMBOL_NAME_LEN) + len = MAX_SYMBOL_NAME_LEN - 1; + symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_ident = LookUpAddString(atable, symbol_name); + return CPP_IDENTIFIER; + break; + case '0': + yylvalpp->symbol_name[len++] = ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == 'x' || ch == 'X') { + yylvalpp->symbol_name[len++] = ch; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')) + { + AlreadyComplained = 0; + ival = 0; + do { + yylvalpp->symbol_name[len++] = ch; + if (ival <= 0x0fffffff) { + if (ch >= '0' && ch <= '9') { + ii = ch - '0'; + } else if (ch >= 'A' && ch <= 'F') { + ii = ch - 'A' + 10; + } else { + ii = ch - 'a' + 10; + } + ival = (ival << 4) | ii; + } else { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___HEX_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while ((ch >= '0' && ch <= '9') || + (ch >= 'A' && ch <= 'F') || + (ch >= 'a' && ch <= 'f')); + } else { + CPPErrorToInfoLog("ERROR___ERROR_IN_HEX_CONSTANT"); + } + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else if (ch >= '0' && ch <= '7') { // octal integer constants + AlreadyComplained = 0; + ival = 0; + do { + yylvalpp->symbol_name[len++] = ch; + if (ival <= 0x1fffffff) { + ii = ch - '0'; + ival = (ival << 3) | ii; + } else { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___OCT_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch >= '0' && ch <= '7'); + if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E') + return lFloatConst(yylvalpp->symbol_name, len, ch, yylvalpp); + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + yylvalpp->sc_int = ival; + return CPP_INTCONSTANT; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ch = '0'; + } + // Fall through... + case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + do { + if (len < MAX_SYMBOL_NAME_LEN) { + if (len > 0 || ch != '0') { + yylvalpp->symbol_name[len] = ch; + len++; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + } while (ch >= '0' && ch <= '9'); + if (ch == '.' || ch == 'e' || ch == 'f' || ch == 'h' || ch == 'x'|| ch == 'E') { + return lFloatConst(yylvalpp->symbol_name, len, ch, yylvalpp); + } else { + yylvalpp->symbol_name[len] = '\0'; + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + ival = 0; + AlreadyComplained = 0; + for (ii = 0; ii < len; ii++) { + ch = yylvalpp->symbol_name[ii] - '0'; + if ((ival > 214748364) || (ival == 214748364 && ch >= 8)) { + if (!AlreadyComplained) + CPPErrorToInfoLog("ERROR___INTEGER_CONST_OVERFLOW"); + AlreadyComplained = 1; + } + ival = ival*10 + ch; + } + yylvalpp->sc_int = ival; + if(ival==0) + strcpy(yylvalpp->symbol_name,"0"); + return CPP_INTCONSTANT; + } + break; + case '-': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '-') { + return CPP_DEC_OP; + } else if (ch == '=') { + return CPP_SUB_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '-'; + } + case '+': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '+') { + return CPP_INC_OP; + } else if (ch == '=') { + return CPP_ADD_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '+'; + } + case '*': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MUL_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '*'; + } + case '%': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_MOD_ASSIGN; + } else if (ch == '>'){ + return CPP_RIGHT_BRACE; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '%'; + } + case ':': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + return CPP_RIGHT_BRACKET; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return ':'; + } + case '^': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '^') { + return CPP_XOR_OP; + } else { + if (ch == '=') + return CPP_XOR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '^'; + } + } + + case '=': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_EQ_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '='; + } + case '!': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '=') { + return CPP_NE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '!'; + } + case '|': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '|') { + return CPP_OR_OP; + } else { + if (ch == '=') + return CPP_OR_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '|'; + } + } + case '&': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '&') { + return CPP_AND_OP; + } else { + if (ch == '=') + return CPP_AND_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '&'; + } + } + case '<': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '<') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_LEFT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_LEFT_OP; + } + } else { + if (ch == '=') { + return CPP_LE_OP; + } else { + if (ch == '%') + return CPP_LEFT_BRACE; + else if (ch == ':') + return CPP_LEFT_BRACKET; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '<'; + } + } + } + case '>': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '>') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if(ch == '=') + return CPP_RIGHT_ASSIGN; + else{ + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return CPP_RIGHT_OP; + } + } else { + if (ch == '=') { + return CPP_GE_OP; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '>'; + } + } + case '.': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch >= '0' && ch <= '9') { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return lFloatConst(yylvalpp->symbol_name, 0, '.', yylvalpp); + } else { + if (ch == '.') { + return -1; // Special EOF hack + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '.'; + } + } + case '/': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '/') { + do { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } while (ch != '\n' && ch != EOF); + if (ch == EOF) + return -1; + return '\n'; + } else if (ch == '*') { + int nlcount = 0; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + do { + while (ch != '*') { + if (ch == '\n') nlcount++; + if (ch == EOF) { + CPPErrorToInfoLog("ERROR___EOF_IN_COMMENT"); + return -1; + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == EOF) { + CPPErrorToInfoLog("ERROR___EOF_IN_COMMENT"); + return -1; + } + } while (ch != '/'); + if (nlcount) { + return '\n'; + } + // Go try it again... + } else if (ch == '=') { + return CPP_DIV_ASSIGN; + } else { + cpp->currentInput->ungetch(cpp->currentInput, ch, yylvalpp); + return '/'; + } + break; + case '"': + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + while (ch != '"' && ch != '\n' && ch != EOF) { + if (ch == '\\') { + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + if (ch == '\n' || ch == EOF) { + break; + } + } + if (len < MAX_STRING_LEN) { + string_val[len] = ch; + len++; + ch = cpp->currentInput->getch(cpp->currentInput, yylvalpp); + } + }; + string_val[len] = '\0'; + if (ch == '"') { + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + return CPP_STRCONSTANT; + } else { + CPPErrorToInfoLog("ERROR___CPP_EOL_IN_STRING"); + return ERROR_SY; + } + } + } +} // byte_scan + +int yylex_CPP(char* buf, int maxSize) +{ + yystypepp yylvalpp; + int token = '\n'; + + for(;;) { + + char* tokenString = 0; + token = cpp->currentInput->scan(cpp->currentInput, &yylvalpp); + if(check_EOF(token)) + return 0; + if (token == '#') { + if (cpp->previous_token == '\n'|| cpp->previous_token == 0) { + token = readCPPline(&yylvalpp); + if(check_EOF(token)) + return 0; + continue; + } else { + CPPErrorToInfoLog("preprocessor command must not be preceded by any other statement in that line"); + return 0; + } + } + cpp->previous_token = token; + // expand macros + if (token == CPP_IDENTIFIER && MacroExpand(yylvalpp.sc_ident, &yylvalpp)) { + cpp->notAVersionToken = 1; + continue; + } + + if (token == '\n') + continue; + + if (token == CPP_IDENTIFIER) { + cpp->notAVersionToken = 1; + tokenString = GetStringOfAtom(atable,yylvalpp.sc_ident); + } else if (token == CPP_FLOATCONSTANT||token == CPP_INTCONSTANT){ + cpp->notAVersionToken = 1; + tokenString = yylvalpp.symbol_name; + } else { + cpp->notAVersionToken = 1; + tokenString = GetStringOfAtom(atable,token); + } + + if (tokenString) { + if ((signed)strlen(tokenString) >= maxSize) { + cpp->tokensBeforeEOF = 1; + return maxSize; + } else if (strlen(tokenString) > 0) { + strcpy(buf, tokenString); + cpp->tokensBeforeEOF = 1; + return (int)strlen(tokenString); + } + + return 0; + } + } + + return 0; +} // yylex + +//Checks if the token just read is EOF or not. +int check_EOF(int token) +{ + if(token==-1){ + if(cpp->ifdepth >0){ + CPPErrorToInfoLog("#endif missing!! Compilation stopped"); + cpp->CompileError=1; + } + return 1; + } + return 0; +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of scanner.c ////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + diff --git a/Compiler/Preprocessor/scanner.h b/Compiler/Preprocessor/scanner.h new file mode 100644 index 000000000..288a0902d --- /dev/null +++ b/Compiler/Preprocessor/scanner.h @@ -0,0 +1,90 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// scanner.h +// + +#if !defined(__SCANNER_H) +#define __SCANNER_H 1 + +#define MAX_SYMBOL_NAME_LEN 128 +#define MAX_STRING_LEN 512 + +#include "parser.h" + +// Not really atom table stuff but needed first... + +typedef struct SourceLoc_Rec { + unsigned short file, line; +} SourceLoc; + +int yyparse (void); + +int yylex_CPP(char* buf, int maxSize); + +typedef struct InputSrc { + struct InputSrc *prev; + int (*scan)(struct InputSrc *, yystypepp *); + int (*getch)(struct InputSrc *, yystypepp *); + void (*ungetch)(struct InputSrc *, int, yystypepp *); + int name; /* atom */ + int line; +} InputSrc; + +int InitScanner(CPPStruct *cpp); // Intialise the cpp scanner. +int ScanFromString(char *); // Start scanning the input from the string mentioned. +int check_EOF(int); // check if we hit a EOF abruptly +void CPPErrorToInfoLog(char *); // sticking the msg,line into the Shader's.Info.log +void SetLineNumber(int); +void SetStringNumber(int); +void IncLineNumber(void); +void DecLineNumber(void); +int FreeScanner(void); // Free the cpp scanner +#endif // !(defined(__SCANNER_H) + diff --git a/Compiler/Preprocessor/slglobals.h b/Compiler/Preprocessor/slglobals.h new file mode 100644 index 000000000..852502fd2 --- /dev/null +++ b/Compiler/Preprocessor/slglobals.h @@ -0,0 +1,87 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// slglobals.h +// + +#if !defined(__SLGLOBALS_H) +#define __SLGLOBALS_H 1 + +typedef struct CPPStruct_Rec CPPStruct; + +extern CPPStruct *cpp; + +#undef CPPC_DEBUG_THE_COMPILER +#if defined(_DEBUG) +#define CPPC_DEBUG_THE_COMPILER 1 +#endif + +#undef CPPC_ENABLE_TOOLS +#define CPPC_ENABLE_TOOLS 1 + +#include "memory.h" +#include "atom.h" +#include "scanner.h" +#include "cpp.h" +#include "tokens.h" +#include "symbols.h" +#include "compile.h" +#if !defined(NO_PARSER) +#include "parser.h" +#endif + +#if !defined(NULL) +#define NULL 0 +#endif + +#endif // !(defined(__SLGLOBALS_H) + + + + diff --git a/Compiler/Preprocessor/symbols.c b/Compiler/Preprocessor/symbols.c new file mode 100644 index 000000000..d97bae00d --- /dev/null +++ b/Compiler/Preprocessor/symbols.c @@ -0,0 +1,290 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.c +// + +#include +#include +#include +#include + +#include "slglobals.h" + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////// Symbol Table Variables: /////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +Scope *ScopeList = NULL; +Scope *CurrentScope = NULL; +Scope *GlobalScope = NULL; + +static void unlinkScope(void *_scope) { + Scope *scope = _scope; + + if (scope->next) + scope->next->prev = scope->prev; + if (scope->prev) + scope->prev->next = scope->next; + else + ScopeList = scope->next; +} + +/* + * NewScope() + * + */ +Scope *NewScopeInPool(MemoryPool *pool) +{ + Scope *lScope; + + lScope = mem_Alloc(pool, sizeof(Scope)); + lScope->pool = pool; + lScope->parent = NULL; + lScope->funScope = NULL; + lScope->symbols = NULL; + + lScope->level = 0; + + lScope->programs = NULL; + if ((lScope->next = ScopeList)) + ScopeList->prev = lScope; + lScope->prev = 0; + ScopeList = lScope; + mem_AddCleanup(pool, unlinkScope, lScope); + return lScope; +} // NewScope + +/* + * PushScope() + * + */ + +void PushScope(Scope *fScope) +{ + Scope *lScope; + + if (CurrentScope) { + fScope->level = CurrentScope->level + 1; + if (fScope->level == 1) { + if (!GlobalScope) { + /* HACK - CTD -- if GlobalScope==NULL and level==1, we're + * defining a function in the superglobal scope. Things + * will break if we leave the level as 1, so we arbitrarily + * set it to 2 */ + fScope->level = 2; + } + } + if (fScope->level >= 2) { + lScope = fScope; + while (lScope->level > 2) + lScope = lScope->next; + fScope->funScope = lScope; + } + } else { + fScope->level = 0; + } + fScope->parent = CurrentScope; + CurrentScope = fScope; +} // PushScope + +/* + * PopScope() + * + */ + +Scope *PopScope(void) +{ + Scope *lScope; + + lScope = CurrentScope; + if (CurrentScope) + CurrentScope = CurrentScope->parent; + return lScope; +} // PopScope + +/* + * NewSymbol() - Allocate a new symbol node; + * + */ + +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind) +{ + Symbol *lSymb; + char *pch; + int ii; + + lSymb = (Symbol *) mem_Alloc(fScope->pool, sizeof(Symbol)); + lSymb->left = NULL; + lSymb->right = NULL; + lSymb->next = NULL; + lSymb->name = name; + lSymb->loc = *loc; + lSymb->kind = kind; + + // Clear union area: + + pch = (char *) &lSymb->details; + for (ii = 0; ii < sizeof(lSymb->details); ii++) + *pch++ = 0; + return lSymb; +} // NewSymbol + +/* + * lAddToTree() - Using a binary tree is not a good idea for basic atom values because they + * are generated in order. We'll fix this later (by reversing the bit pattern). + */ + +static void lAddToTree(Symbol **fSymbols, Symbol *fSymb) +{ + Symbol *lSymb; + int lrev, frev; + + lSymb = *fSymbols; + if (lSymb) { + frev = GetReversedAtom(atable, fSymb->name); + while (lSymb) { + lrev = GetReversedAtom(atable, lSymb->name); + if (lrev == frev) { + CPPErrorToInfoLog("GetAtomString(atable, fSymb->name)"); + break; + } else { + if (lrev > frev) { + if (lSymb->left) { + lSymb = lSymb->left; + } else { + lSymb->left = fSymb; + break; + } + } else { + if (lSymb->right) { + lSymb = lSymb->right; + } else { + lSymb->right = fSymb; + break; + } + } + } + } + } else { + *fSymbols = fSymb; + } +} // lAddToTree + + +/* + * AddSymbol() - Add a variable, type, or function name to a scope. + * + */ + +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + lSymb = NewSymbol(loc, fScope, atom, kind); + lAddToTree(&fScope->symbols, lSymb); + return lSymb; +} // AddSymbol + + +/*********************************************************************************************/ +/************************************ Symbol Semantic Functions ******************************/ +/*********************************************************************************************/ + +/* + * LookUpLocalSymbol() + * + */ + +Symbol *LookUpLocalSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + int rname, ratom; + + ratom = GetReversedAtom(atable, atom); + if (!fScope) + fScope = CurrentScope; + lSymb = fScope->symbols; + while (lSymb) { + rname = GetReversedAtom(atable, lSymb->name); + if (rname == ratom) { + return lSymb; + } else { + if (rname > ratom) { + lSymb = lSymb->left; + } else { + lSymb = lSymb->right; + } + } + } + return NULL; +} // LookUpLocalSymbol + +/* + * LookUpSymbol() + * + */ + +Symbol *LookUpSymbol(Scope *fScope, int atom) +{ + Symbol *lSymb; + + if (!fScope) + fScope = CurrentScope; + while (fScope) { + lSymb = LookUpLocalSymbol(fScope, atom); + if (lSymb) + return lSymb; + fScope = fScope->parent; + } + return NULL; +} // LookUpSymbol + diff --git a/Compiler/Preprocessor/symbols.h b/Compiler/Preprocessor/symbols.h new file mode 100644 index 000000000..a94adbf5e --- /dev/null +++ b/Compiler/Preprocessor/symbols.h @@ -0,0 +1,117 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// symbols.h +// + +#if !defined(__SYMBOLS_H) +#define __SYMBOLS_H 1 + +#include "memory.h" + +typedef enum symbolkind { + MACRO_S +} symbolkind; + +// Typedefs for things defined here in "symbols.h": + +typedef struct Scope_Rec Scope; +typedef struct Symbol_Rec Symbol; + +typedef struct SymbolList_Rec { + struct SymbolList_Rec *next; + Symbol *symb; +} SymbolList; + +struct Scope_Rec { + Scope *next, *prev; // doubly-linked list of all scopes + Scope *parent; + Scope *funScope; // Points to base scope of enclosing function + MemoryPool *pool; // pool used for allocation in this scope + Symbol *symbols; + + int level; // 0 = super globals, 1 = globals, etc. + + // Only used at global scope (level 1): + SymbolList *programs; // List of programs for this compilation. +}; + + +// Symbol table is a simple binary tree. + +#include "cpp.h" // to get MacroSymbol def + +struct Symbol_Rec { + Symbol *left, *right; + Symbol *next; + int name; // Name atom + SourceLoc loc; + symbolkind kind; + union { + MacroSymbol mac; + } details; +}; + +extern Scope *CurrentScope; +extern Scope *GlobalScope; +extern Scope *ScopeList; + +Scope *NewScopeInPool(MemoryPool *); +#define NewScope() NewScopeInPool(CurrentScope->pool) +void PushScope(Scope *fScope); +Scope *PopScope(void); +Symbol *NewSymbol(SourceLoc *loc, Scope *fScope, int name, symbolkind kind); +Symbol *AddSymbol(SourceLoc *loc, Scope *fScope, int atom, symbolkind kind); +Symbol *LookUpLocalSymbol(Scope *fScope, int atom); +Symbol *LookUpSymbol(Scope *fScope, int atom); +void CPPErrorToInfoLog(char *); + + +#endif // !defined(__SYMBOLS_H) + diff --git a/Compiler/Preprocessor/tokens.c b/Compiler/Preprocessor/tokens.c new file mode 100644 index 000000000..b508f032d --- /dev/null +++ b/Compiler/Preprocessor/tokens.c @@ -0,0 +1,444 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.c +// + +#include +#include +#include +#include +#include + +#include "slglobals.h" + +/////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////// Preprocessor and Token Recorder and Playback: //////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// + +/* + * idstr() + * Copy a string to a malloc'ed block and convert it into something suitable + * for an ID + * + */ + +static char *idstr(const char *fstr, MemoryPool *pool) +{ + size_t len; + char *str, *t; + const char *f; + + len = strlen(fstr); + if (!pool) + str = (char *) malloc(len + 1); + else + str = (char *) mem_Alloc(pool, len + 1); + + for (f=fstr, t=str; *f; f++) { + if (isalnum(*f)) *t++ = *f; + else if (*f == '.' || *f == '/') *t++ = '_'; + } + *t = 0; + return str; +} // idstr + + +/* + * lNewBlock() + * + */ + +static TokenBlock *lNewBlock(TokenStream *fTok, MemoryPool *pool) +{ + TokenBlock *lBlock; + + if (!pool) + lBlock = (TokenBlock *) malloc(sizeof(TokenBlock) + 256); + else + lBlock = (TokenBlock *) mem_Alloc(pool, sizeof(TokenBlock) + 256); + lBlock->count = 0; + lBlock->current = 0; + lBlock->data = (unsigned char *) lBlock + sizeof(TokenBlock); + lBlock->max = 256; + lBlock->next = NULL; + if (fTok->head) { + fTok->current->next = lBlock; + } else { + fTok->head = lBlock; + } + fTok->current = lBlock; + return lBlock; +} // lNewBlock + +/* + * lAddByte() + * + */ + +static void lAddByte(TokenStream *fTok, unsigned char fVal) +{ + TokenBlock *lBlock; + lBlock = fTok->current; + if (lBlock->count >= lBlock->max) + lBlock = lNewBlock(fTok, 0); + lBlock->data[lBlock->count++] = fVal; +} // lAddByte + + + +/* + * lReadByte() - Get the next byte from a stream. + * + */ + +static int lReadByte(TokenStream *pTok) +{ + TokenBlock *lBlock; + int lval = -1; + + lBlock = pTok->current; + if (lBlock) { + if (lBlock->current >= lBlock->count) { + lBlock = lBlock->next; + if (lBlock) + lBlock->current = 0; + pTok->current = lBlock; + } + if (lBlock) + lval = lBlock->data[lBlock->current++]; + } + return lval; +} // lReadByte + +/////////////////////////////////////// Global Functions:////////////////////////////////////// + +/* + * NewTokenStream() + * + */ + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool) +{ + TokenStream *pTok; + + if (!pool) + pTok = (TokenStream *) malloc(sizeof(TokenStream)); + else + pTok = (TokenStream*)mem_Alloc(pool, sizeof(TokenStream)); + pTok->next = NULL; + pTok->name = idstr(name, pool); + pTok->head = NULL; + pTok->current = NULL; + lNewBlock(pTok, pool); + return pTok; +} // NewTokenStream + +/* + * DeleteTokenStream() + * + */ + +void DeleteTokenStream(TokenStream *pTok) +{ + TokenBlock *pBlock, *nBlock; + + if (pTok) { + pBlock = pTok->head; + while (pBlock) { + nBlock = pBlock->next; + free(pBlock); + pBlock = nBlock; + } + if (pTok->name) + free(pTok->name); + free(pTok); + } +} // DeleteTokenStream + +/* + * RecordToken() - Add a token to the end of a list for later playback or printout. + * + */ + +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp) +{ + const char *s; + unsigned char *str=NULL; + + if (token > 256) + lAddByte(pTok, (unsigned char)((token & 0x7f) + 0x80)); + else + lAddByte(pTok, (unsigned char)(token & 0x7f)); + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + case CPP_STRCONSTANT: + s = GetAtomString(atable, yylvalpp->sc_ident); + while (*s) + lAddByte(pTok, (unsigned char) *s++); + lAddByte(pTok, 0); + break; + case CPP_FLOATCONSTANT: + case CPP_INTCONSTANT: + str=yylvalpp->symbol_name; + while (*str){ + lAddByte(pTok,(unsigned char) *str); + *str++; + } + lAddByte(pTok, 0); + break; + case '(': + lAddByte(pTok, (unsigned char)(yylvalpp->sc_int ? 1 : 0)); + default: + break; + } +} // RecordToken + +/* + * RewindTokenStream() - Reset a token stream in preperation for reading. + * + */ + +void RewindTokenStream(TokenStream *pTok) +{ + if (pTok->head) { + pTok->current = pTok->head; + pTok->current->current = 0; + } +} // RewindTokenStream + +/* + * ReadToken() - Read the next token from a stream. + * + */ + +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp) +{ + char symbol_name[MAX_SYMBOL_NAME_LEN + 1]; + char string_val[MAX_STRING_LEN + 1]; + int ltoken, len; + char ch; + + ltoken = lReadByte(pTok); + if (ltoken >= 0) { + if (ltoken > 127) + ltoken += 128; + switch (ltoken) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + len = 0; + ch = lReadByte(pTok); + while ((ch >= 'a' && ch <= 'z') || + (ch >= 'A' && ch <= 'Z') || + (ch >= '0' && ch <= '9') || + ch == '_') + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + yylvalpp->sc_ident = LookUpAddString(atable, symbol_name); + return CPP_IDENTIFIER; + break; + case CPP_STRCONSTANT: + len = 0; + while ((ch = lReadByte(pTok)) != 0) + if (len < MAX_STRING_LEN) + string_val[len++] = ch; + string_val[len] = 0; + yylvalpp->sc_ident = LookUpAddString(atable, string_val); + break; + case CPP_FLOATCONSTANT: + len = 0; + ch = lReadByte(pTok); + while ((ch >= '0' && ch <= '9')||(ch=='e'||ch=='E'||ch=='.')||(ch=='+'||ch=='-')) + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name,symbol_name); + yylvalpp->sc_fval=(float)atof(yylvalpp->symbol_name); + break; + case CPP_INTCONSTANT: + len = 0; + ch = lReadByte(pTok); + while ((ch >= '0' && ch <= '9')) + { + if (len < MAX_SYMBOL_NAME_LEN) { + symbol_name[len] = ch; + len++; + ch = lReadByte(pTok); + } + } + symbol_name[len] = '\0'; + assert(ch == '\0'); + strcpy(yylvalpp->symbol_name,symbol_name); + yylvalpp->sc_int=atoi(yylvalpp->symbol_name); + break; + case '(': + yylvalpp->sc_int = lReadByte(pTok); + break; + } + return ltoken; + } + return EOF_SY; +} // ReadToken + +typedef struct TokenInputSrc { + InputSrc base; + TokenStream *tokens; + int (*final)(CPPStruct *); +} TokenInputSrc; + +static int scan_token(TokenInputSrc *in, yystypepp * yylvalpp) +{ + int token = ReadToken(in->tokens, yylvalpp); + int (*final)(CPPStruct *); + cpp->tokenLoc->file = cpp->currentInput->name; + cpp->tokenLoc->line = cpp->currentInput->line; + if (token == '\n') { + in->base.line++; + return token; + } + if (token > 0) return token; + cpp->currentInput = in->base.prev; + final = in->final; + free(in); + if (final && !final(cpp)) return -1; + return cpp->currentInput->scan(cpp->currentInput, yylvalpp); +} + +int ReadFromTokenStream(TokenStream *ts, int name, int (*final)(CPPStruct *)) +{ + TokenInputSrc *in = malloc(sizeof(TokenInputSrc)); + memset(in, 0, sizeof(TokenInputSrc)); + in->base.name = name; + in->base.prev = cpp->currentInput; + in->base.scan = (int (*)(InputSrc *, yystypepp *))scan_token; + in->base.line = 1; + in->tokens = ts; + in->final = final; + RewindTokenStream(ts); + cpp->currentInput = &in->base; + return 1; +} + +typedef struct UngotToken { + InputSrc base; + int token; + yystypepp lval; +} UngotToken; + +static int reget_token(UngotToken *t, yystypepp * yylvalpp) +{ + int token = t->token; + *yylvalpp = t->lval; + cpp->currentInput = t->base.prev; + free(t); + return token; +} + +void UngetToken(int token, yystypepp * yylvalpp) { + UngotToken *t = malloc(sizeof(UngotToken)); + memset(t, 0, sizeof(UngotToken)); + t->token = token; + t->lval = *yylvalpp; + t->base.scan = (void *)reget_token; + t->base.prev = cpp->currentInput; + t->base.name = cpp->currentInput->name; + t->base.line = cpp->currentInput->line; + cpp->currentInput = &t->base; +} + + +void DumpTokenStream(FILE *fp, TokenStream *s, yystypepp * yylvalpp) { + int token; + char str[100]; + + if (fp == 0) fp = stdout; + RewindTokenStream(s); + while ((token = ReadToken(s, yylvalpp)) > 0) { + switch (token) { + case CPP_IDENTIFIER: + case CPP_TYPEIDENTIFIER: + sprintf(str, "%s ", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_STRCONSTANT: + sprintf(str, "\"%s\"", GetAtomString(atable, yylvalpp->sc_ident)); + break; + case CPP_FLOATCONSTANT: + //printf("%g9.6 ", yylvalpp->sc_fval); + break; + case CPP_INTCONSTANT: + //printf("%d ", yylvalpp->sc_int); + break; + default: + if (token >= 127) + sprintf(str, "%s ", GetAtomString(atable, token)); + else + sprintf(str, "%c", token); + break; + } + CPPDebugLogMsg(str); + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////// End of tokens.c /////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/Compiler/Preprocessor/tokens.h b/Compiler/Preprocessor/tokens.h new file mode 100644 index 000000000..19938d7be --- /dev/null +++ b/Compiler/Preprocessor/tokens.h @@ -0,0 +1,94 @@ +// +// Copyright (c) 2002-2010 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. +// +/****************************************************************************\ +Copyright (c) 2002, NVIDIA Corporation. + +NVIDIA Corporation("NVIDIA") supplies this software to you in +consideration of your agreement to the following terms, and your use, +installation, modification or redistribution of this NVIDIA software +constitutes acceptance of these terms. If you do not agree with these +terms, please do not use, install, modify or redistribute this NVIDIA +software. + +In consideration of your agreement to abide by the following terms, and +subject to these terms, NVIDIA grants you a personal, non-exclusive +license, under NVIDIA's copyrights in this original NVIDIA software (the +"NVIDIA Software"), to use, reproduce, modify and redistribute the +NVIDIA Software, with or without modifications, in source and/or binary +forms; provided that if you redistribute the NVIDIA Software, you must +retain the copyright notice of NVIDIA, this notice and the following +text and disclaimers in all such redistributions of the NVIDIA Software. +Neither the name, trademarks, service marks nor logos of NVIDIA +Corporation may be used to endorse or promote products derived from the +NVIDIA Software without specific prior written permission from NVIDIA. +Except as expressly stated in this notice, no other rights or licenses +express or implied, are granted by NVIDIA herein, including but not +limited to any patent rights that may be infringed by your derivative +works or by other works in which the NVIDIA Software may be +incorporated. No hardware is licensed hereunder. + +THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT +WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, +INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE, +NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR +ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER +PRODUCTS. + +IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT, +INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF +USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY +OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE +NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, +TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF +NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +\****************************************************************************/ +// +// tokens.h +// + +#if !defined(__TOKENS_H) +#define __TOKENS_H 1 + +#include "parser.h" + +#define EOF_SY (-1) + +typedef struct TokenBlock_Rec TokenBlock; + +typedef struct TokenStream_Rec { + struct TokenStream_Rec *next; + char *name; + TokenBlock *head; + TokenBlock *current; +} TokenStream; + +struct TokenBlock_Rec { + TokenBlock *next; + int current; + int count; + int max; + unsigned char *data; +}; + +extern TokenStream stdlib_cpp_stream; + + +TokenStream *NewTokenStream(const char *name, MemoryPool *pool); +void DeleteTokenStream(TokenStream *pTok); +void RecordToken(TokenStream *pTok, int token, yystypepp * yylvalpp); +void RewindTokenStream(TokenStream *pTok); +int ReadToken(TokenStream *pTok, yystypepp * yylvalpp); +int ReadFromTokenStream(TokenStream *pTok, int name, int (*final)(CPPStruct *)); +void UngetToken(int, yystypepp * yylvalpp); + +#if defined(CPPC_ENABLE_TOOLS) + +void DumpTokenStream(FILE *, TokenStream *, yystypepp * yylvalpp); + +#endif // defined(CPPC_ENABLE_TOOLS) + +#endif // !defined(__TOKENS_H) diff --git a/Compiler/QualifierAlive.cpp b/Compiler/QualifierAlive.cpp new file mode 100644 index 000000000..e47fd6f9e --- /dev/null +++ b/Compiler/QualifierAlive.cpp @@ -0,0 +1,58 @@ +// +// Copyright (c) 2002-2010 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 "intermediate.h" + +class TAliveTraverser : public TIntermTraverser { +public: + TAliveTraverser(TQualifier q) : TIntermTraverser(true, false, false, true), found(false), qualifier(q) + { + } + + bool wasFound() { return found; } + +protected: + bool found; + TQualifier qualifier; + + void visitSymbol(TIntermSymbol*); + bool visitSelection(Visit, TIntermSelection*); +}; + +// +// Report whether or not a variable of the given qualifier type +// is guaranteed written. Not always possible to determine if +// it is written conditionally. +// +// ?? It does not do this well yet, this is just a place holder +// that simply determines if it was reference at all, anywhere. +// +bool QualifierWritten(TIntermNode* node, TQualifier qualifier) +{ + TAliveTraverser it(qualifier); + + if (node) + node->traverse(&it); + + return it.wasFound(); +} + +void TAliveTraverser::visitSymbol(TIntermSymbol* node) +{ + // + // If it's what we're looking for, record it. + // + if (node->getQualifier() == qualifier) + found = true; +} + +bool TAliveTraverser::visitSelection(Visit preVisit, TIntermSelection* node) +{ + if (wasFound()) + return false; + + return true; +} diff --git a/Compiler/QualifierAlive.h b/Compiler/QualifierAlive.h new file mode 100644 index 000000000..872a06f72 --- /dev/null +++ b/Compiler/QualifierAlive.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 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. +// + +bool QualifierWritten(TIntermNode* root, TQualifier); diff --git a/Compiler/RemoveTree.cpp b/Compiler/RemoveTree.cpp new file mode 100644 index 000000000..9c4162ecb --- /dev/null +++ b/Compiler/RemoveTree.cpp @@ -0,0 +1,76 @@ +// +// Copyright (c) 2002-2010 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 "intermediate.h" +#include "RemoveTree.h" +// +// Code to recursively delete the intermediate tree. +// + +class RemoveTree : public TIntermTraverser +{ +public: + RemoveTree() : TIntermTraverser(false, false, true) + { + } + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); +}; + +void RemoveTree::visitSymbol(TIntermSymbol* node) +{ + delete node; +} + +bool RemoveTree::visitBinary(Visit visit, TIntermBinary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitUnary(Visit visit, TIntermUnary* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitAggregate(Visit visit, TIntermAggregate* node) +{ + delete node; + + return true; +} + +bool RemoveTree::visitSelection(Visit visit, TIntermSelection* node) +{ + delete node; + + return true; +} + +void RemoveTree::visitConstantUnion(TIntermConstantUnion* node) +{ + delete node; +} + +// +// Entry point. +// +void RemoveAllTreeNodes(TIntermNode* root) +{ + RemoveTree it; + + root->traverse(&it); +} + diff --git a/Compiler/RemoveTree.h b/Compiler/RemoveTree.h new file mode 100644 index 000000000..97a821679 --- /dev/null +++ b/Compiler/RemoveTree.h @@ -0,0 +1,7 @@ +// +// Copyright (c) 2002-2010 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. +// + +void RemoveAllTreeNodes(TIntermNode*); diff --git a/Compiler/ResourceLimits.h b/Compiler/ResourceLimits.h new file mode 100644 index 000000000..7b7a4b75b --- /dev/null +++ b/Compiler/ResourceLimits.h @@ -0,0 +1,21 @@ +// +// Copyright (c) 2002-2010 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 _RESOURCE_LIMITS_INCLUDED_ +#define _RESOURCE_LIMITS_INCLUDED_ + +struct TBuiltInResource +{ + int maxVertexAttribs; + int maxVertexUniformVectors; + int maxVaryingVectors; + int maxVertexTextureImageUnits; + int maxCombinedTextureImageUnits; + int maxTextureImageUnits; + int maxFragmentUniformVectors; + int maxDrawBuffers; +}; +#endif // _RESOURCE_LIMITS_INCLUDED_ diff --git a/Compiler/ShHandle.h b/Compiler/ShHandle.h new file mode 100644 index 000000000..cd6353e2b --- /dev/null +++ b/Compiler/ShHandle.h @@ -0,0 +1,139 @@ +// +// Copyright (c) 2002-2010 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 _SHHANDLE_INCLUDED_ +#define _SHHANDLE_INCLUDED_ + +// +// Machine independent part of the compiler private objects +// sent as ShHandle to the driver. +// +// This should not be included by driver code. +// + +#include "ShaderLang.h" + +#include "InfoSink.h" + +class TCompiler; +class TLinker; +class TUniformMap; + + +// +// The base class used to back handles returned to the driver. +// +class TShHandleBase { +public: + TShHandleBase() { } + virtual ~TShHandleBase() { } + virtual TCompiler* getAsCompiler() { return 0; } + virtual TLinker* getAsLinker() { return 0; } + virtual TUniformMap* getAsUniformMap() { return 0; } +}; + +// +// The base class for the machine dependent linker to derive from +// for managing where uniforms live. +// +class TUniformMap : public TShHandleBase { +public: + TUniformMap() { } + virtual ~TUniformMap() { } + virtual TUniformMap* getAsUniformMap() { return this; } + virtual int getLocation(const char* name) = 0; + virtual TInfoSink& getInfoSink() { return infoSink; } + TInfoSink infoSink; +}; +class TIntermNode; + +// +// The base class for the machine dependent compiler to derive from +// for managing object code from the compile. +// +class TCompiler : public TShHandleBase { +public: + TCompiler(EShLanguage l, TInfoSink& sink) : infoSink(sink) , language(l), haveValidObjectCode(false) { } + virtual ~TCompiler() { } + EShLanguage getLanguage() { return language; } + virtual TInfoSink& getInfoSink() { return infoSink; } + + virtual bool compile(TIntermNode* root) = 0; + + virtual TCompiler* getAsCompiler() { return this; } + virtual bool linkable() { return haveValidObjectCode; } + + TInfoSink& infoSink; +protected: + EShLanguage language; + bool haveValidObjectCode; +}; + +// +// Link operations are base on a list of compile results... +// +typedef TVector TCompilerList; +typedef TVector THandleList; + +// +// The base class for the machine dependent linker to derive from +// to manage the resulting executable. +// + +class TLinker : public TShHandleBase { +public: + TLinker(EShExecutable e, TInfoSink& iSink) : + infoSink(iSink), + executable(e), + haveReturnableObjectCode(false), + appAttributeBindings(0), + fixedAttributeBindings(0), + excludedAttributes(0), + excludedCount(0), + uniformBindings(0) { } + virtual TLinker* getAsLinker() { return this; } + virtual ~TLinker() { } + virtual bool link(TCompilerList&, TUniformMap*) = 0; + virtual bool link(THandleList&) { return false; } + virtual void setAppAttributeBindings(const ShBindingTable* t) { appAttributeBindings = t; } + virtual void setFixedAttributeBindings(const ShBindingTable* t) { fixedAttributeBindings = t; } + virtual void getAttributeBindings(ShBindingTable const **t) const = 0; + virtual void setExcludedAttributes(const int* attributes, int count) { excludedAttributes = attributes; excludedCount = count; } + virtual ShBindingTable* getUniformBindings() const { return uniformBindings; } + virtual const void* getObjectCode() const { return 0; } // a real compiler would be returning object code here + virtual TInfoSink& getInfoSink() { return infoSink; } + TInfoSink& infoSink; +protected: + EShExecutable executable; + bool haveReturnableObjectCode; // true when objectCode is acceptable to send to driver + + const ShBindingTable* appAttributeBindings; + const ShBindingTable* fixedAttributeBindings; + const int* excludedAttributes; + int excludedCount; + ShBindingTable* uniformBindings; // created by the linker +}; + +// +// This is the interface between the machine independent code +// and the machine dependent code. +// +// The machine dependent code should derive from the classes +// above. Then Construct*() and Delete*() will create and +// destroy the machine dependent objects, which contain the +// above machine independent information. +// +TCompiler* ConstructCompiler(EShLanguage, int); + +TShHandleBase* ConstructLinker(EShExecutable, int); +void DeleteLinker(TShHandleBase*); + +TUniformMap* ConstructUniformMap(); +void DeleteCompiler(TCompiler*); + +void DeleteUniformMap(TUniformMap*); + +#endif // _SHHANDLE_INCLUDED_ diff --git a/Compiler/ShaderLang.cpp b/Compiler/ShaderLang.cpp new file mode 100644 index 000000000..461604a3a --- /dev/null +++ b/Compiler/ShaderLang.cpp @@ -0,0 +1,587 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// Implement the top-level of interface to the compiler/linker, +// as defined in ShaderLang.h +// +#include "SymbolTable.h" +#include "ParseHelper.h" + +#include "ShHandle.h" +#include "InitializeDll.h" + +#include "ShaderLang.h" +#include "Initialize.h" + +#include "OutputHLSL.h" + +// +// A symbol table for each language. Each has a different +// set of built-ins, and we want to preserve that from +// compile to compile. +// +TSymbolTable SymbolTables[EShLangCount]; + + +TPoolAllocator* PerProcessGPA = 0; +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler/linker. +// + +// +// Driver must call this first, once, before doing any other +// compiler/linker operations. +// +int ShInitialize() +{ + TInfoSink infoSink; + bool ret = true; + + if (!InitProcess()) + return 0; + + // This method should be called once per process. If its called by multiple threads, then + // we need to have thread synchronization code around the initialization of per process + // global pool allocator + if (!PerProcessGPA) { + TPoolAllocator *builtInPoolAllocator = new TPoolAllocator(true); + builtInPoolAllocator->push(); + TPoolAllocator* gPoolAllocator = &GlobalPoolAllocator; + SetGlobalPoolAllocatorPtr(builtInPoolAllocator); + + TSymbolTable symTables[EShLangCount]; + GenerateBuiltInSymbolTable(0, infoSink, symTables); + + PerProcessGPA = new TPoolAllocator(true); + PerProcessGPA->push(); + SetGlobalPoolAllocatorPtr(PerProcessGPA); + + SymbolTables[EShLangVertex].copyTable(symTables[EShLangVertex]); + SymbolTables[EShLangFragment].copyTable(symTables[EShLangFragment]); + + SetGlobalPoolAllocatorPtr(gPoolAllocator); + + symTables[EShLangVertex].pop(); + symTables[EShLangFragment].pop(); + + builtInPoolAllocator->popAll(); + delete builtInPoolAllocator; + + } + + return ret ? 1 : 0; +} + +// +// Driver calls these to create and destroy compiler/linker +// objects. +// + +ShHandle ShConstructCompiler(const EShLanguage language, int debugOptions) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructCompiler(language, debugOptions)); + + return reinterpret_cast(base); +} + +ShHandle ShConstructLinker(const EShExecutable executable, int debugOptions) +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructLinker(executable, debugOptions)); + + return reinterpret_cast(base); +} + +ShHandle ShConstructUniformMap() +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = static_cast(ConstructUniformMap()); + + return reinterpret_cast(base); +} + +void ShDestruct(ShHandle handle) +{ + if (handle == 0) + return; + + TShHandleBase* base = static_cast(handle); + + if (base->getAsCompiler()) + DeleteCompiler(base->getAsCompiler()); + else if (base->getAsLinker()) + DeleteLinker(base->getAsLinker()); + else if (base->getAsUniformMap()) + DeleteUniformMap(base->getAsUniformMap()); +} + +// +// Cleanup symbol tables +// +int __fastcall ShFinalize() +{ + if (PerProcessGPA) { + PerProcessGPA->popAll(); + delete PerProcessGPA; + } + return 1; +} + +bool GenerateBuiltInSymbolTable(const TBuiltInResource* resources, TInfoSink& infoSink, TSymbolTable* symbolTables, EShLanguage language) +{ + TBuiltIns builtIns; + + if (resources) { + builtIns.initialize(*resources); + InitializeSymbolTable(builtIns.getBuiltInStrings(), language, infoSink, resources, symbolTables); + } else { + builtIns.initialize(); + InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangVertex, infoSink, resources, symbolTables); + InitializeSymbolTable(builtIns.getBuiltInStrings(), EShLangFragment, infoSink, resources, symbolTables); + } + + return true; +} + +bool InitializeSymbolTable(TBuiltInStrings* BuiltInStrings, EShLanguage language, TInfoSink& infoSink, const TBuiltInResource* resources, TSymbolTable* symbolTables) +{ + TIntermediate intermediate(infoSink); + TSymbolTable* symbolTable; + + if (resources) + symbolTable = symbolTables; + else + symbolTable = &symbolTables[language]; + + TParseContext parseContext(*symbolTable, intermediate, language, infoSink); + + GlobalParseContext = &parseContext; + + setInitialState(); + + assert(symbolTable->isEmpty() || symbolTable->atSharedBuiltInLevel()); + + // + // Parse the built-ins. This should only happen once per + // language symbol table. + // + // Push the symbol table to give it an initial scope. This + // push should not have a corresponding pop, so that built-ins + // are preserved, and the test for an empty table fails. + // + + symbolTable->push(); + + //Initialize the Preprocessor + int ret = InitPreprocessor(); + if (ret) { + infoSink.info.message(EPrefixInternalError, "Unable to intialize the Preprocessor"); + return false; + } + + for (TBuiltInStrings::iterator i = BuiltInStrings[parseContext.language].begin(); + i != BuiltInStrings[parseContext.language].end(); + ++i) { + const char* builtInShaders[1]; + int builtInLengths[1]; + + builtInShaders[0] = (*i).c_str(); + builtInLengths[0] = (int) (*i).size(); + + if (PaParseStrings(const_cast(builtInShaders), builtInLengths, 1, parseContext) != 0) { + infoSink.info.message(EPrefixInternalError, "Unable to parse built-ins"); + return false; + } + } + + if (resources) { + IdentifyBuiltIns(parseContext.language, *symbolTable, *resources); + } else { + IdentifyBuiltIns(parseContext.language, *symbolTable); + } + + FinalizePreprocessor(); + + return true; +} + +// +// Do an actual compile on the given strings. The result is left +// in the given compile object. +// +// Return: The return value of ShCompile is really boolean, indicating +// success or failure. +// +int ShCompile( + const ShHandle handle, + const char* const shaderStrings[], + const int numStrings, + const EShOptimizationLevel optLevel, + const TBuiltInResource* resources, + int debugOptions + ) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TCompiler* compiler = base->getAsCompiler(); + if (compiler == 0) + return 0; + + GlobalPoolAllocator.push(); + compiler->infoSink.info.erase(); + compiler->infoSink.debug.erase(); + compiler->infoSink.obj.erase(); + + if (numStrings == 0) + return 1; + + TIntermediate intermediate(compiler->infoSink); + TSymbolTable symbolTable(SymbolTables[compiler->getLanguage()]); + + GenerateBuiltInSymbolTable(resources, compiler->infoSink, &symbolTable, compiler->getLanguage()); + + TParseContext parseContext(symbolTable, intermediate, compiler->getLanguage(), compiler->infoSink); + parseContext.initializeExtensionBehavior(); + + GlobalParseContext = &parseContext; + + setInitialState(); + + InitPreprocessor(); + // + // Parse the application's shaders. All the following symbol table + // work will be throw-away, so push a new allocation scope that can + // be thrown away, then push a scope for the current shader's globals. + // + bool success = true; + + symbolTable.push(); + if (!symbolTable.atGlobalLevel()) + parseContext.infoSink.info.message(EPrefixInternalError, "Wrong symbol table level"); + + int ret = PaParseStrings(const_cast(shaderStrings), 0, numStrings, parseContext); + if (ret) + success = false; + + if (success && parseContext.treeRoot) { + if (optLevel == EShOptNoGeneration) + parseContext.infoSink.info.message(EPrefixNone, "No errors. No code generation or linking was requested."); + else { + success = intermediate.postProcess(parseContext.treeRoot, parseContext.language); + + if (success) { + + if (debugOptions & EDebugOpIntermediate) + intermediate.outputTree(parseContext.treeRoot); + + if(debugOptions & EDebugOpObjectCode) + { + sh::OutputHLSL outputHLSL(parseContext); + + outputHLSL.header(); + parseContext.treeRoot->traverse(&outputHLSL); + } + + // + // Call the machine dependent compiler + // + if (! compiler->compile(parseContext.treeRoot)) + success = false; + } + } + } else if (!success) { + parseContext.infoSink.info.prefix(EPrefixError); + parseContext.infoSink.info << parseContext.numErrors << " compilation errors. No code generated.\n\n"; + success = false; + if (debugOptions & EDebugOpIntermediate) + intermediate.outputTree(parseContext.treeRoot); + } + + intermediate.remove(parseContext.treeRoot); + + // + // Ensure symbol table is returned to the built-in level, + // throwing away all but the built-ins. + // + while (! symbolTable.atSharedBuiltInLevel()) + symbolTable.pop(); + + FinalizePreprocessor(); + // + // Throw away all the temporary memory used by the compilation process. + // + GlobalPoolAllocator.pop(); + + return success ? 1 : 0; +} + +// +// Do an actual link on the given compile objects. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShLink( + const ShHandle linkHandle, + const ShHandle compHandles[], + const int numHandles, + ShHandle uniformMapHandle, + short int** uniformsAccessed, + int* numUniformsAccessed) + +{ + if (!InitThread()) + return 0; + + TShHandleBase* base = reinterpret_cast(linkHandle); + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + int returnValue; + GlobalPoolAllocator.push(); + returnValue = ShLinkExt(linkHandle, compHandles, numHandles); + GlobalPoolAllocator.pop(); + + if (returnValue) + return 1; + + return 0; +} +// +// This link method will be eventually used once the ICD supports the new linker interface +// +int ShLinkExt( + const ShHandle linkHandle, + const ShHandle compHandles[], + const int numHandles) +{ + if (linkHandle == 0 || numHandles == 0) + return 0; + + THandleList cObjects; + + {// support MSVC++6.0 + for (int i = 0; i < numHandles; ++i) { + if (compHandles[i] == 0) + return 0; + TShHandleBase* base = reinterpret_cast(compHandles[i]); + if (base->getAsLinker()) { + cObjects.push_back(base->getAsLinker()); + } + if (base->getAsCompiler()) + cObjects.push_back(base->getAsCompiler()); + + + if (cObjects[i] == 0) + return 0; + } + } + + TShHandleBase* base = reinterpret_cast(linkHandle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->infoSink.info.erase(); + linker->infoSink.obj.erase(); + + {// support MSVC++6.0 + for (int i = 0; i < numHandles; ++i) { + if (cObjects[i]->getAsCompiler()) { + if (! cObjects[i]->getAsCompiler()->linkable()) { + linker->infoSink.info.message(EPrefixError, "Not all shaders have valid object code."); + return 0; + } + } + } + } + + bool ret = linker->link(cObjects); + + return ret ? 1 : 0; +} + +// +// ShSetEncrpytionMethod is a place-holder for specifying +// how source code is encrypted. +// +void ShSetEncryptionMethod(ShHandle handle) +{ + if (handle == 0) + return; +} + +// +// Return any compiler/linker/uniformmap log of messages for the application. +// +const char* ShGetInfoLog(const ShHandle handle) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = static_cast(handle); + TInfoSink* infoSink; + + if (base->getAsCompiler()) + infoSink = &(base->getAsCompiler()->getInfoSink()); + else if (base->getAsLinker()) + infoSink = &(base->getAsLinker()->getInfoSink()); + + infoSink->info << infoSink->debug.c_str(); + return infoSink->info.c_str(); +} + +// +// Return any unlinked object code. +// +const char* ShGetObjectCode(const ShHandle handle) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = static_cast(handle); + TInfoSink* infoSink; + + if (base->getAsCompiler()) + infoSink = &(base->getAsCompiler()->getInfoSink()); + + return infoSink->obj.c_str(); +} + +// +// Return the resulting binary code from the link process. Structure +// is machine dependent. +// +const void* ShGetExecutable(const ShHandle handle) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + return linker->getObjectCode(); +} + +// +// Let the linker know where the application said it's attributes are bound. +// The linker does not use these values, they are remapped by the ICD or +// hardware. It just needs them to know what's aliased. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShSetVirtualAttributeBindings(const ShHandle handle, const ShBindingTable* table) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->setAppAttributeBindings(table); + + return 1; +} + +// +// Let the linker know where the predefined attributes have to live. +// +int ShSetFixedAttributeBindings(const ShHandle handle, const ShBindingTable* table) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + + if (linker == 0) + return 0; + + linker->setFixedAttributeBindings(table); + return 1; +} + +// +// Some attribute locations are off-limits to the linker... +// +int ShExcludeAttributes(const ShHandle handle, int *attributes, int count) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return 0; + + TShHandleBase* base = reinterpret_cast(handle); + TLinker* linker = static_cast(base->getAsLinker()); + if (linker == 0) + return 0; + + linker->setExcludedAttributes(attributes, count); + + return 1; +} + +// +// Return the index for OpenGL to use for knowing where a uniform lives. +// +// Return: The return value of is really boolean, indicating +// success or failure. +// +int ShGetUniformLocation(const ShHandle handle, const char* name) +{ + if (!InitThread()) + return 0; + + if (handle == 0) + return -1; + + TShHandleBase* base = reinterpret_cast(handle); + TUniformMap* uniformMap= base->getAsUniformMap(); + if (uniformMap == 0) + return -1; + + return uniformMap->getLocation(name); +} + diff --git a/Compiler/ShaderLang.h b/Compiler/ShaderLang.h new file mode 100644 index 000000000..4e695eb96 --- /dev/null +++ b/Compiler/ShaderLang.h @@ -0,0 +1,179 @@ +// +// Copyright (c) 2002-2010 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_INTERFACE_INCLUDED_ +#define _COMPILER_INTERFACE_INCLUDED_ + +#include "ResourceLimits.h" + +#ifdef _WIN32 +#define C_DECL __cdecl +#else +#define __fastcall +#define C_DECL +#endif + +// +// This is the platform independent interface between an OGL driver +// and the shading language compiler/linker. +// + +#ifdef __cplusplus + extern "C" { +#endif +// +// Driver must call this first, once, before doing any other +// compiler/linker operations. +// +int ShInitialize(); +// +// Driver should call this at shutdown. +// +int __fastcall ShFinalize(); +// +// Types of languages the compiler can consume. +// +typedef enum { + EShLangVertex, + EShLangFragment, + EShLangPack, + EShLangUnpack, + EShLangCount, +} EShLanguage; + +// +// Types of output the linker will create. +// +typedef enum { + EShExVertexFragment, + EShExPackFragment, + EShExUnpackFragment, + EShExFragment +} EShExecutable; + +// +// Optimization level for the compiler. +// +typedef enum { + EShOptNoGeneration, + EShOptNone, + EShOptSimple, // Optimizations that can be done quickly + EShOptFull, // Optimizations that will take more time +} EShOptimizationLevel; + +// +// Build a table for bindings. This can be used for locating +// attributes, uniforms, globals, etc., as needed. +// +typedef struct { + const char* name; + int binding; +} ShBinding; + +typedef struct { + int numBindings; + ShBinding* bindings; // array of bindings +} ShBindingTable; + +// +// ShHandle held by but opaque to the driver. It is allocated, +// managed, and de-allocated by the compiler/linker. It's contents +// are defined by and used by the compiler and linker. For example, +// symbol table information and object code passed from the compiler +// to the linker can be stored where ShHandle points. +// +// If handle creation fails, 0 will be returned. +// +typedef void* ShHandle; + +// +// Driver calls these to create and destroy compiler/linker +// objects. +// +ShHandle ShConstructCompiler(const EShLanguage, int debugOptions); // one per shader +ShHandle ShConstructLinker(const EShExecutable, int debugOptions); // one per shader pair +ShHandle ShConstructUniformMap(); // one per uniform namespace (currently entire program object) +void ShDestruct(ShHandle); + +// +// The return value of ShCompile is boolean, indicating +// success or failure. +// +// The info-log should be written by ShCompile into +// ShHandle, so it can answer future queries. +// +int ShCompile( + const ShHandle, + const char* const shaderStrings[], + const int numStrings, + const EShOptimizationLevel, + const TBuiltInResource *resources, + int debugOptions + ); + + +// +// Similar to ShCompile, but accepts an opaque handle to an +// intermediate language structure. +// +int ShCompileIntermediate( + ShHandle compiler, + ShHandle intermediate, + const EShOptimizationLevel, + int debuggable // boolean + ); + +int ShLink( + const ShHandle, // linker object + const ShHandle h[], // compiler objects to link together + const int numHandles, + ShHandle uniformMap, // updated with new uniforms + short int** uniformsAccessed, // returned with indexes of uniforms accessed + int* numUniformsAccessed); + +int ShLinkExt( + const ShHandle, // linker object + const ShHandle h[], // compiler objects to link together + const int numHandles); + +// +// ShSetEncrpytionMethod is a place-holder for specifying +// how source code is encrypted. +// +void ShSetEncryptionMethod(ShHandle); + +// +// All the following return 0 if the information is not +// available in the object passed down, or the object is bad. +// +const char* ShGetInfoLog(const ShHandle); +const char* ShGetObjectCode(const ShHandle); +const void* ShGetExecutable(const ShHandle); +int ShSetVirtualAttributeBindings(const ShHandle, const ShBindingTable*); // to detect user aliasing +int ShSetFixedAttributeBindings(const ShHandle, const ShBindingTable*); // to force any physical mappings +int ShGetPhysicalAttributeBindings(const ShHandle, const ShBindingTable**); // for all attributes +// +// Tell the linker to never assign a vertex attribute to this list of physical attributes +// +int ShExcludeAttributes(const ShHandle, int *attributes, int count); + +// +// Returns the location ID of the named uniform. +// Returns -1 if error. +// +int ShGetUniformLocation(const ShHandle uniformMap, const char* name); + +enum TDebugOptions { + EDebugOpNone = 0x000, + EDebugOpIntermediate = 0x001, + EDebugOpAssembly = 0x002, + EDebugOpObjectCode = 0x004, + EDebugOpLinkMaps = 0x008 +}; +#ifdef __cplusplus + } +#endif + +#endif // _COMPILER_INTERFACE_INCLUDED_ diff --git a/Compiler/SymbolTable.cpp b/Compiler/SymbolTable.cpp new file mode 100644 index 000000000..fa54a9a59 --- /dev/null +++ b/Compiler/SymbolTable.cpp @@ -0,0 +1,211 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// Symbol table for parsing. Most functionaliy and main ideas +// are documented in the header file. +// + +#include "SymbolTable.h" + +// +// TType helper function needs a place to live. +// + +// +// Recursively generate mangled names. +// +void TType::buildMangledName(TString& mangledName) +{ + if (isMatrix()) + mangledName += 'm'; + else if (isVector()) + mangledName += 'v'; + + switch (type) { + case EbtFloat: mangledName += 'f'; break; + case EbtInt: mangledName += 'i'; break; + case EbtBool: mangledName += 'b'; break; + case EbtSampler2D: mangledName += "s2"; break; + case EbtSamplerCube: mangledName += "sC"; break; + case EbtStruct: + mangledName += "struct-"; + if (typeName) + mangledName += *typeName; + {// support MSVC++6.0 + for (unsigned int i = 0; i < structure->size(); ++i) { + mangledName += '-'; + (*structure)[i].type->buildMangledName(mangledName); + } + } + default: + break; + } + + mangledName += static_cast('0' + getNominalSize()); + if (isArray()) { + char buf[10]; + sprintf(buf, "%d", arraySize); + mangledName += '['; + mangledName += buf; + mangledName += ']'; + } +} + +int TType::getStructSize() const +{ + if (!getStruct()) { + assert(false && "Not a struct"); + return 0; + } + + if (structureSize == 0) + for (TTypeList::iterator tl = getStruct()->begin(); tl != getStruct()->end(); tl++) + structureSize += ((*tl).type)->getObjectSize(); + + return structureSize; +} + +// +// Dump functions. +// + +void TVariable::dump(TInfoSink& infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << type.getQualifierString() << " " << type.getBasicString(); + if (type.isArray()) { + infoSink.debug << "[0]"; + } + infoSink.debug << "\n"; +} + +void TFunction::dump(TInfoSink &infoSink) const +{ + infoSink.debug << getName().c_str() << ": " << returnType.getBasicString() << " " << getMangledName().c_str() << "\n"; +} + +void TSymbolTableLevel::dump(TInfoSink &infoSink) const +{ + tLevel::const_iterator it; + for (it = level.begin(); it != level.end(); ++it) + (*it).second->dump(infoSink); +} + +void TSymbolTable::dump(TInfoSink &infoSink) const +{ + for (int level = currentLevel(); level >= 0; --level) { + infoSink.debug << "LEVEL " << level << "\n"; + table[level]->dump(infoSink); + } +} + +// +// Functions have buried pointers to delete. +// +TFunction::~TFunction() +{ + for (TParamList::iterator i = parameters.begin(); i != parameters.end(); ++i) + delete (*i).type; +} + +// +// Symbol table levels are a map of pointers to symbols that have to be deleted. +// +TSymbolTableLevel::~TSymbolTableLevel() +{ + for (tLevel::iterator it = level.begin(); it != level.end(); ++it) + delete (*it).second; +} + +// +// Change all function entries in the table with the non-mangled name +// to be related to the provided built-in operation. This is a low +// performance operation, and only intended for symbol tables that +// live across a large number of compiles. +// +void TSymbolTableLevel::relateToOperator(const char* name, TOperator op) +{ + tLevel::iterator it; + for (it = level.begin(); it != level.end(); ++it) { + if ((*it).second->isFunction()) { + TFunction* function = static_cast((*it).second); + if (function->getName() == name) + function->relateToOperator(op); + } + } +} + + +TSymbol::TSymbol(const TSymbol& copyOf) +{ + name = NewPoolTString(copyOf.name->c_str()); + uniqueId = copyOf.uniqueId; +} + +TVariable::TVariable(const TVariable& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + type.copyType(copyOf.type, remapper); + userType = copyOf.userType; + // for builtIn symbol table level, unionArray and arrayInformation pointers should be NULL + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; + + if (copyOf.unionArray) { + assert(!copyOf.type.getStruct()); + assert(copyOf.type.getObjectSize() == 1); + unionArray = new constUnion[1]; + unionArray[0] = copyOf.unionArray[0]; + } else + unionArray = 0; +} + +TVariable* TVariable::clone(TStructureMap& remapper) +{ + TVariable *variable = new TVariable(*this, remapper); + + return variable; +} + +TFunction::TFunction(const TFunction& copyOf, TStructureMap& remapper) : TSymbol(copyOf) +{ + for (unsigned int i = 0; i < copyOf.parameters.size(); ++i) { + TParameter param; + parameters.push_back(param); + parameters.back().copyParam(copyOf.parameters[i], remapper); + } + + returnType.copyType(copyOf.returnType, remapper); + mangledName = copyOf.mangledName; + op = copyOf.op; + defined = copyOf.defined; +} + +TFunction* TFunction::clone(TStructureMap& remapper) +{ + TFunction *function = new TFunction(*this, remapper); + + return function; +} + +TSymbolTableLevel* TSymbolTableLevel::clone(TStructureMap& remapper) +{ + TSymbolTableLevel *symTableLevel = new TSymbolTableLevel(); + tLevel::iterator iter; + for (iter = level.begin(); iter != level.end(); ++iter) { + symTableLevel->insert(*iter->second->clone(remapper)); + } + + return symTableLevel; +} + +void TSymbolTable::copyTable(const TSymbolTable& copyOf) +{ + TStructureMap remapper; + uniqueId = copyOf.uniqueId; + for (unsigned int i = 0; i < copyOf.table.size(); ++i) { + table.push_back(copyOf.table[i]->clone(remapper)); + } +} diff --git a/Compiler/SymbolTable.h b/Compiler/SymbolTable.h new file mode 100644 index 000000000..3af31ade6 --- /dev/null +++ b/Compiler/SymbolTable.h @@ -0,0 +1,300 @@ +// +// Copyright (c) 2002-2010 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 _SYMBOL_TABLE_INCLUDED_ +#define _SYMBOL_TABLE_INCLUDED_ + +// +// Symbol table for parsing. Has these design characteristics: +// +// * Same symbol table can be used to compile many shaders, to preserve +// effort of creating and loading with the large numbers of built-in +// symbols. +// +// * Name mangling will be used to give each function a unique name +// so that symbol table lookups are never ambiguous. This allows +// a simpler symbol table structure. +// +// * Pushing and popping of scope, so symbol table will really be a stack +// of symbol tables. Searched from the top, with new inserts going into +// the top. +// +// * Constants: Compile time constant symbols will keep their values +// in the symbol table. The parser can substitute constants at parse +// time, including doing constant folding and constant propagation. +// +// * No temporaries: Temporaries made from operations (+, --, .xy, etc.) +// are tracked in the intermediate representation, not the symbol table. +// + +#include "Common.h" +#include "intermediate.h" +#include "InfoSink.h" + +// +// Symbol base class. (Can build functions or variables out of these...) +// +class TSymbol { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbol(const TString *n) : name(n) { } + virtual ~TSymbol() { /* don't delete name, it's from the pool */ } + const TString& getName() const { return *name; } + virtual const TString& getMangledName() const { return getName(); } + virtual bool isFunction() const { return false; } + virtual bool isVariable() const { return false; } + void setUniqueId(int id) { uniqueId = id; } + int getUniqueId() const { return uniqueId; } + virtual void dump(TInfoSink &infoSink) const = 0; + TSymbol(const TSymbol&); + virtual TSymbol* clone(TStructureMap& remapper) = 0; + +protected: + const TString *name; + unsigned int uniqueId; // For real comparing during code generation +}; + +// +// Variable class, meaning a symbol that's not a function. +// +// There could be a separate class heirarchy for Constant variables; +// Only one of int, bool, or float, (or none) is correct for +// any particular use, but it's easy to do this way, and doesn't +// seem worth having separate classes, and "getConst" can't simply return +// different values for different types polymorphically, so this is +// just simple and pragmatic. +// +class TVariable : public TSymbol { +public: + TVariable(const TString *name, const TType& t, bool uT = false ) : TSymbol(name), type(t), userType(uT), unionArray(0), arrayInformationType(0) { } + virtual ~TVariable() { } + virtual bool isVariable() const { return true; } + TType& getType() { return type; } + const TType& getType() const { return type; } + bool isUserType() const { return userType; } + void changeQualifier(TQualifier qualifier) { type.changeQualifier(qualifier); } + void updateArrayInformationType(TType *t) { arrayInformationType = t; } + TType* getArrayInformationType() { return arrayInformationType; } + + virtual void dump(TInfoSink &infoSink) const; + + constUnion* getConstPointer() { + if (!unionArray) + unionArray = new constUnion[type.getObjectSize()]; + + return unionArray; + } + + constUnion* getConstPointer() const { return unionArray; } + + void shareConstPointer( constUnion *constArray) + { + delete unionArray; + unionArray = constArray; + } + TVariable(const TVariable&, TStructureMap& remapper); // copy constructor + virtual TVariable* clone(TStructureMap& remapper); + +protected: + TType type; + bool userType; + // we are assuming that Pool Allocator will free the memory allocated to unionArray + // when this object is destroyed + constUnion *unionArray; + TType *arrayInformationType; // this is used for updating maxArraySize in all the references to a given symbol +}; + +// +// The function sub-class of symbols and the parser will need to +// share this definition of a function parameter. +// +struct TParameter { + TString *name; + TType* type; + void copyParam(const TParameter& param, TStructureMap& remapper) { + name = NewPoolTString(param.name->c_str()); + type = param.type->clone(remapper); + } +}; + +// +// The function sub-class of a symbol. +// +class TFunction : public TSymbol { +public: + TFunction(TOperator o) : + TSymbol(0), + returnType(TType(EbtVoid)), + op(o), + defined(false) { } + TFunction(const TString *name, TType& retType, TOperator tOp = EOpNull) : + TSymbol(name), + returnType(retType), + mangledName(*name + '('), + op(tOp), + defined(false) { } + virtual ~TFunction(); + virtual bool isFunction() const { return true; } + + void addParameter(TParameter& p) + { + parameters.push_back(p); + mangledName = mangledName + p.type->getMangledName(); + } + + const TString& getMangledName() const { return mangledName; } + const TType& getReturnType() const { return returnType; } + void relateToOperator(TOperator o) { op = o; } + TOperator getBuiltInOp() const { return op; } + void setDefined() { defined = true; } + bool isDefined() { return defined; } + + int getParamCount() const { return static_cast(parameters.size()); } + TParameter& operator [](int i) { return parameters[i]; } + const TParameter& operator [](int i) const { return parameters[i]; } + + virtual void dump(TInfoSink &infoSink) const; + TFunction(const TFunction&, TStructureMap& remapper); + virtual TFunction* clone(TStructureMap& remapper); + +protected: + typedef TVector TParamList; + TParamList parameters; + TType returnType; + TString mangledName; + TOperator op; + bool defined; +}; + + +class TSymbolTableLevel { +public: + typedef std::map, pool_allocator > > tLevel; + typedef tLevel::const_iterator const_iterator; + typedef const tLevel::value_type tLevelPair; + typedef std::pair tInsertResult; + + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + TSymbolTableLevel() { } + ~TSymbolTableLevel(); + + bool insert(TSymbol& symbol) + { + // + // returning true means symbol was added to the table + // + tInsertResult result; + result = level.insert(tLevelPair(symbol.getMangledName(), &symbol)); + + return result.second; + } + + TSymbol* find(const TString& name) const + { + tLevel::const_iterator it = level.find(name); + if (it == level.end()) + return 0; + else + return (*it).second; + } + + const_iterator begin() const + { + return level.begin(); + } + + const_iterator end() const + { + return level.end(); + } + + void relateToOperator(const char* name, TOperator op); + void dump(TInfoSink &infoSink) const; + TSymbolTableLevel* clone(TStructureMap& remapper); + +protected: + tLevel level; +}; + +class TSymbolTable { +public: + TSymbolTable() : uniqueId(0) + { + // + // The symbol table cannot be used until push() is called, but + // the lack of an initial call to push() can be used to detect + // that the symbol table has not been preloaded with built-ins. + // + } + + TSymbolTable(TSymbolTable& symTable) + { + table.push_back(symTable.table[0]); + uniqueId = symTable.uniqueId; + } + + ~TSymbolTable() + { + // level 0 is always built In symbols, so we never pop that out + while (table.size() > 1) + pop(); + } + + // + // When the symbol table is initialized with the built-ins, there should + // 'push' calls, so that built-ins are at level 0 and the shader + // globals are at level 1. + // + bool isEmpty() { return table.size() == 0; } + bool atBuiltInLevel() { return atSharedBuiltInLevel() || atDynamicBuiltInLevel(); } + bool atSharedBuiltInLevel() { return table.size() == 1; } + bool atGlobalLevel() { return table.size() <= 3; } + void push() { + table.push_back(new TSymbolTableLevel); + } + + void pop() { + delete table[currentLevel()]; + table.pop_back(); + } + + bool insert(TSymbol& symbol) + { + symbol.setUniqueId(++uniqueId); + return table[currentLevel()]->insert(symbol); + } + + TSymbol* find(const TString& name, bool* builtIn = 0, bool *sameScope = 0) + { + int level = currentLevel(); + TSymbol* symbol; + do { + symbol = table[level]->find(name); + --level; + } while (symbol == 0 && level >= 0); + level++; + if (builtIn) + *builtIn = level == 0; + if (sameScope) + *sameScope = level == currentLevel(); + return symbol; + } + + TSymbolTableLevel* getGlobalLevel() { assert(table.size() >= 3); return table[2]; } + void relateToOperator(const char* name, TOperator op) { table[0]->relateToOperator(name, op); } + int getMaxSymbolId() { return uniqueId; } + void dump(TInfoSink &infoSink) const; + void copyTable(const TSymbolTable& copyOf); + +protected: + int currentLevel() const { return static_cast(table.size()) - 1; } + bool atDynamicBuiltInLevel() { return table.size() == 2; } + + std::vector table; + int uniqueId; // for unique identification in code generation +}; + +#endif // _SYMBOL_TABLE_INCLUDED_ diff --git a/Compiler/Tools/bison.exe b/Compiler/Tools/bison.exe new file mode 100644 index 000000000..4881bf604 Binary files /dev/null and b/Compiler/Tools/bison.exe differ diff --git a/Compiler/Tools/bison.hairy b/Compiler/Tools/bison.hairy new file mode 100644 index 000000000..999b55591 --- /dev/null +++ b/Compiler/Tools/bison.hairy @@ -0,0 +1,334 @@ + +extern int timeclock; + + +int yyerror; /* Yyerror and yycost are set by guards. */ +int yycost; /* If yyerror is set to a nonzero value by a */ + /* guard, the reduction with which the guard */ + /* is associated is not performed, and the */ + /* error recovery mechanism is invoked. */ + /* Yycost indicates the cost of performing */ + /* the reduction given the attributes of the */ + /* symbols. */ + + +/* YYMAXDEPTH indicates the size of the parser's state and value */ +/* stacks. */ + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 500 +#endif + +/* YYMAXRULES must be at least as large as the number of rules that */ +/* could be placed in the rule queue. That number could be determined */ +/* from the grammar and the size of the stack, but, as yet, it is not. */ + +#ifndef YYMAXRULES +#define YYMAXRULES 100 +#endif + +#ifndef YYMAXBACKUP +#define YYMAXBACKUP 100 +#endif + + +short yyss[YYMAXDEPTH]; /* the state stack */ +YYSTYPE yyvs[YYMAXDEPTH]; /* the semantic value stack */ +YYLTYPE yyls[YYMAXDEPTH]; /* the location stack */ +short yyrq[YYMAXRULES]; /* the rule queue */ +int yychar; /* the lookahead symbol */ + +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +YYSTYPE yytval; /* the semantic value for the state */ + /* at the top of the state stack. */ + +YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ + +YYLTYPE yytloc; /* location data for the state at the */ + /* top of the state stack */ + + +int yynunlexed; +short yyunchar[YYMAXBACKUP]; +YYSTYPE yyunval[YYMAXBACKUP]; +YYLTYPE yyunloc[YYMAXBACKUP]; + +short *yygssp; /* a pointer to the top of the state */ + /* stack; only set during error */ + /* recovery. */ + +YYSTYPE *yygvsp; /* a pointer to the top of the value */ + /* stack; only set during error */ + /* recovery. */ + +YYLTYPE *yyglsp; /* a pointer to the top of the */ + /* location stack; only set during */ + /* error recovery. */ + + +/* Yyget is an interface between the parser and the lexical analyzer. */ +/* It is costly to provide such an interface, but it avoids requiring */ +/* the lexical analyzer to be able to back up the scan. */ + +yyget() +{ + if (yynunlexed > 0) + { + yynunlexed--; + yychar = yyunchar[yynunlexed]; + yylval = yyunval[yynunlexed]; + yylloc = yyunloc[yynunlexed]; + } + else if (yychar <= 0) + yychar = 0; + else + { + yychar = yylex(); + if (yychar < 0) + yychar = 0; + else yychar = YYTRANSLATE(yychar); + } +} + + + +yyunlex(chr, val, loc) +int chr; +YYSTYPE val; +YYLTYPE loc; +{ + yyunchar[yynunlexed] = chr; + yyunval[yynunlexed] = val; + yyunloc[yynunlexed] = loc; + yynunlexed++; +} + + + +yyrestore(first, last) +register short *first; +register short *last; +{ + register short *ssp; + register short *rp; + register int symbol; + register int state; + register int tvalsaved; + + ssp = yygssp; + yyunlex(yychar, yylval, yylloc); + + tvalsaved = 0; + while (first != last) + { + symbol = yystos[*ssp]; + if (symbol < YYNTBASE) + { + yyunlex(symbol, yytval, yytloc); + tvalsaved = 1; + ssp--; + } + + ssp--; + + if (first == yyrq) + first = yyrq + YYMAXRULES; + + first--; + + for (rp = yyrhs + yyprhs[*first]; symbol = *rp; rp++) + { + if (symbol < YYNTBASE) + state = yytable[yypact[*ssp] + symbol]; + else + { + state = yypgoto[symbol - YYNTBASE] + *ssp; + + if (state >= 0 && state <= YYLAST && yycheck[state] == *ssp) + state = yytable[state]; + else + state = yydefgoto[symbol - YYNTBASE]; + } + + *++ssp = state; + } + } + + if ( ! tvalsaved && ssp > yyss) + { + yyunlex(yystos[*ssp], yytval, yytloc); + ssp--; + } + + yygssp = ssp; +} + + + +int +yyparse() +{ + register int yystate; + register int yyn; + register short *yyssp; + register short *yyrq0; + register short *yyptr; + register YYSTYPE *yyvsp; + + int yylen; + YYLTYPE *yylsp; + short *yyrq1; + short *yyrq2; + + yystate = 0; + yyssp = yyss - 1; + yyvsp = yyvs - 1; + yylsp = yyls - 1; + yyrq0 = yyrq; + yyrq1 = yyrq0; + yyrq2 = yyrq0; + + yychar = yylex(); + if (yychar < 0) + yychar = 0; + else yychar = YYTRANSLATE(yychar); + +yynewstate: + + if (yyssp >= yyss + YYMAXDEPTH - 1) + { + yyabort("Parser Stack Overflow"); + YYABORT; + } + + *++yyssp = yystate; + +yyresume: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + yyn += yychar; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar) + goto yydefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + yystate = yyn; + + yyptr = yyrq2; + while (yyptr != yyrq1) + { + yyn = *yyptr++; + yylen = yyr2[yyn]; + yyvsp -= yylen; + yylsp -= yylen; + + yyguard(yyn, yyvsp, yylsp); + if (yyerror) + goto yysemerr; + + yyaction(yyn, yyvsp, yylsp); + *++yyvsp = yyval; + + yylsp++; + if (yylen == 0) + { + yylsp->timestamp = timeclock; + yylsp->first_line = yytloc.first_line; + yylsp->first_column = yytloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } + + if (yyptr == yyrq + YYMAXRULES) + yyptr = yyrq; + } + + if (yystate == YYFINAL) + YYACCEPT; + + yyrq2 = yyptr; + yyrq1 = yyrq0; + + *++yyvsp = yytval; + *++yylsp = yytloc; + yytval = yylval; + yytloc = yylloc; + yyget(); + + goto yynewstate; + +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +yyreduce: + + *yyrq0++ = yyn; + + if (yyrq0 == yyrq + YYMAXRULES) + yyrq0 = yyrq; + + if (yyrq0 == yyrq2) + { + yyabort("Parser Rule Queue Overflow"); + YYABORT; + } + + yyssp -= yyr2[yyn]; + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yysemerr: + *--yyptr = yyn; + yyrq2 = yyptr; + yyvsp += yyr2[yyn]; + +yyerrlab: + + yygssp = yyssp; + yygvsp = yyvsp; + yyglsp = yylsp; + yyrestore(yyrq0, yyrq2); + yyrecover(); + yystate = *yygssp; + yyssp = yygssp; + yyvsp = yygvsp; + yyrq0 = yyrq; + yyrq1 = yyrq0; + yyrq2 = yyrq0; + goto yyresume; +} + +$ diff --git a/Compiler/Tools/bison.simple b/Compiler/Tools/bison.simple new file mode 100644 index 000000000..08acea80a --- /dev/null +++ b/Compiler/Tools/bison.simple @@ -0,0 +1,699 @@ +/* -*-C-*- Note some compilers choke on comments on `#line' lines. */ + +/* Skeleton output parser for bison, + Copyright (C) 1984, 1989, 1990 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* As a special exception, when this file is copied by Bison into a + Bison output file, you may use that output file without restriction. + This special exception was added by the Free Software Foundation + in version 1.24 of Bison. */ + +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not __GNUC__ */ +#if HAVE_ALLOCA_H +#include +#else /* not HAVE_ALLOCA_H */ +#ifdef _AIX + #pragma alloca +#else /* not _AIX */ +char *alloca (); +#endif /* not _AIX */ +#endif /* not HAVE_ALLOCA_H */ +#endif /* not __GNUC__ */ + +extern void yyerror(char* s); + +#ifndef alloca +#ifdef __GNUC__ +#define alloca __builtin_alloca +#else /* not GNU C. */ +#if (!defined (__STDC__) && defined (sparc)) || defined (__sparc__) || defined (__sparc) || defined (__sgi) +#include +#else /* not sparc */ +#if (defined (MSDOS) && !defined (__TURBOC__)) || defined (WIN32) +#include +#else /* not MSDOS, or __TURBOC__ */ +#if defined(_AIX) +#include + #pragma alloca +#else /* not MSDOS, __TURBOC__, or _AIX */ +#ifdef __hpux +#ifdef __cplusplus +extern "C" { +void *alloca (unsigned int); +}; +#else /* not __cplusplus */ +void *alloca (); +#endif /* not __cplusplus */ +#endif /* __hpux */ +#endif /* not _AIX */ +#endif /* not MSDOS, or __TURBOC__ */ +#endif /* not sparc. */ +#endif /* not GNU C. */ +#endif /* alloca not defined. */ + +/* This is the parser code that is written into each bison parser + when the %semantic_parser declaration is not specified in the grammar. + It was written by Richard Stallman by simplifying the hairy parser + used when %semantic_parser is specified. */ + +/* Note: there must be only one dollar sign in this file. + It is replaced by the list of actions, each action + as one case of the switch. */ + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY -2 +#define YYEOF 0 +#define YYACCEPT return(0) +#define YYABORT return(1) +#define YYERROR goto yyerrlab1 +/* Like YYERROR except do call yyerror. + This remains here temporarily to ease the + transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ +#define YYFAIL goto yyerrlab +#define YYRECOVERING() (!!yyerrstatus) +#define YYBACKUP(token, value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { yychar = (token), yylval = (value); \ + yychar1 = YYTRANSLATE (yychar); \ + YYPOPSTACK; \ + goto yybackup; \ + } \ + else \ + { yyerror ("syntax error: cannot back up"); YYERROR; } \ +while (0) + +#define YYTERROR 1 +#define YYERRCODE 256 + +#ifndef YYPURE +#define YYLEX yylex() +#endif + +#ifdef YYPURE +#ifdef YYLSP_NEEDED +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, &yylloc, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval, &yylloc) +#endif +#else /* not YYLSP_NEEDED */ +#ifdef YYLEX_PARAM +#define YYLEX yylex(&yylval, YYLEX_PARAM) +#else +#define YYLEX yylex(&yylval) +#endif +#endif /* not YYLSP_NEEDED */ +#endif + +/* If nonreentrant, generate the variables here */ + +#ifndef YYPURE + +int yychar; /* the lookahead symbol */ +YYSTYPE yylval; /* the semantic value of the */ + /* lookahead symbol */ + +#ifdef YYLSP_NEEDED +YYLTYPE yylloc; /* location data for the lookahead */ + /* symbol */ +#endif + +int yynerrs; /* number of parse errors so far */ +#endif /* not YYPURE */ + +#if YYDEBUG != 0 +int yydebug; /* nonzero means print parse trace */ +/* Since this is uninitialized, it does not stop multiple parsers + from coexisting. */ +#endif + +/* YYINITDEPTH indicates the initial size of the parser's stacks */ + +#ifndef YYINITDEPTH +#define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH is the maximum size the stacks can grow to + (effective only if the built-in stack extension method is used). */ + +#if YYMAXDEPTH == 0 +#undef YYMAXDEPTH +#endif + +#ifndef YYMAXDEPTH +#define YYMAXDEPTH 10000 +#endif + +/* Prevent warning if -Wstrict-prototypes. */ +#ifdef __GNUC__ +int yyparse (void); +#endif + +#if __GNUC__ > 1 /* GNU C and GNU C++ define this. */ +#define __yy_memcpy(FROM,TO,COUNT) __builtin_memcpy(TO,FROM,COUNT) +#else /* not GNU C or C++ */ +#ifndef __cplusplus + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (from, to, count) + char *from; + char *to; + size_t count; +{ + register char *f = from; + register char *t = to; + register size_t i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#else /* __cplusplus */ + +/* This is the most reliable way to avoid incompatibilities + in available built-in functions on various systems. */ +static void +__yy_memcpy (char *from, char *to, size_t count) +{ + register char *f = from; + register char *t = to; + register size_t i = count; + + while (i-- > 0) + *t++ = *f++; +} + +#endif +#endif + +/* The user can define YYPARSE_PARAM as the name of an argument to be passed + into yyparse. The argument should have type void *. + It should actually point to an object. + Grammar actions can access the variable by casting it + to the proper pointer type. */ + +#ifdef YYPARSE_PARAM +#ifndef YYPARSE_PARAM_DECL +#define YYPARSE_PARAM_DECL void *YYPARSE_PARAM; +#endif +#else +#define YYPARSE_PARAM +#define YYPARSE_PARAM_DECL +#endif + +extern YY_DECL; + +int +yyparse(YYPARSE_PARAM_DECL YYPARSE_PARAM) { + register int yystate; + register int yyn; + register short *yyssp; + register YYSTYPE *yyvsp; + int yyerrstatus; /* number of tokens to shift before error messages enabled */ + int yychar1 = 0; /* lookahead token as an internal (translated) token number */ + + short yyssa[YYINITDEPTH]; /* the state stack */ + YYSTYPE yyvsa[YYINITDEPTH]; /* the semantic value stack */ + + short *yyss = yyssa; /* refer to the stacks thru separate pointers */ + YYSTYPE *yyvs = yyvsa; /* to allow yyoverflow to reallocate them elsewhere */ + +#ifdef YYLSP_NEEDED + YYLTYPE yylsa[YYINITDEPTH]; /* the location stack */ + YYLTYPE *yyls = yylsa; + YYLTYPE *yylsp; + +#define YYPOPSTACK (yyvsp--, yyssp--, yylsp--) +#else +#define YYPOPSTACK (yyvsp--, yyssp--) +#endif + + size_t yystacksize = YYINITDEPTH; + +#ifdef YYPURE + int yychar; + YYSTYPE yylval; + int yynerrs; +#ifdef YYLSP_NEEDED + YYLTYPE yylloc; +#endif +#endif + + YYSTYPE yyval; /* the variable used to return */ + /* semantic values from the action */ + /* routines */ + + int yylen; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Starting parse\n"); +#endif + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + + yyssp = yyss - 1; + yyvsp = yyvs; +#ifdef YYLSP_NEEDED + yylsp = yyls; +#endif + +/* Push a new state, which is found in yystate . */ +/* In all cases, when you get here, the value and location stacks + have just been pushed. so pushing a state here evens the stacks. */ +yynewstate: + + *++yyssp = yystate; + + if (yyssp >= yyss + yystacksize - 1) + { + /* Give user a chance to reallocate the stack */ + /* Use copies of these so that the &'s don't force the real ones into memory. */ + YYSTYPE *yyvs1 = yyvs; + short *yyss1 = yyss; +#ifdef YYLSP_NEEDED + YYLTYPE *yyls1 = yyls; +#endif + + /* Get the current used size of the three stacks, in elements. */ + size_t size = yyssp - yyss + 1; + +#ifdef yyoverflow + /* Each stack pointer address is followed by the size of + the data in use in that stack, in bytes. */ +#ifdef YYLSP_NEEDED + /* This used to be a conditional around just the two extra args, + but that might be undefined if yyoverflow is a macro. */ + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yyls1, size * sizeof (*yylsp), + &yystacksize); +#else + yyoverflow("parser stack overflow", + &yyss1, size * sizeof (*yyssp), + &yyvs1, size * sizeof (*yyvsp), + &yystacksize); +#endif + + yyss = yyss1; yyvs = yyvs1; +#ifdef YYLSP_NEEDED + yyls = yyls1; +#endif +#else /* no yyoverflow */ + /* Extend the stack our own way. */ + if (yystacksize >= YYMAXDEPTH) + { + yyerror("parser stack overflow"); + return 2; + } + yystacksize *= 2; + if (yystacksize > YYMAXDEPTH) + yystacksize = YYMAXDEPTH; + yyss = (short *) alloca (yystacksize * sizeof (*yyssp)); + __yy_memcpy ((char *)yyss1, (char *)yyss, size * sizeof (*yyssp)); + yyvs = (YYSTYPE *) alloca (yystacksize * sizeof (*yyvsp)); + __yy_memcpy ((char *)yyvs1, (char *)yyvs, size * sizeof (*yyvsp)); +#ifdef YYLSP_NEEDED + yyls = (YYLTYPE *) alloca (yystacksize * sizeof (*yylsp)); + __yy_memcpy ((char *)yyls1, (char *)yyls, size * sizeof (*yylsp)); +#endif +#endif /* no yyoverflow */ + + yyssp = yyss + size - 1; + yyvsp = yyvs + size - 1; +#ifdef YYLSP_NEEDED + yylsp = yyls + size - 1; +#endif + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Stack size increased to %d\n", yystacksize); +#endif + + if (yyssp >= yyss + yystacksize - 1) + YYABORT; + } + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Entering state %d\n", yystate); +#endif + + goto yybackup; + yybackup: + +/* Do appropriate processing given the current state. */ +/* Read a lookahead token if we need one and don't already have one. */ +/* yyresume: */ + + /* First try to decide what to do without reference to lookahead token. */ + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* yychar is either YYEMPTY or YYEOF + or a valid token in external form. */ + + if (yychar == YYEMPTY) + { +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Reading a token: "); +#endif + yychar = YYLEX; + } + + /* Convert token to internal form (in yychar1) for indexing tables with */ + + if (yychar <= 0) /* This means end of input. */ + { + yychar1 = 0; + yychar = YYEOF; /* Don't call YYLEX any more */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Now at end of input.\n"); +#endif + } + else + { + yychar1 = YYTRANSLATE(yychar); + +#if YYDEBUG != 0 + if (yydebug) + { + fprintf (stderr, "Next token is %d (%s", yychar, yytname[yychar1]); + /* Give the individual parser a way to print the precise meaning + of a token, for further debugging info. */ +#ifdef YYPRINT + YYPRINT (stderr, yychar, yylval); +#endif + fprintf (stderr, ")\n"); + } +#endif + } + + yyn += yychar1; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != yychar1) + goto yydefault; + + yyn = yytable[yyn]; + + /* yyn is what to do for this token type in this state. + Negative => reduce, -yyn is rule number. + Positive => shift, yyn is new state. + New state is final state => don't bother to shift, + just return success. + 0, or most negative number => error. */ + + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrlab; + + if (yyn == YYFINAL) + YYACCEPT; + + /* Shift the lookahead token. */ + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting token %d (%s), ", yychar, yytname[yychar1]); +#endif + + /* Discard the token being shifted unless it is eof. */ + if (yychar != YYEOF) + yychar = YYEMPTY; + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + /* count tokens shifted since error; after three, turn off error status. */ + if (yyerrstatus) yyerrstatus--; + + yystate = yyn; + goto yynewstate; + +/* Do the default action for the current state. */ +yydefault: + + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + +/* Do a reduction. yyn is the number of a rule to reduce with. */ +yyreduce: + yylen = yyr2[yyn]; + if (yylen > 0) + yyval = yyvsp[1-yylen]; /* implement default value of the action */ + +#if YYDEBUG != 0 + if (yydebug) + { + int i; + + fprintf (stderr, "Reducing via rule %d (line %d), ", + yyn, yyrline[yyn]); + + /* Print the symbols being reduced, and their result. */ + for (i = yyprhs[yyn]; yyrhs[i] > 0; i++) + fprintf (stderr, "%s ", yytname[yyrhs[i]]); + fprintf (stderr, " -> %s\n", yytname[yyr1[yyn]]); + } +#endif + +$ /* the action file gets copied in in place of this dollarsign */ + yyvsp -= yylen; + yyssp -= yylen; +#ifdef YYLSP_NEEDED + yylsp -= yylen; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + + *++yyvsp = yyval; + +#ifdef YYLSP_NEEDED + yylsp++; + if (yylen == 0) + { + yylsp->first_line = yylloc.first_line; + yylsp->first_column = yylloc.first_column; + yylsp->last_line = (yylsp-1)->last_line; + yylsp->last_column = (yylsp-1)->last_column; + yylsp->text = 0; + } + else + { + yylsp->last_line = (yylsp+yylen-1)->last_line; + yylsp->last_column = (yylsp+yylen-1)->last_column; + } +#endif + + /* Now "shift" the result of the reduction. + Determine what state that goes to, + based on the state we popped back to + and the rule number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTBASE] + *yyssp; + if (yystate >= 0 && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTBASE]; + + goto yynewstate; + +yyerrlab: /* here on detecting error */ + + if (! yyerrstatus) + /* If not already recovering from an error, report this error. */ + { + ++yynerrs; + +#ifdef YYERROR_VERBOSE + yyn = yypact[yystate]; + + if (yyn > YYFLAG && yyn < YYLAST) + { + int size = 0; + char *msg; + int x, count; + + count = 0; + /* Start X at -yyn if nec to avoid negative indexes in yycheck. */ + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + size += strlen(yytname[x]) + 15, count++; + msg = (char *) malloc(size + 15); + if (msg != 0) + { + strcpy(msg, "parse error"); + + if (count < 5) + { + count = 0; + for (x = (yyn < 0 ? -yyn : 0); + x < (sizeof(yytname) / sizeof(char *)); x++) + if (yycheck[x + yyn] == x) + { + strcat(msg, count == 0 ? ", expecting `" : " or `"); + strcat(msg, yytname[x]); + strcat(msg, "'"); + count++; + } + } + yyerror(msg); + free(msg); + } + else + yyerror ("parse error; also virtual memory exceeded"); + } + else +#endif /* YYERROR_VERBOSE */ + yyerror("parse error"); + } + + goto yyerrlab1; +yyerrlab1: /* here on error raised explicitly by an action */ + + if (yyerrstatus == 3) + { + /* if just tried and failed to reuse lookahead token after an error, discard it. */ + + /* return failure if at end of input */ + if (yychar == YYEOF) + YYABORT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Discarding token %d (%s).\n", yychar, yytname[yychar1]); +#endif + + yychar = YYEMPTY; + } + + /* Else will try to reuse lookahead token + after shifting the error token. */ + + yyerrstatus = 3; /* Each real token shifted decrements this */ + + goto yyerrhandle; + +yyerrdefault: /* current state does not do anything special for the error token. */ + +#if 0 + /* This is wrong; only states that explicitly want error tokens + should shift them. */ + yyn = yydefact[yystate]; /* If its default is to accept any token, ok. Otherwise pop it.*/ + if (yyn) goto yydefault; +#endif + +yyerrpop: /* pop the current state because it cannot handle the error token */ + + if (yyssp == yyss) YYABORT; + yyvsp--; + yystate = *--yyssp; +#ifdef YYLSP_NEEDED + yylsp--; +#endif + +#if YYDEBUG != 0 + if (yydebug) + { + short *ssp1 = yyss - 1; + fprintf (stderr, "Error: state stack now"); + while (ssp1 != yyssp) + fprintf (stderr, " %d", *++ssp1); + fprintf (stderr, "\n"); + } +#endif + +yyerrhandle: + + yyn = yypact[yystate]; + if (yyn == YYFLAG) + goto yyerrdefault; + + yyn += YYTERROR; + if (yyn < 0 || yyn > YYLAST || yycheck[yyn] != YYTERROR) + goto yyerrdefault; + + yyn = yytable[yyn]; + if (yyn < 0) + { + if (yyn == YYFLAG) + goto yyerrpop; + yyn = -yyn; + goto yyreduce; + } + else if (yyn == 0) + goto yyerrpop; + + if (yyn == YYFINAL) + YYACCEPT; + +#if YYDEBUG != 0 + if (yydebug) + fprintf(stderr, "Shifting error token, "); +#endif + + *++yyvsp = yylval; +#ifdef YYLSP_NEEDED + *++yylsp = yylloc; +#endif + + yystate = yyn; + goto yynewstate; +} diff --git a/Compiler/Tools/flex.exe b/Compiler/Tools/flex.exe new file mode 100644 index 000000000..58f10ce35 Binary files /dev/null and b/Compiler/Tools/flex.exe differ diff --git a/Compiler/Types.h b/Compiler/Types.h new file mode 100644 index 000000000..eba792c71 --- /dev/null +++ b/Compiler/Types.h @@ -0,0 +1,300 @@ +// +// Copyright (c) 2002-2010 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 _TYPES_INCLUDED +#define _TYPES_INCLUDED + +#include "Common.h" +#include "BaseTypes.h" + +// +// Need to have association of line numbers to types in a list for building structs. +// +class TType; +struct TTypeLine { + TType* type; + int line; +}; +typedef TVector TTypeList; + +inline TTypeList* NewPoolTTypeList() +{ + void* memory = GlobalPoolAllocator.allocate(sizeof(TTypeList)); + return new(memory) TTypeList; +} + +// +// This is a workaround for a problem with the yacc stack, It can't have +// types that it thinks have non-trivial constructors. It should +// just be used while recognizing the grammar, not anything else. Pointers +// could be used, but also trying to avoid lots of memory management overhead. +// +// Not as bad as it looks, there is no actual assumption that the fields +// match up or are name the same or anything like that. +// +class TPublicType { +public: + TBasicType type; + TQualifier qualifier; + TPrecision precision; + int size; // size of vector or matrix, not size of array + bool matrix; + bool array; + int arraySize; + TType* userDef; + int line; + + void setBasic(TBasicType bt, TQualifier q, int ln = 0) + { + type = bt; + qualifier = q; + precision = EbpHigh; + size = 1; + matrix = false; + array = false; + arraySize = 0; + userDef = 0; + line = ln; + } + + void setPrecision(TPrecision pcs) + { + precision = pcs; + } + + void setAggregate(int s, bool m = false) + { + size = s; + matrix = m; + } + + void setArray(bool a, int s = 0) + { + array = a; + arraySize = s; + } +}; + +typedef std::map TStructureMap; +typedef std::map::iterator TStructureMapIterator; +// +// Base class for things that have a type. +// +class TType { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + explicit TType(TBasicType t, TQualifier q = EvqTemporary, int s = 1, bool m = false, bool a = false, TPrecision p = EbpHigh) : + type(t), precision(p), qualifier(q), size(s), matrix(m), array(a), arraySize(0), + structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) + { } + explicit TType(const TPublicType &p) : + type(p.type), precision(p.precision), qualifier(p.qualifier), size(p.size), matrix(p.matrix), array(p.array), arraySize(p.arraySize), + structure(0), structureSize(0), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0), typeName(0) + { + if (p.userDef) { + structure = p.userDef->getStruct(); + typeName = NewPoolTString(p.userDef->getTypeName().c_str()); + } + } + explicit TType(TTypeList* userDef, const TString& n, TPrecision p = EbpHigh) : + type(EbtStruct), precision(p), qualifier(EvqTemporary), size(1), matrix(false), array(false), arraySize(0), + structure(userDef), maxArraySize(0), arrayInformationType(0), fieldName(0), mangled(0) { + typeName = NewPoolTString(n.c_str()); + } + explicit TType() {} + virtual ~TType() {} + + TType(const TType& type) { *this = type; } + + void copyType(const TType& copyOf, TStructureMap& remapper) + { + type = copyOf.type; + precision = copyOf.precision; + qualifier = copyOf.qualifier; + size = copyOf.size; + matrix = copyOf.matrix; + array = copyOf.array; + arraySize = copyOf.arraySize; + + TStructureMapIterator iter; + if (copyOf.structure) { + if ((iter = remapper.find(structure)) == remapper.end()) { + // create the new structure here + structure = NewPoolTTypeList(); + for (unsigned int i = 0; i < copyOf.structure->size(); ++i) { + TTypeLine typeLine; + typeLine.line = (*copyOf.structure)[i].line; + typeLine.type = (*copyOf.structure)[i].type->clone(remapper); + structure->push_back(typeLine); + } + } else { + structure = iter->second; + } + } else + structure = 0; + + fieldName = 0; + if (copyOf.fieldName) + fieldName = NewPoolTString(copyOf.fieldName->c_str()); + typeName = 0; + if (copyOf.typeName) + typeName = NewPoolTString(copyOf.typeName->c_str()); + + mangled = 0; + if (copyOf.mangled) + mangled = NewPoolTString(copyOf.mangled->c_str()); + + structureSize = copyOf.structureSize; + maxArraySize = copyOf.maxArraySize; + assert(copyOf.arrayInformationType == 0); + arrayInformationType = 0; // arrayInformationType should not be set for builtIn symbol table level + } + + TType* clone(TStructureMap& remapper) + { + TType *newType = new TType(); + newType->copyType(*this, remapper); + + return newType; + } + + virtual void setType(TBasicType t, int s, bool m, bool a, int aS = 0) + { type = t; size = s; matrix = m; array = a; arraySize = aS; } + virtual void setType(TBasicType t, int s, bool m, TType* userDef = 0) + { type = t; + size = s; + matrix = m; + if (userDef) + structure = userDef->getStruct(); + // leave array information intact. + } + virtual void setTypeName(const TString& n) { typeName = NewPoolTString(n.c_str()); } + virtual void setFieldName(const TString& n) { fieldName = NewPoolTString(n.c_str()); } + virtual const TString& getTypeName() const + { + assert(typeName); + return *typeName; + } + + virtual const TString& getFieldName() const + { + assert(fieldName); + return *fieldName; + } + + virtual TBasicType getBasicType() const { return type; } + virtual TPrecision getPrecision() const { return precision; } + virtual TQualifier getQualifier() const { return qualifier; } + virtual void changePrecision(TPrecision p) { precision = p; } + virtual void changeQualifier(TQualifier q) { qualifier = q; } + + // One-dimensional size of single instance type + virtual int getNominalSize() const { return size; } + + // Full-dimensional size of single instance of type + virtual int getInstanceSize() const + { + if (matrix) + return size * size; + else + return size; + } + + virtual bool isMatrix() const { return matrix ? true : false; } + virtual bool isArray() const { return array ? true : false; } + int getArraySize() const { return arraySize; } + void setArraySize(int s) { array = true; arraySize = s; } + void setMaxArraySize (int s) { maxArraySize = s; } + int getMaxArraySize () const { return maxArraySize; } + void clearArrayness() { array = false; arraySize = 0; maxArraySize = 0; } + void setArrayInformationType(TType* t) { arrayInformationType = t; } + TType* getArrayInformationType() const { return arrayInformationType; } + virtual bool isVector() const { return size > 1 && !matrix; } + static const char* getBasicString(TBasicType t) { + switch (t) { + case EbtVoid: return "void"; break; + case EbtFloat: return "float"; break; + case EbtInt: return "int"; break; + case EbtBool: return "bool"; break; + case EbtSampler2D: return "sampler2D"; break; + case EbtSamplerCube: return "samplerCube"; break; + case EbtStruct: return "structure"; break; + default: return "unknown type"; + } + } + const char* getBasicString() const { return TType::getBasicString(type); } + const char* getPrecisionString() const { return ::getPrecisionString(precision); } + const char* getQualifierString() const { return ::getQualifierString(qualifier); } + TTypeList* getStruct() { return structure; } + + int getObjectSize() const + { + int totalSize; + + if (getBasicType() == EbtStruct) + totalSize = getStructSize(); + else if (matrix) + totalSize = size * size; + else + totalSize = size; + + if (isArray()) + totalSize *= Max(getArraySize(), getMaxArraySize()); + + return totalSize; + } + + TTypeList* getStruct() const { return structure; } + TString& getMangledName() { + if (!mangled) { + mangled = NewPoolTString(""); + buildMangledName(*mangled); + *mangled += ';' ; + } + + return *mangled; + } + bool sameElementType(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + structure == right.structure; + } + bool operator==(const TType& right) const { + return type == right.type && + size == right.size && + matrix == right.matrix && + array == right.array && (!array || arraySize == right.arraySize) && + structure == right.structure; + // don't check the qualifier, it's not ever what's being sought after + } + bool operator!=(const TType& right) const { + return !operator==(right); + } + TString getCompleteString() const; + +protected: + void buildMangledName(TString&); + int getStructSize() const; + + TBasicType type : 6; + TPrecision precision; + TQualifier qualifier : 7; + int size : 8; // size of vector or matrix, not size of array + unsigned int matrix : 1; + unsigned int array : 1; + int arraySize; + + TTypeList* structure; // 0 unless this is a struct + mutable int structureSize; + int maxArraySize; + TType* arrayInformationType; + TString *fieldName; // for structure field names + TString *mangled; + TString *typeName; // for structure field type name +}; + +#endif // _TYPES_INCLUDED_ diff --git a/Compiler/glslang.l b/Compiler/glslang.l new file mode 100644 index 000000000..6a7623413 --- /dev/null +++ b/Compiler/glslang.l @@ -0,0 +1,605 @@ +/* +// +// Copyright (c) 2002-2010 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 +ANSI C grammar, Lex specification + +In 1985, Jeff Lee published this Lex specification together with a Yacc +grammar for the April 30, 1985 ANSI C draft. Tom Stockfisch reposted +both to net.sources in 1987; that original, as mentioned in the answer +to question 17.25 of the comp.lang.c FAQ, can be ftp'ed from ftp.uu.net, +file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar +as possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +D [0-9] +L [a-zA-Z_] +H [a-fA-F0-9] +E [Ee][+-]?{D}+ +O [0-7] + +%option nounput +%{ +#include +#include +#include "ParseHelper.h" +#include "glslang_tab.h" + +/* windows only pragma */ +#ifdef _MSC_VER +#pragma warning(disable : 4102) +#endif + +int yy_input(char* buf, int max_size); +TSourceLoc yylineno; + +#ifdef _WIN32 + extern int yyparse(TParseContext&); + #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext) +#else + extern int yyparse(void*); + #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal) + #define parseContext (*((TParseContext*)(parseContextLocal))) +#endif + +#define YY_INPUT(buf,result,max_size) (result = yy_input(buf, max_size)) + +%} + +%option noyywrap +%option never-interactive +%option outfile="Gen_glslang.cpp" +%x FIELDS + + +%% +<*>"//"[^\n]*"\n" { /* ?? carriage and/or line-feed? */ }; + +"invariant" { pyylval->lex.line = yylineno; return(INVARIANT); } +"highp" { pyylval->lex.line = yylineno; return(HIGH_PRECISION); } +"mediump" { pyylval->lex.line = yylineno; return(MEDIUM_PRECISION); } +"lowp" { pyylval->lex.line = yylineno; return(LOW_PRECISION); } +"precision" { pyylval->lex.line = yylineno; return(PRECISION); } + +"attribute" { pyylval->lex.line = yylineno; return(ATTRIBUTE); } +"const" { pyylval->lex.line = yylineno; return(CONST_QUAL); } +"uniform" { pyylval->lex.line = yylineno; return(UNIFORM); } +"varying" { pyylval->lex.line = yylineno; return(VARYING); } + +"break" { pyylval->lex.line = yylineno; return(BREAK); } +"continue" { pyylval->lex.line = yylineno; return(CONTINUE); } +"do" { pyylval->lex.line = yylineno; return(DO); } +"for" { pyylval->lex.line = yylineno; return(FOR); } +"while" { pyylval->lex.line = yylineno; return(WHILE); } + +"if" { pyylval->lex.line = yylineno; return(IF); } +"else" { pyylval->lex.line = yylineno; return(ELSE); } + +"in" { pyylval->lex.line = yylineno; return(IN_QUAL); } +"out" { pyylval->lex.line = yylineno; return(OUT_QUAL); } +"inout" { pyylval->lex.line = yylineno; return(INOUT_QUAL); } + +"float" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(FLOAT_TYPE); } +"int" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(INT_TYPE); } +"void" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(VOID_TYPE); } +"bool" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(BOOL_TYPE); } +"true" { pyylval->lex.line = yylineno; pyylval->lex.b = true; return(BOOLCONSTANT); } +"false" { pyylval->lex.line = yylineno; pyylval->lex.b = false; return(BOOLCONSTANT); } + +"discard" { pyylval->lex.line = yylineno; return(DISCARD); } +"return" { pyylval->lex.line = yylineno; return(RETURN); } + +"mat2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX2); } +"mat3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX3); } +"mat4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return(MATRIX4); } + +"vec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC2); } +"vec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC3); } +"vec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (VEC4); } +"ivec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC2); } +"ivec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC3); } +"ivec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (IVEC4); } +"bvec2" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC2); } +"bvec3" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC3); } +"bvec4" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return (BVEC4); } + +"sampler2D" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLER2D; } +"samplerCube" { pyylval->lex.line = yylineno; parseContext.lexAfterType = true; return SAMPLERCUBE; } + +"struct" { pyylval->lex.line = yylineno; return(STRUCT); } + +"asm" { PaReservedWord(); return 0; } + +"class" { PaReservedWord(); return 0; } +"union" { PaReservedWord(); return 0; } +"enum" { PaReservedWord(); return 0; } +"typedef" { PaReservedWord(); return 0; } +"template" { PaReservedWord(); return 0; } +"this" { PaReservedWord(); return 0; } +"packed" { PaReservedWord(); return 0; } + +"goto" { PaReservedWord(); return 0; } +"switch" { PaReservedWord(); return 0; } +"default" { PaReservedWord(); return 0; } + +"inline" { PaReservedWord(); return 0; } +"noinline" { PaReservedWord(); return 0; } +"volatile" { PaReservedWord(); return 0; } +"public" { PaReservedWord(); return 0; } +"static" { PaReservedWord(); return 0; } +"extern" { PaReservedWord(); return 0; } +"external" { PaReservedWord(); return 0; } +"interface" { PaReservedWord(); return 0; } + +"long" { PaReservedWord(); return 0; } +"short" { PaReservedWord(); return 0; } +"double" { PaReservedWord(); return 0; } +"half" { PaReservedWord(); return 0; } +"fixed" { PaReservedWord(); return 0; } +"unsigned" { PaReservedWord(); return 0; } + +"input" { PaReservedWord(); return 0; } +"output" { PaReservedWord(); return 0; } + +"hvec2" { PaReservedWord(); return 0; } +"hvec3" { PaReservedWord(); return 0; } +"hvec4" { PaReservedWord(); return 0; } +"fvec2" { PaReservedWord(); return 0; } +"fvec3" { PaReservedWord(); return 0; } +"fvec4" { PaReservedWord(); return 0; } +"dvec2" { PaReservedWord(); return 0; } +"dvec3" { PaReservedWord(); return 0; } +"dvec4" { PaReservedWord(); return 0; } + +"sizeof" { PaReservedWord(); return 0; } +"cast" { PaReservedWord(); return 0; } + +"namespace" { PaReservedWord(); return 0; } +"using" { PaReservedWord(); return 0; } + +{L}({L}|{D})* { + pyylval->lex.line = yylineno; + pyylval->lex.string = NewPoolTString(yytext); + return PaIdentOrType(*pyylval->lex.string, parseContext, pyylval->lex.symbol); +} + +0[xX]{H}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{O}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } +0{D}+ { pyylval->lex.line = yylineno; parseContext.error(yylineno, "Invalid Octal number.", yytext, "", ""); parseContext.recover(); return 0;} +{D}+ { pyylval->lex.line = yylineno; pyylval->lex.i = strtol(yytext, 0, 0); return(INTCONSTANT); } + +{D}+{E} { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } +{D}+"."{D}*({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } +"."{D}+({E})? { pyylval->lex.line = yylineno; pyylval->lex.f = static_cast(atof(yytext)); return(FLOATCONSTANT); } + +"/*" { int ret = PaParseComment(pyylval->lex.line, parseContext); if (!ret) return ret; } + +"+=" { pyylval->lex.line = yylineno; return(ADD_ASSIGN); } +"-=" { pyylval->lex.line = yylineno; return(SUB_ASSIGN); } +"*=" { pyylval->lex.line = yylineno; return(MUL_ASSIGN); } +"/=" { pyylval->lex.line = yylineno; return(DIV_ASSIGN); } +"%=" { pyylval->lex.line = yylineno; return(MOD_ASSIGN); } +"<<=" { pyylval->lex.line = yylineno; return(LEFT_ASSIGN); } +">>=" { pyylval->lex.line = yylineno; return(RIGHT_ASSIGN); } +"&=" { pyylval->lex.line = yylineno; return(AND_ASSIGN); } +"^=" { pyylval->lex.line = yylineno; return(XOR_ASSIGN); } +"|=" { pyylval->lex.line = yylineno; return(OR_ASSIGN); } + +"++" { pyylval->lex.line = yylineno; return(INC_OP); } +"--" { pyylval->lex.line = yylineno; return(DEC_OP); } +"&&" { pyylval->lex.line = yylineno; return(AND_OP); } +"||" { pyylval->lex.line = yylineno; return(OR_OP); } +"^^" { pyylval->lex.line = yylineno; return(XOR_OP); } +"<=" { pyylval->lex.line = yylineno; return(LE_OP); } +">=" { pyylval->lex.line = yylineno; return(GE_OP); } +"==" { pyylval->lex.line = yylineno; return(EQ_OP); } +"!=" { pyylval->lex.line = yylineno; return(NE_OP); } +"<<" { pyylval->lex.line = yylineno; return(LEFT_OP); } +">>" { pyylval->lex.line = yylineno; return(RIGHT_OP); } +";" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(SEMICOLON); } +("{"|"<%") { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(LEFT_BRACE); } +("}"|"%>") { pyylval->lex.line = yylineno; return(RIGHT_BRACE); } +"," { pyylval->lex.line = yylineno; if (parseContext.inTypeParen) parseContext.lexAfterType = false; return(COMMA); } +":" { pyylval->lex.line = yylineno; return(COLON); } +"=" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; return(EQUAL); } +"(" { pyylval->lex.line = yylineno; parseContext.lexAfterType = false; parseContext.inTypeParen = true; return(LEFT_PAREN); } +")" { pyylval->lex.line = yylineno; parseContext.inTypeParen = false; return(RIGHT_PAREN); } +("["|"<:") { pyylval->lex.line = yylineno; return(LEFT_BRACKET); } +("]"|":>") { pyylval->lex.line = yylineno; return(RIGHT_BRACKET); } +"." { BEGIN(FIELDS); return(DOT); } +"!" { pyylval->lex.line = yylineno; return(BANG); } +"-" { pyylval->lex.line = yylineno; return(DASH); } +"~" { pyylval->lex.line = yylineno; return(TILDE); } +"+" { pyylval->lex.line = yylineno; return(PLUS); } +"*" { pyylval->lex.line = yylineno; return(STAR); } +"/" { pyylval->lex.line = yylineno; return(SLASH); } +"%" { pyylval->lex.line = yylineno; return(PERCENT); } +"<" { pyylval->lex.line = yylineno; return(LEFT_ANGLE); } +">" { pyylval->lex.line = yylineno; return(RIGHT_ANGLE); } +"|" { pyylval->lex.line = yylineno; return(VERTICAL_BAR); } +"^" { pyylval->lex.line = yylineno; return(CARET); } +"&" { pyylval->lex.line = yylineno; return(AMPERSAND); } +"?" { pyylval->lex.line = yylineno; return(QUESTION); } + +{L}({L}|{D})* { +BEGIN(INITIAL); + pyylval->lex.line = yylineno; + pyylval->lex.string = NewPoolTString(yytext); + return FIELD_SELECTION; } +[ \t\v\f\r] {} + +[ \t\v\n\f\r] { } +<*><> { (&parseContext)->AfterEOF = true; yy_delete_buffer(YY_CURRENT_BUFFER); yyterminate();} +<*>. { parseContext.infoSink.info << "FLEX: Unknown char " << yytext << "\n"; + return 0; } + +%% + + +//Including Pre-processor. +extern "C" { + #include "./preprocessor/preprocess.h" +} + +// +// The YY_INPUT macro just calls this. Maybe this could be just put into +// the macro directly. +// + +int yy_input(char* buf, int max_size) +{ + int len; + + if ((len = yylex_CPP(buf, max_size)) == 0) + return 0; + if (len >= max_size) + YY_FATAL_ERROR( "input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); + + buf[len] = ' '; + return len+1; +} + + +// +// Parse an array of strings using yyparse. We set up globals used by +// yywrap. +// +// Returns 0 for success, as per yyparse(). +// +int PaParseStrings(char* argv[], int strLen[], int argc, TParseContext& parseContextLocal) +{ + int argv0len; + + ScanFromString(argv[0]); + + //Storing the Current Compiler Parse context into the cpp structure. + cpp->pC = (void*)&parseContextLocal; + + if (!argv || argc == 0) + return 1; + + for (int i = 0; i < argc; ++i) { + if (!argv[i]) { + parseContextLocal.error(0, "Null shader source string", "", ""); + parseContextLocal.recover(); + return 1; + } + } + + if (!strLen) { + argv0len = (int) strlen(argv[0]); + strLen = &argv0len; + } + yyrestart(0); + (&parseContextLocal)->AfterEOF = false; + cpp->PaWhichStr = 0; + cpp->PaArgv = argv; + cpp->PaArgc = argc; + cpp->PaStrLen = strLen; + cpp->notAVersionToken = 0; + yylineno = 1; + + if (*cpp->PaStrLen >= 0) { + int ret; + #ifdef _WIN32 + ret = yyparse(parseContextLocal); + #else + ret = yyparse((void*)(&parseContextLocal)); + #endif + if (cpp->CompileError == 1 || parseContextLocal.recoveredFromError || parseContextLocal.numErrors > 0) + return 1; + else + return 0; + } + else + return 0; +} + +void yyerror(char *s) +{ + if (((TParseContext *)cpp->pC)->AfterEOF) { + if (cpp->tokensBeforeEOF == 1) { + GlobalParseContext->error(yylineno, "syntax error", "pre-mature EOF", s, ""); + GlobalParseContext->recover(); + } + } else { + GlobalParseContext->error(yylineno, "syntax error", yytext, s, ""); + GlobalParseContext->recover(); + } +} + +void PaReservedWord() +{ + GlobalParseContext->error(yylineno, "Reserved word.", yytext, "", ""); + GlobalParseContext->recover(); +} + +int PaIdentOrType(TString& id, TParseContext& parseContextLocal, TSymbol*& symbol) +{ + symbol = parseContextLocal.symbolTable.find(id); + if (parseContextLocal.lexAfterType == false && symbol && symbol->isVariable()) { + TVariable* variable = static_cast(symbol); + if (variable->isUserType()) { + parseContextLocal.lexAfterType = true; + return TYPE_NAME; + } + } + + return IDENTIFIER; +} + +int PaParseComment(int &lineno, TParseContext& parseContextLocal) +{ + int transitionFlag = 0; + int nextChar; + + while (transitionFlag != 2) { + nextChar = yyinput(); + if (nextChar == '\n') + lineno++; + switch (nextChar) { + case '*' : + transitionFlag = 1; + break; + case '/' : /* if star is the previous character, then it is the end of comment */ + if (transitionFlag == 1) { + return 1 ; + } + break; + case EOF : + /* Raise error message here */ + parseContextLocal.error(yylineno, "End of shader found before end of comment.", "", "", ""); + GlobalParseContext->recover(); + return YY_NULL; + default : /* Any other character will be a part of the comment */ + transitionFlag = 0; + } + } + return 1; +} + +extern "C" { + +void CPPDebugLogMsg(const char *msg) +{ + ((TParseContext *)cpp->pC)->infoSink.debug.message(EPrefixNone, msg); +} + +void CPPWarningToInfoLog(const char *msg) +{ + ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg, yylineno); +} + +void CPPShInfoLogMsg(const char *msg) +{ + ((TParseContext *)cpp->pC)->error(yylineno,"", "",msg,""); + GlobalParseContext->recover(); +} + +void CPPErrorToInfoLog(char *msg) +{ + ((TParseContext *)cpp->pC)->error(yylineno,"syntax error", "",msg,""); + GlobalParseContext->recover(); +} + +void SetLineNumber(int line) +{ + yylineno &= ~SourceLocLineMask; + yylineno |= line; +} + +void SetStringNumber(int string) +{ + yylineno = (string << SourceLocStringShift) | (yylineno & SourceLocLineMask); +} + +int GetStringNumber(void) +{ + return yylineno >> 16; +} + +int GetLineNumber(void) +{ + return yylineno & SourceLocLineMask; +} + +void IncLineNumber(void) +{ + if ((yylineno & SourceLocLineMask) <= SourceLocLineMask) + ++yylineno; +} + +void DecLineNumber(void) +{ + if ((yylineno & SourceLocLineMask) > 0) + --yylineno; +} + +void HandlePragma(const char **tokens, int numTokens) +{ + if (!strcmp(tokens[0], "optimize")) { + if (numTokens != 4) { + CPPShInfoLogMsg("optimize pragma syntax is incorrect"); + return; + } + + if (strcmp(tokens[1], "(")) { + CPPShInfoLogMsg("\"(\" expected after 'optimize' keyword"); + return; + } + + if (!strcmp(tokens[2], "on")) + ((TParseContext *)cpp->pC)->contextPragma.optimize = true; + else if (!strcmp(tokens[2], "off")) + ((TParseContext *)cpp->pC)->contextPragma.optimize = false; + else { + CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'optimize' pragma"); + return; + } + + if (strcmp(tokens[3], ")")) { + CPPShInfoLogMsg("\")\" expected to end 'optimize' pragma"); + return; + } + } else if (!strcmp(tokens[0], "debug")) { + if (numTokens != 4) { + CPPShInfoLogMsg("debug pragma syntax is incorrect"); + return; + } + + if (strcmp(tokens[1], "(")) { + CPPShInfoLogMsg("\"(\" expected after 'debug' keyword"); + return; + } + + if (!strcmp(tokens[2], "on")) + ((TParseContext *)cpp->pC)->contextPragma.debug = true; + else if (!strcmp(tokens[2], "off")) + ((TParseContext *)cpp->pC)->contextPragma.debug = false; + else { + CPPShInfoLogMsg("\"on\" or \"off\" expected after '(' for 'debug' pragma"); + return; + } + + if (strcmp(tokens[3], ")")) { + CPPShInfoLogMsg("\")\" expected to end 'debug' pragma"); + return; + } + } else { + +#ifdef PRAGMA_TABLE + // + // implementation specific pragma + // use ((TParseContext *)cpp->pC)->contextPragma.pragmaTable to store the information about pragma + // For now, just ignore the pragma that the implementation cannot recognize + // An Example of one such implementation for a pragma that has a syntax like + // #pragma pragmaname(pragmavalue) + // This implementation stores the current pragmavalue against the pragma name in pragmaTable. + // + if (numTokens == 4 && !strcmp(tokens[1], "(") && !strcmp(tokens[3], ")")) { + TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; + TPragmaTable::iterator iter; + iter = pragmaTable.find(TString(tokens[0])); + if (iter != pragmaTable.end()) { + iter->second = tokens[2]; + } else { + pragmaTable[tokens[0]] = tokens[2]; + } + } else if (numTokens >= 2) { + TPragmaTable& pragmaTable = ((TParseContext *)cpp->pC)->contextPragma.pragmaTable; + TPragmaTable::iterator iter; + iter = pragmaTable.find(TString(tokens[0])); + if (iter != pragmaTable.end()) { + iter->second = tokens[1]; + } else { + pragmaTable[tokens[0]] = tokens[1]; + } + } +#endif // PRAGMA_TABLE + } +} + +void StoreStr(char *string) +{ + TString strSrc; + strSrc = TString(string); + + ((TParseContext *)cpp->pC)->HashErrMsg = ((TParseContext *)cpp->pC)->HashErrMsg + " " + strSrc; +} + +const char* GetStrfromTStr(void) +{ + cpp->ErrMsg = (((TParseContext *)cpp->pC)->HashErrMsg).c_str(); + return cpp->ErrMsg; +} + +void ResetTString(void) +{ + ((TParseContext *)cpp->pC)->HashErrMsg = ""; +} + +TBehavior GetBehavior(const char* behavior) +{ + if (!strcmp("require", behavior)) + return EBhRequire; + else if (!strcmp("enable", behavior)) + return EBhEnable; + else if (!strcmp("disable", behavior)) + return EBhDisable; + else if (!strcmp("warn", behavior)) + return EBhWarn; + else { + CPPShInfoLogMsg((TString("behavior '") + behavior + "' is not supported").c_str()); + return EBhDisable; + } +} + +void updateExtensionBehavior(const char* extName, const char* behavior) +{ + TBehavior behaviorVal = GetBehavior(behavior); + TMap:: iterator iter; + TString msg; + + // special cased for all extension + if (!strcmp(extName, "all")) { + if (behaviorVal == EBhRequire || behaviorVal == EBhEnable) { + CPPShInfoLogMsg("extension 'all' cannot have 'require' or 'enable' behavior"); + return; + } else { + for (iter = ((TParseContext *)cpp->pC)->extensionBehavior.begin(); iter != ((TParseContext *)cpp->pC)->extensionBehavior.end(); ++iter) + iter->second = behaviorVal; + } + } else { + iter = ((TParseContext *)cpp->pC)->extensionBehavior.find(TString(extName)); + if (iter == ((TParseContext *)cpp->pC)->extensionBehavior.end()) { + switch (behaviorVal) { + case EBhRequire: + CPPShInfoLogMsg((TString("extension '") + extName + "' is not supported").c_str()); + break; + case EBhEnable: + case EBhWarn: + case EBhDisable: + msg = TString("extension '") + extName + "' is not supported"; + ((TParseContext *)cpp->pC)->infoSink.info.message(EPrefixWarning, msg.c_str(), yylineno); + break; + } + return; + } else + iter->second = behaviorVal; + } +} + +} // extern "C" + +void setInitialState() +{ + yy_start = 1; +} diff --git a/Compiler/glslang.y b/Compiler/glslang.y new file mode 100644 index 000000000..ec2603e94 --- /dev/null +++ b/Compiler/glslang.y @@ -0,0 +1,2204 @@ +// +// Copyright (c) 2002-2010 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. +// + +/** + * This is bison grammar and production code for parsing the OpenGL 2.0 shading + * languages. + */ +%{ + +/* Based on: +ANSI C Yacc grammar + +In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a +matching Lex specification) for the April 30, 1985 draft version of the +ANSI C standard. Tom Stockfisch reposted it to net.sources in 1987; that +original, as mentioned in the answer to question 17.25 of the comp.lang.c +FAQ, can be ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z. + +I intend to keep this version as close to the current C Standard grammar as +possible; please let me know if you discover discrepancies. + +Jutta Degener, 1995 +*/ + +#include "SymbolTable.h" +#include "ParseHelper.h" +#include "ShaderLang.h" + +#ifdef _WIN32 + #define YYPARSE_PARAM parseContext + #define YYPARSE_PARAM_DECL TParseContext& + #define YY_DECL int yylex(YYSTYPE* pyylval, TParseContext& parseContext) + #define YYLEX_PARAM parseContext +#else + #define YYPARSE_PARAM parseContextLocal + #define parseContext (*((TParseContext*)(parseContextLocal))) + #define YY_DECL int yylex(YYSTYPE* pyylval, void* parseContextLocal) + #define YYLEX_PARAM (void*)(parseContextLocal) + extern void yyerror(char*); +#endif + +#define FRAG_VERT_ONLY(S, L) { \ + if (parseContext.language != EShLangFragment && \ + parseContext.language != EShLangVertex) { \ + parseContext.error(L, " supported in vertex/fragment shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define VERTEX_ONLY(S, L) { \ + if (parseContext.language != EShLangVertex) { \ + parseContext.error(L, " supported in vertex shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define FRAG_ONLY(S, L) { \ + if (parseContext.language != EShLangFragment) { \ + parseContext.error(L, " supported in fragment shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define PACK_ONLY(S, L) { \ + if (parseContext.language != EShLangPack) { \ + parseContext.error(L, " supported in pack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define UNPACK_ONLY(S, L) { \ + if (parseContext.language != EShLangUnpack) { \ + parseContext.error(L, " supported in unpack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} + +#define PACK_UNPACK_ONLY(S, L) { \ + if (parseContext.language != EShLangUnpack && \ + parseContext.language != EShLangPack) { \ + parseContext.error(L, " supported in pack/unpack shaders only ", S, "", ""); \ + parseContext.recover(); \ + } \ +} +%} +%union { + struct { + TSourceLoc line; + union { + TString *string; + float f; + int i; + bool b; + }; + TSymbol* symbol; + } lex; + struct { + TSourceLoc line; + TOperator op; + union { + TIntermNode* intermNode; + TIntermNodePair nodePair; + TIntermTyped* intermTypedNode; + TIntermAggregate* intermAggregate; + }; + union { + TPublicType type; + TPrecision precision; + TQualifier qualifier; + TFunction* function; + TParameter param; + TTypeLine typeLine; + TTypeList* typeList; + }; + } interm; +} + +%{ +#ifndef _WIN32 + extern int yylex(YYSTYPE*, void*); +#endif +%} + +%pure_parser /* Just in case is called from multiple threads */ +%expect 1 /* One shift reduce conflict because of if | else */ +%token INVARIANT HIGH_PRECISION MEDIUM_PRECISION LOW_PRECISION PRECISION +%token ATTRIBUTE CONST_QUAL BOOL_TYPE FLOAT_TYPE INT_TYPE +%token BREAK CONTINUE DO ELSE FOR IF DISCARD RETURN +%token BVEC2 BVEC3 BVEC4 IVEC2 IVEC3 IVEC4 VEC2 VEC3 VEC4 +%token MATRIX2 MATRIX3 MATRIX4 IN_QUAL OUT_QUAL INOUT_QUAL UNIFORM VARYING +%token STRUCT VOID_TYPE WHILE +%token SAMPLER2D SAMPLERCUBE + +%token IDENTIFIER TYPE_NAME FLOATCONSTANT INTCONSTANT BOOLCONSTANT +%token FIELD_SELECTION +%token LEFT_OP RIGHT_OP +%token INC_OP DEC_OP LE_OP GE_OP EQ_OP NE_OP +%token AND_OP OR_OP XOR_OP MUL_ASSIGN DIV_ASSIGN ADD_ASSIGN +%token MOD_ASSIGN LEFT_ASSIGN RIGHT_ASSIGN AND_ASSIGN XOR_ASSIGN OR_ASSIGN +%token SUB_ASSIGN + +%token LEFT_PAREN RIGHT_PAREN LEFT_BRACKET RIGHT_BRACKET LEFT_BRACE RIGHT_BRACE DOT +%token COMMA COLON EQUAL SEMICOLON BANG DASH TILDE PLUS STAR SLASH PERCENT +%token LEFT_ANGLE RIGHT_ANGLE VERTICAL_BAR CARET AMPERSAND QUESTION + +%type assignment_operator unary_operator +%type variable_identifier primary_expression postfix_expression +%type expression integer_expression assignment_expression +%type unary_expression multiplicative_expression additive_expression +%type relational_expression equality_expression +%type conditional_expression constant_expression +%type logical_or_expression logical_xor_expression logical_and_expression +%type shift_expression and_expression exclusive_or_expression inclusive_or_expression +%type function_call initializer condition conditionopt + +%type translation_unit function_definition +%type statement simple_statement +%type statement_list compound_statement +%type declaration_statement selection_statement expression_statement +%type declaration external_declaration +%type for_init_statement compound_statement_no_new_scope +%type selection_rest_statement for_rest_statement +%type iteration_statement jump_statement statement_no_new_scope +%type single_declaration init_declarator_list + +%type parameter_declaration parameter_declarator parameter_type_specifier +%type parameter_qualifier + +%type precision_qualifier +%type type_qualifier fully_specified_type type_specifier +%type type_specifier_no_prec type_specifier_nonarray +%type struct_specifier +%type struct_declarator +%type struct_declarator_list struct_declaration struct_declaration_list +%type function_header function_declarator function_identifier +%type function_header_with_parameters function_call_header +%type function_call_header_with_parameters function_call_header_no_parameters function_call_generic function_prototype +%type function_call_or_method + +%start translation_unit +%% + +variable_identifier + : IDENTIFIER { + // The symbol table search was done in the lexical phase + const TSymbol* symbol = $1.symbol; + const TVariable* variable; + if (symbol == 0) { + parseContext.error($1.line, "undeclared identifier", $1.string->c_str(), ""); + parseContext.recover(); + TType type(EbtFloat); + TVariable* fakeVariable = new TVariable($1.string, type); + parseContext.symbolTable.insert(*fakeVariable); + variable = fakeVariable; + } else { + // This identifier can only be a variable type symbol + if (! symbol->isVariable()) { + parseContext.error($1.line, "variable expected", $1.string->c_str(), ""); + parseContext.recover(); + } + variable = static_cast(symbol); + } + + // don't delete $1.string, it's used by error recovery, and the pool + // pop will reclaim the memory + + if (variable->getType().getQualifier() == EvqConst ) { + constUnion* constArray = variable->getConstPointer(); + TType t(variable->getType()); + $$ = parseContext.intermediate.addConstantUnion(constArray, t, $1.line); + } else + $$ = parseContext.intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line); + } + ; + +primary_expression + : variable_identifier { + $$ = $1; + } + | INTCONSTANT { + // + // INT_TYPE is only 16-bit plus sign bit for vertex/fragment shaders, + // check for overflow for constants + // + if (abs($1.i) >= (1 << 16)) { + parseContext.error($1.line, " integer constant overflow", "", ""); + parseContext.recover(); + } + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst($1.i); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line); + } + | FLOATCONSTANT { + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst($1.f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line); + } + | BOOLCONSTANT { + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst($1.b); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $1.line); + } + | LEFT_PAREN expression RIGHT_PAREN { + $$ = $2; + } + ; + +postfix_expression + : primary_expression { + $$ = $1; + } + | postfix_expression LEFT_BRACKET integer_expression RIGHT_BRACKET { + if (!$1->isArray() && !$1->isMatrix() && !$1->isVector()) { + if ($1->getAsSymbolNode()) + parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", $1->getAsSymbolNode()->getSymbol().c_str(), ""); + else + parseContext.error($2.line, " left of '[' is not of type array, matrix, or vector ", "expression", ""); + parseContext.recover(); + } + if ($1->getType().getQualifier() == EvqConst && $3->getQualifier() == EvqConst) { + if ($1->isArray()) { // constant folding for arrays + $$ = parseContext.addConstArrayNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } else if ($1->isVector()) { // constant folding for vectors + TVectorFields fields; + fields.num = 1; + fields.offsets[0] = $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(); // need to do it this way because v.xy sends fields integer array + $$ = parseContext.addConstVectorNode(fields, $1, $2.line); + } else if ($1->isMatrix()) { // constant folding for matrices + $$ = parseContext.addConstMatrixNode($3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), $1, $2.line); + } + } else { + if ($3->getQualifier() == EvqConst) { + if (($1->isVector() || $1->isMatrix()) && $1->getType().getNominalSize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() && !$1->isArray() ) { + parseContext.error($2.line, "", "[", "field selection out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()); + parseContext.recover(); + } else { + if ($1->isArray()) { + if ($1->getType().getArraySize() == 0) { + if ($1->getType().getMaxArraySize() <= $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()) { + if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst(), true, $2.line)) + parseContext.recover(); + } else { + if (parseContext.arraySetMaxSize($1->getAsSymbolNode(), $1->getTypePointer(), 0, false, $2.line)) + parseContext.recover(); + } + } else if ( $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst() >= $1->getType().getArraySize()) { + parseContext.error($2.line, "", "[", "array index out of range '%d'", $3->getAsConstantUnion()->getUnionArrayPointer()->getIConst()); + parseContext.recover(); + } + } + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, $3, $2.line); + } + } else { + if ($1->isArray() && $1->getType().getArraySize() == 0) { + parseContext.error($2.line, "", "[", "array must be redeclared with a size before being indexed with a variable"); + parseContext.recover(); + } + + $$ = parseContext.intermediate.addIndex(EOpIndexIndirect, $1, $3, $2.line); + } + } + if ($$ == 0) { + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst(0.0f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $2.line); + } else if ($1->isArray()) { + if ($1->getType().getStruct()) + $$->setType(TType($1->getType().getStruct(), $1->getType().getTypeName())); + else + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize(), $1->isMatrix())); + + if ($1->getType().getQualifier() == EvqConst) + $$->getTypePointer()->changeQualifier(EvqConst); + } else if ($1->isMatrix() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), EvqConst, $1->getNominalSize())); + else if ($1->isMatrix()) + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize())); + else if ($1->isVector() && $1->getType().getQualifier() == EvqConst) + $$->setType(TType($1->getBasicType(), EvqConst)); + else if ($1->isVector()) + $$->setType(TType($1->getBasicType(), EvqTemporary)); + else + $$->setType($1->getType()); + } + | function_call { + $$ = $1; + } + | postfix_expression DOT FIELD_SELECTION { + if ($1->isArray()) { + parseContext.error($3.line, "cannot apply dot operator to an array", ".", ""); + parseContext.recover(); + } + + if ($1->isVector()) { + TVectorFields fields; + if (! parseContext.parseVectorFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.num = 1; + fields.offsets[0] = 0; + parseContext.recover(); + } + + if ($1->getType().getQualifier() == EvqConst) { // constant folding for vector fields + $$ = parseContext.addConstVectorNode(fields, $1, $3.line); + if ($$ == 0) { + parseContext.recover(); + $$ = $1; + } + else + $$->setType(TType($1->getBasicType(), EvqConst, (int) (*$3.string).size())); + } else { + if (fields.num == 1) { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(fields.offsets[0]); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType())); + } else { + TString vectorString = *$3.string; + TIntermTyped* index = parseContext.intermediate.addSwizzle(fields, $3.line); + $$ = parseContext.intermediate.addIndex(EOpVectorSwizzle, $1, index, $2.line); + $$->setType(TType($1->getBasicType(),EvqTemporary, (int) vectorString.size())); + } + } + } else if ($1->isMatrix()) { + TMatrixFields fields; + if (! parseContext.parseMatrixFields(*$3.string, $1->getNominalSize(), fields, $3.line)) { + fields.wholeRow = false; + fields.wholeCol = false; + fields.row = 0; + fields.col = 0; + parseContext.recover(); + } + + if (fields.wholeRow || fields.wholeCol) { + parseContext.error($2.line, " non-scalar fields not implemented yet", ".", ""); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(0); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType(), EvqTemporary, $1->getNominalSize())); + } else { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(fields.col * $1->getNominalSize() + fields.row); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirect, $1, index, $2.line); + $$->setType(TType($1->getBasicType())); + } + } else if ($1->getBasicType() == EbtStruct) { + bool fieldFound = false; + TTypeList* fields = $1->getType().getStruct(); + if (fields == 0) { + parseContext.error($2.line, "structure has no fields", "Internal Error", ""); + parseContext.recover(); + $$ = $1; + } else { + unsigned int i; + for (i = 0; i < fields->size(); ++i) { + if ((*fields)[i].type->getFieldName() == *$3.string) { + fieldFound = true; + break; + } + } + if (fieldFound) { + if ($1->getType().getQualifier() == EvqConst) { + $$ = parseContext.addConstStruct(*$3.string, $1, $2.line); + if ($$ == 0) { + parseContext.recover(); + $$ = $1; + } + else { + $$->setType(*(*fields)[i].type); + // change the qualifier of the return type, not of the structure field + // as the structure definition is shared between various structures. + $$->getTypePointer()->changeQualifier(EvqConst); + } + } else { + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst(i); + TIntermTyped* index = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $3.line); + $$ = parseContext.intermediate.addIndex(EOpIndexDirectStruct, $1, index, $2.line); + $$->setType(*(*fields)[i].type); + } + } else { + parseContext.error($2.line, " no such field in structure", $3.string->c_str(), ""); + parseContext.recover(); + $$ = $1; + } + } + } else { + parseContext.error($2.line, " field selection requires structure, vector, or matrix on left hand side", $3.string->c_str(), ""); + parseContext.recover(); + $$ = $1; + } + // don't delete $3.string, it's from the pool + } + | postfix_expression INC_OP { + if (parseContext.lValueErrorCheck($2.line, "++", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPostIncrement, $1, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($2.line, "++", $1->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | postfix_expression DEC_OP { + if (parseContext.lValueErrorCheck($2.line, "--", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPostDecrement, $1, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($2.line, "--", $1->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +integer_expression + : expression { + if (parseContext.integerErrorCheck($1, "[]")) + parseContext.recover(); + $$ = $1; + } + ; + +function_call + : function_call_or_method { + TFunction* fnCall = $1.function; + TOperator op = fnCall->getBuiltInOp(); + + if (op == EOpArrayLength) { + if ($1.intermNode->getAsTyped() == 0 || $1.intermNode->getAsTyped()->getType().getArraySize() == 0) { + parseContext.error($1.line, "", fnCall->getName().c_str(), "array must be declared with a size before using this method"); + parseContext.recover(); + } + + constUnion *unionArray = new constUnion[1]; + unionArray->setIConst($1.intermNode->getAsTyped()->getType().getArraySize()); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtInt, EvqConst), $1.line); + } else if (op != EOpNull) { + // + // Then this should be a constructor. + // Don't go through the symbol table for constructors. + // Their parameters will be verified algorithmically. + // + TType type(EbtVoid); // use this to get the type back + if (parseContext.constructorErrorCheck($1.line, $1.intermNode, *fnCall, op, &type)) { + $$ = 0; + } else { + // + // It's a constructor, of type 'type'. + // + $$ = parseContext.addConstructor($1.intermNode, &type, op, fnCall, $1.line); + } + + if ($$ == 0) { + parseContext.recover(); + $$ = parseContext.intermediate.setAggregateOperator(0, op, $1.line); + } + $$->setType(type); + } else { + // + // Not a constructor. Find it in the symbol table. + // + const TFunction* fnCandidate; + bool builtIn; + fnCandidate = parseContext.findFunction($1.line, fnCall, &builtIn); + if (fnCandidate) { + // + // A declared function. But, it might still map to a built-in + // operation. + // + op = fnCandidate->getBuiltInOp(); + if (builtIn && op != EOpNull) { + // + // A function call mapped to a built-in operation. + // + if (fnCandidate->getParamCount() == 1) { + // + // Treat it like a built-in unary operator. + // + $$ = parseContext.intermediate.addUnaryMath(op, $1.intermNode, 0, parseContext.symbolTable); + if ($$ == 0) { + parseContext.error($1.intermNode->getLine(), " wrong operand type", "Internal Error", + "built in unary operator function. Type: %s", + static_cast($1.intermNode)->getCompleteString().c_str()); + YYERROR; + } + } else { + $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, op, $1.line); + } + } else { + // This is a real function call + + $$ = parseContext.intermediate.setAggregateOperator($1.intermAggregate, EOpFunctionCall, $1.line); + $$->setType(fnCandidate->getReturnType()); + + // this is how we know whether the given function is a builtIn function or a user defined function + // if builtIn == false, it's a userDefined -> could be an overloaded builtIn function also + // if builtIn == true, it's definitely a builtIn function with EOpNull + if (!builtIn) + $$->getAsAggregate()->setUserDefined(); + $$->getAsAggregate()->setName(fnCandidate->getMangledName()); + + TQualifier qual; + TQualifierList& qualifierList = $$->getAsAggregate()->getQualifier(); + for (int i = 0; i < fnCandidate->getParamCount(); ++i) { + qual = (*fnCandidate)[i].type->getQualifier(); + if (qual == EvqOut || qual == EvqInOut) { + if (parseContext.lValueErrorCheck($$->getLine(), "assign", $$->getAsAggregate()->getSequence()[i]->getAsTyped())) { + parseContext.error($1.intermNode->getLine(), "Constant value cannot be passed for 'out' or 'inout' parameters.", "Error", ""); + parseContext.recover(); + } + } + qualifierList.push_back(qual); + } + } + $$->setType(fnCandidate->getReturnType()); + } else { + // error message was put out by PaFindFunction() + // Put on a dummy node for error recovery + constUnion *unionArray = new constUnion[1]; + unionArray->setFConst(0.0f); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtFloat, EvqConst), $1.line); + parseContext.recover(); + } + } + delete fnCall; + } + ; + +function_call_or_method + : function_call_generic { + $$ = $1; + } + | postfix_expression DOT function_call_generic { + parseContext.error($3.line, "methods are not supported", "", ""); + parseContext.recover(); + $$ = $3; + } + ; + +function_call_generic + : function_call_header_with_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + | function_call_header_no_parameters RIGHT_PAREN { + $$ = $1; + $$.line = $2.line; + } + ; + +function_call_header_no_parameters + : function_call_header VOID_TYPE { + $$.function = $1; + $$.intermNode = 0; + } + | function_call_header { + $$.function = $1; + $$.intermNode = 0; + } + ; + +function_call_header_with_parameters + : function_call_header assignment_expression { + TParameter param = { 0, new TType($2->getType()) }; + $1->addParameter(param); + $$.function = $1; + $$.intermNode = $2; + } + | function_call_header_with_parameters COMMA assignment_expression { + TParameter param = { 0, new TType($3->getType()) }; + $1.function->addParameter(param); + $$.function = $1.function; + $$.intermNode = parseContext.intermediate.growAggregate($1.intermNode, $3, $2.line); + } + ; + +function_call_header + : function_identifier LEFT_PAREN { + $$ = $1; + } + ; + +// Grammar Note: Constructors look like functions, but are recognized as types. + +function_identifier + : type_specifier { + // + // Constructor + // + if ($1.array) { + if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $1.setArray(false); + } + } + + if ($1.userDef) { + TString tempString = ""; + TType type($1); + TFunction *function = new TFunction(&tempString, type, EOpConstructStruct); + $$ = function; + } else { + TOperator op = EOpNull; + switch ($1.type) { + case EbtFloat: + if ($1.matrix) { + switch($1.size) { + case 2: op = EOpConstructMat2; break; + case 3: op = EOpConstructMat3; break; + case 4: op = EOpConstructMat4; break; + } + } else { + switch($1.size) { + case 1: op = EOpConstructFloat; break; + case 2: op = EOpConstructVec2; break; + case 3: op = EOpConstructVec3; break; + case 4: op = EOpConstructVec4; break; + } + } + break; + case EbtInt: + switch($1.size) { + case 1: op = EOpConstructInt; break; + case 2: FRAG_VERT_ONLY("ivec2", $1.line); op = EOpConstructIVec2; break; + case 3: FRAG_VERT_ONLY("ivec3", $1.line); op = EOpConstructIVec3; break; + case 4: FRAG_VERT_ONLY("ivec4", $1.line); op = EOpConstructIVec4; break; + } + break; + case EbtBool: + switch($1.size) { + case 1: op = EOpConstructBool; break; + case 2: FRAG_VERT_ONLY("bvec2", $1.line); op = EOpConstructBVec2; break; + case 3: FRAG_VERT_ONLY("bvec3", $1.line); op = EOpConstructBVec3; break; + case 4: FRAG_VERT_ONLY("bvec4", $1.line); op = EOpConstructBVec4; break; + } + break; + } + if (op == EOpNull) { + parseContext.error($1.line, "cannot construct this type", TType::getBasicString($1.type), ""); + parseContext.recover(); + $1.type = EbtFloat; + op = EOpConstructFloat; + } + TString tempString = ""; + TType type($1); + TFunction *function = new TFunction(&tempString, type, op); + $$ = function; + } + } + | IDENTIFIER { + if (parseContext.reservedErrorCheck($1.line, *$1.string)) + parseContext.recover(); + TType type(EbtVoid); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + | FIELD_SELECTION { + if (parseContext.reservedErrorCheck($1.line, *$1.string)) + parseContext.recover(); + TType type(EbtVoid); + TFunction *function = new TFunction($1.string, type); + $$ = function; + } + ; + +unary_expression + : postfix_expression { + $$ = $1; + } + | INC_OP unary_expression { + if (parseContext.lValueErrorCheck($1.line, "++", $2)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPreIncrement, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($1.line, "++", $2->getCompleteString()); + parseContext.recover(); + $$ = $2; + } + } + | DEC_OP unary_expression { + if (parseContext.lValueErrorCheck($1.line, "--", $2)) + parseContext.recover(); + $$ = parseContext.intermediate.addUnaryMath(EOpPreDecrement, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.unaryOpError($1.line, "--", $2->getCompleteString()); + parseContext.recover(); + $$ = $2; + } + } + | unary_operator unary_expression { + if ($1.op != EOpNull) { + $$ = parseContext.intermediate.addUnaryMath($1.op, $2, $1.line, parseContext.symbolTable); + if ($$ == 0) { + const char* errorOp = ""; + switch($1.op) { + case EOpNegative: errorOp = "-"; break; + case EOpLogicalNot: errorOp = "!"; break; + case EOpBitwiseNot: errorOp = "~"; break; + default: break; + } + parseContext.unaryOpError($1.line, errorOp, $2->getCompleteString()); + parseContext.recover(); + $$ = $2; + } + } else + $$ = $2; + } + ; +// Grammar Note: No traditional style type casts. + +unary_operator + : PLUS { $$.line = $1.line; $$.op = EOpNull; } + | DASH { $$.line = $1.line; $$.op = EOpNegative; } + | BANG { $$.line = $1.line; $$.op = EOpLogicalNot; } + | TILDE { PACK_UNPACK_ONLY("~", $1.line); + $$.line = $1.line; $$.op = EOpBitwiseNot; } + ; +// Grammar Note: No '*' or '&' unary ops. Pointers are not supported. + +multiplicative_expression + : unary_expression { $$ = $1; } + | multiplicative_expression STAR unary_expression { + FRAG_VERT_ONLY("*", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpMul, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "*", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | multiplicative_expression SLASH unary_expression { + FRAG_VERT_ONLY("/", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpDiv, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "/", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | multiplicative_expression PERCENT unary_expression { + PACK_UNPACK_ONLY("%", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpMod, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "%", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +additive_expression + : multiplicative_expression { $$ = $1; } + | additive_expression PLUS multiplicative_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpAdd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "+", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | additive_expression DASH multiplicative_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpSub, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "-", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +shift_expression + : additive_expression { $$ = $1; } + | shift_expression LEFT_OP additive_expression { + PACK_UNPACK_ONLY("<<", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpLeftShift, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<<", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + | shift_expression RIGHT_OP additive_expression { + PACK_UNPACK_ONLY(">>", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpRightShift, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">>", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +relational_expression + : shift_expression { $$ = $1; } + | relational_expression LEFT_ANGLE shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLessThan, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression RIGHT_ANGLE shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThan, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression LE_OP shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLessThanEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "<=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + | relational_expression GE_OP shift_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpGreaterThanEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ">=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +equality_expression + : relational_expression { $$ = $1; } + | equality_expression EQ_OP relational_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "==", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + | equality_expression NE_OP relational_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpNotEqual, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "!=", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + ; + +and_expression + : equality_expression { $$ = $1; } + | and_expression AMPERSAND equality_expression { + PACK_UNPACK_ONLY("&", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpAnd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "&", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +exclusive_or_expression + : and_expression { $$ = $1; } + | exclusive_or_expression CARET and_expression { + PACK_UNPACK_ONLY("^", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpExclusiveOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "^", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +inclusive_or_expression + : exclusive_or_expression { $$ = $1; } + | inclusive_or_expression VERTICAL_BAR exclusive_or_expression { + PACK_UNPACK_ONLY("|", $2.line); + $$ = parseContext.intermediate.addBinaryMath(EOpInclusiveOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "|", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } + } + ; + +logical_and_expression + : inclusive_or_expression { $$ = $1; } + | logical_and_expression AND_OP inclusive_or_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalAnd, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "&&", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +logical_xor_expression + : logical_and_expression { $$ = $1; } + | logical_xor_expression XOR_OP logical_and_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalXor, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "^^", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +logical_or_expression + : logical_xor_expression { $$ = $1; } + | logical_or_expression OR_OP logical_xor_expression { + $$ = parseContext.intermediate.addBinaryMath(EOpLogicalOr, $1, $3, $2.line, parseContext.symbolTable); + if ($$ == 0) { + parseContext.binaryOpError($2.line, "||", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + constUnion *unionArray = new constUnion[1]; + unionArray->setBConst(false); + $$ = parseContext.intermediate.addConstantUnion(unionArray, TType(EbtBool, EvqConst), $2.line); + } + } + ; + +conditional_expression + : logical_or_expression { $$ = $1; } + | logical_or_expression QUESTION expression COLON assignment_expression { + if (parseContext.boolErrorCheck($2.line, $1)) + parseContext.recover(); + + $$ = parseContext.intermediate.addSelection($1, $3, $5, $2.line); + if ($3->getType() != $5->getType()) + $$ = 0; + + if ($$ == 0) { + parseContext.binaryOpError($2.line, ":", $3->getCompleteString(), $5->getCompleteString()); + parseContext.recover(); + $$ = $5; + } + } + ; + +assignment_expression + : conditional_expression { $$ = $1; } + | unary_expression assignment_operator assignment_expression { + if (parseContext.lValueErrorCheck($2.line, "assign", $1)) + parseContext.recover(); + $$ = parseContext.intermediate.addAssign($2.op, $1, $3, $2.line); + if ($$ == 0) { + parseContext.assignError($2.line, "assign", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $1; + } else if (($1->isArray() || $3->isArray()) && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) + parseContext.recover(); + } + ; + +assignment_operator + : EQUAL { $$.line = $1.line; $$.op = EOpAssign; } + | MUL_ASSIGN { FRAG_VERT_ONLY("*=", $1.line); $$.line = $1.line; $$.op = EOpMulAssign; } + | DIV_ASSIGN { FRAG_VERT_ONLY("/=", $1.line); $$.line = $1.line; $$.op = EOpDivAssign; } + | MOD_ASSIGN { PACK_UNPACK_ONLY("%=", $1.line); $$.line = $1.line; $$.op = EOpModAssign; } + | ADD_ASSIGN { $$.line = $1.line; $$.op = EOpAddAssign; } + | SUB_ASSIGN { $$.line = $1.line; $$.op = EOpSubAssign; } + | LEFT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line); $$.line = $1.line; $$.op = EOpLeftShiftAssign; } + | RIGHT_ASSIGN { PACK_UNPACK_ONLY("<<=", $1.line); $$.line = $1.line; $$.op = EOpRightShiftAssign; } + | AND_ASSIGN { PACK_UNPACK_ONLY("&=", $1.line); $$.line = $1.line; $$.op = EOpAndAssign; } + | XOR_ASSIGN { PACK_UNPACK_ONLY("^=", $1.line); $$.line = $1.line; $$.op = EOpExclusiveOrAssign; } + | OR_ASSIGN { PACK_UNPACK_ONLY("|=", $1.line); $$.line = $1.line; $$.op = EOpInclusiveOrAssign; } + ; + +expression + : assignment_expression { + $$ = $1; + } + | expression COMMA assignment_expression { + $$ = parseContext.intermediate.addComma($1, $3, $2.line); + if ($$ == 0) { + parseContext.binaryOpError($2.line, ",", $1->getCompleteString(), $3->getCompleteString()); + parseContext.recover(); + $$ = $3; + } + } + ; + +constant_expression + : conditional_expression { + if (parseContext.constErrorCheck($1)) + parseContext.recover(); + $$ = $1; + } + ; + +declaration + : function_prototype SEMICOLON { $$ = 0; } + | init_declarator_list SEMICOLON { + if ($1.intermAggregate) + $1.intermAggregate->setOperator(EOpDeclaration); + $$ = $1.intermAggregate; + } + | PRECISION precision_qualifier type_specifier_no_prec SEMICOLON { + $$ = 0; + } + ; + +function_prototype + : function_declarator RIGHT_PAREN { + // + // Multiple declarations of the same function are allowed. + // + // If this is a definition, the definition production code will check for redefinitions + // (we don't know at this point if it's a definition or not). + // + // Redeclarations are allowed. But, return types and parameter qualifiers must match. + // + TFunction* prevDec = static_cast(parseContext.symbolTable.find($1->getMangledName())); + if (prevDec) { + if (prevDec->getReturnType() != $1->getReturnType()) { + parseContext.error($2.line, "overloaded functions must have the same return type", $1->getReturnType().getBasicString(), ""); + parseContext.recover(); + } + for (int i = 0; i < prevDec->getParamCount(); ++i) { + if ((*prevDec)[i].type->getQualifier() != (*$1)[i].type->getQualifier()) { + parseContext.error($2.line, "overloaded functions must have the same parameter qualifiers", (*$1)[i].type->getQualifierString(), ""); + parseContext.recover(); + } + } + } + + // + // If this is a redeclaration, it could also be a definition, + // in which case, we want to use the variable names from this one, and not the one that's + // being redeclared. So, pass back up this declaration, not the one in the symbol table. + // + $$.function = $1; + $$.line = $2.line; + + parseContext.symbolTable.insert(*$$.function); + } + ; + +function_declarator + : function_header { + $$ = $1; + } + | function_header_with_parameters { + $$ = $1; + } + ; + + +function_header_with_parameters + : function_header parameter_declaration { + // Add the parameter + $$ = $1; + if ($2.param.type->getBasicType() != EbtVoid) + $1->addParameter($2.param); + else + delete $2.param.type; + } + | function_header_with_parameters COMMA parameter_declaration { + // + // Only first parameter of one-parameter functions can be void + // The check for named parameters not being void is done in parameter_declarator + // + if ($3.param.type->getBasicType() == EbtVoid) { + // + // This parameter > first is void + // + parseContext.error($2.line, "cannot be an argument type except for '(void)'", "void", ""); + parseContext.recover(); + delete $3.param.type; + } else { + // Add the parameter + $$ = $1; + $1->addParameter($3.param); + } + } + ; + +function_header + : fully_specified_type IDENTIFIER LEFT_PAREN { + if ($1.qualifier != EvqGlobal && $1.qualifier != EvqTemporary) { + parseContext.error($2.line, "no qualifiers allowed for function return", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + // make sure a sampler is not involved as well... + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + // Add the function as a prototype after parsing it (we do not support recursion) + TFunction *function; + TType type($1); + function = new TFunction($2.string, type); + $$ = function; + } + ; + +parameter_declarator + // Type + name + : type_specifier IDENTIFIER { + if ($1.type == EbtVoid) { + parseContext.error($2.line, "illegal use of type 'void'", $2.string->c_str(), ""); + parseContext.recover(); + } + if (parseContext.reservedErrorCheck($2.line, *$2.string)) + parseContext.recover(); + TParameter param = {$2.string, new TType($1)}; + $$.line = $2.line; + $$.param = param; + } + | type_specifier IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + // Check that we can make an array out of this type + if (parseContext.arrayTypeErrorCheck($3.line, $1)) + parseContext.recover(); + + if (parseContext.reservedErrorCheck($2.line, *$2.string)) + parseContext.recover(); + + int size; + if (parseContext.arraySizeErrorCheck($3.line, $4, size)) + parseContext.recover(); + $1.setArray(true, size); + + TType* type = new TType($1); + TParameter param = { $2.string, type }; + $$.line = $2.line; + $$.param = param; + } + ; + +parameter_declaration + // + // The only parameter qualifier a parameter can have are + // IN_QUAL, OUT_QUAL, INOUT_QUAL, or CONST. + // + + // + // Type + name + // + : type_qualifier parameter_qualifier parameter_declarator { + $$ = $3; + if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + parseContext.recover(); + } + | parameter_qualifier parameter_declarator { + $$ = $2; + if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + parseContext.recover(); + if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + parseContext.recover(); + } + // + // Only type + // + | type_qualifier parameter_qualifier parameter_type_specifier { + $$ = $3; + if (parseContext.paramErrorCheck($3.line, $1.qualifier, $2, $$.param.type)) + parseContext.recover(); + } + | parameter_qualifier parameter_type_specifier { + $$ = $2; + if (parseContext.parameterSamplerErrorCheck($2.line, $1, *$2.param.type)) + parseContext.recover(); + if (parseContext.paramErrorCheck($2.line, EvqTemporary, $1, $$.param.type)) + parseContext.recover(); + } + ; + +parameter_qualifier + : /* empty */ { + $$ = EvqIn; + } + | IN_QUAL { + $$ = EvqIn; + } + | OUT_QUAL { + $$ = EvqOut; + } + | INOUT_QUAL { + $$ = EvqInOut; + } + ; + +parameter_type_specifier + : type_specifier { + TParameter param = { 0, new TType($1) }; + $$.param = param; + } + ; + +init_declarator_list + : single_declaration { + $$ = $1; + } + | init_declarator_list COMMA IDENTIFIER { + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, parseContext.intermediate.addSymbol(0, *$3.string, TType($1.type), $3.line), $3.line); + + if (parseContext.structQualifierErrorCheck($3.line, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitErrorCheck($3.line, *$3.string, $$.type)) + parseContext.recover(); + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type)) + parseContext.recover(); + + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + $1.type.setArray(true); + TVariable* variable; + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($3.line, *$3.string, $1.type)) + parseContext.recover(); + + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($4.line, $5, size)) + parseContext.recover(); + $1.type.setArray(true, size); + TVariable* variable; + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET RIGHT_BRACKET EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + $1.type.setArray(true, $7->getType().getArraySize()); + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $7, intermNode, variable)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $6.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | init_declarator_list COMMA IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TVariable* variable = 0; + if (parseContext.arrayTypeErrorCheck($4.line, $1.type) || parseContext.arrayQualifierErrorCheck($4.line, $1.type)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($4.line, $5, size)) + parseContext.recover(); + $1.type.setArray(true, size); + if (parseContext.arrayErrorCheck($4.line, *$3.string, $1.type, variable)) + parseContext.recover(); + } + + if (parseContext.extensionErrorCheck($$.line, "GL_3DL_array_objects")) + parseContext.recover(); + else { + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $8, intermNode, variable)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $7.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + } + | init_declarator_list COMMA IDENTIFIER EQUAL initializer { + if (parseContext.structQualifierErrorCheck($3.line, $1.type)) + parseContext.recover(); + + $$ = $1; + + TIntermNode* intermNode; + if (!parseContext.executeInitializer($3.line, *$3.string, $1.type, $5, intermNode)) { + // + // build the intermediate representation + // + if (intermNode) + $$.intermAggregate = parseContext.intermediate.growAggregate($1.intermNode, intermNode, $4.line); + else + $$.intermAggregate = $1.intermAggregate; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + ; + +single_declaration + : fully_specified_type { + $$.type = $1; + $$.intermAggregate = 0; + } + | fully_specified_type IDENTIFIER { + $$.intermAggregate = parseContext.intermediate.makeAggregate(parseContext.intermediate.addSymbol(0, *$2.string, TType($1), $2.line), $2.line); + + if (parseContext.structQualifierErrorCheck($2.line, $$.type)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $$.type)) + parseContext.recover(); + + $$.type = $1; + + if (parseContext.nonInitErrorCheck($2.line, *$2.string, $$.type)) + parseContext.recover(); + } + | fully_specified_type IDENTIFIER LEFT_BRACKET RIGHT_BRACKET { + $$.intermAggregate = parseContext.intermediate.makeAggregate(parseContext.intermediate.addSymbol(0, *$2.string, TType($1), $2.line), $2.line); + + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1)) + parseContext.recover(); + + $$.type = $1; + + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + $1.setArray(true); + TVariable* variable; + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + } + | fully_specified_type IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + TType type = TType($1); + int size; + if (parseContext.arraySizeErrorCheck($2.line, $4, size)) + parseContext.recover(); + type.setArraySize(size); + $$.intermAggregate = parseContext.intermediate.makeAggregate(parseContext.intermediate.addSymbol(0, *$2.string, type, $2.line), $2.line); + + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + if (parseContext.nonInitConstErrorCheck($2.line, *$2.string, $1)) + parseContext.recover(); + + $$.type = $1; + + if (parseContext.arrayTypeErrorCheck($3.line, $1) || parseContext.arrayQualifierErrorCheck($3.line, $1)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($3.line, $4, size)) + parseContext.recover(); + + $1.setArray(true, size); + TVariable* variable; + if (parseContext.arrayErrorCheck($3.line, *$2.string, $1, variable)) + parseContext.recover(); + } + } + | fully_specified_type IDENTIFIER EQUAL initializer { + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + + $$.type = $1; + + TIntermNode* intermNode; + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) { + // + // Build intermediate representation + // + if(intermNode) + $$.intermAggregate = parseContext.intermediate.makeAggregate(intermNode, $3.line); + else + $$.intermAggregate = 0; + } else { + parseContext.recover(); + $$.intermAggregate = 0; + } + } + | INVARIANT IDENTIFIER { + VERTEX_ONLY("invariant declaration", $1.line); + $$.qualifier = EvqInvariantVaryingOut; + $$.intermAggregate = 0; + } + +// +// Place holder for the pack/unpack languages. +// +// | buffer_specifier { +// $$.intermAggregate = 0; +// } + ; + +// Grammar Note: No 'enum', or 'typedef'. + +// +// Place holder for the pack/unpack languages. +// +//%type buffer_declaration +//%type buffer_specifier input_or_output buffer_declaration_list +//buffer_specifier +// : input_or_output LEFT_BRACE buffer_declaration_list RIGHT_BRACE { +// } +// ; +// +//input_or_output +// : INPUT { +// if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "input")) +// parseContext.recover(); +// UNPACK_ONLY("input", $1.line); +// $$.qualifier = EvqInput; +// } +// | OUTPUT { +// if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "output")) +// parseContext.recover(); +// PACK_ONLY("output", $1.line); +// $$.qualifier = EvqOutput; +// } +// ; + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration_list +// : buffer_declaration { +// } +// | buffer_declaration_list buffer_declaration { +// } +// ; + +// +// Input/output semantics: +// float must be 16 or 32 bits +// float alignment restrictions? +// check for only one input and only one output +// sum of bitfields has to be multiple of 32 +// + +// +// Place holder for the pack/unpack languages. +// +//buffer_declaration +// : type_specifier IDENTIFIER COLON constant_expression SEMICOLON { +// if (parseContext.reservedErrorCheck($2.line, *$2.string, parseContext)) +// parseContext.recover(); +// $$.variable = new TVariable($2.string, $1); +// if (! parseContext.symbolTable.insert(*$$.variable)) { +// parseContext.error($2.line, "redefinition", $$.variable->getName().c_str(), ""); +// parseContext.recover(); +// // don't have to delete $$.variable, the pool pop will take care of it +// } +// } +// ; + +fully_specified_type + : type_specifier { + $$ = $1; + + if ($1.array) { + if (parseContext.extensionErrorCheck($1.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $1.setArray(false); + } + } + } + | type_qualifier type_specifier { + if ($2.array && parseContext.extensionErrorCheck($2.line, "GL_3DL_array_objects")) { + parseContext.recover(); + $2.setArray(false); + } + if ($2.array && parseContext.arrayQualifierErrorCheck($2.line, $1)) { + parseContext.recover(); + $2.setArray(false); + } + + if ($1.qualifier == EvqAttribute && + ($2.type == EbtBool || $2.type == EbtInt)) { + parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + if (($1.qualifier == EvqVaryingIn || $1.qualifier == EvqVaryingOut) && + ($2.type == EbtBool || $2.type == EbtInt)) { + parseContext.error($2.line, "cannot be bool or int", getQualifierString($1.qualifier), ""); + parseContext.recover(); + } + $$ = $2; + $$.qualifier = $1.qualifier; + } + ; + +type_qualifier + : CONST_QUAL { + $$.setBasic(EbtVoid, EvqConst, $1.line); + } + | ATTRIBUTE { + VERTEX_ONLY("attribute", $1.line); + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "attribute")) + parseContext.recover(); + $$.setBasic(EbtVoid, EvqAttribute, $1.line); + } + | VARYING { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "varying")) + parseContext.recover(); + if (parseContext.language == EShLangVertex) + $$.setBasic(EbtVoid, EvqVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqVaryingIn, $1.line); + } + | INVARIANT VARYING { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "invariant varying")) + parseContext.recover(); + if (parseContext.language == EShLangVertex) + $$.setBasic(EbtVoid, EvqInvariantVaryingOut, $1.line); + else + $$.setBasic(EbtVoid, EvqInvariantVaryingIn, $1.line); + } + | UNIFORM { + if (parseContext.globalErrorCheck($1.line, parseContext.symbolTable.atGlobalLevel(), "uniform")) + parseContext.recover(); + $$.setBasic(EbtVoid, EvqUniform, $1.line); + } + ; + +type_specifier + : type_specifier_no_prec { + $$ = $1; + } + | precision_qualifier type_specifier_no_prec { + $$ = $2; + $$.setPrecision($1); + } + ; + +precision_qualifier + : HIGH_PRECISION { + $$ = EbpHigh; + } + | MEDIUM_PRECISION { + $$ = EbpMedium; + } + | LOW_PRECISION { + $$ = EbpLow; + } + ; + +type_specifier_no_prec + : type_specifier_nonarray { + $$ = $1; + } + | type_specifier_nonarray LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$ = $1; + + if (parseContext.arrayTypeErrorCheck($2.line, $1)) + parseContext.recover(); + else { + int size; + if (parseContext.arraySizeErrorCheck($2.line, $3, size)) + parseContext.recover(); + $$.setArray(true, size); + } + } + ; + +type_specifier_nonarray + : VOID_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtVoid, qual, $1.line); + } + | FLOAT_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + } + | INT_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + } + | BOOL_TYPE { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + } +// | UNSIGNED INT_TYPE { +// PACK_UNPACK_ONLY("unsigned", $1.line); +// TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; +// $$.setBasic(EbtInt, qual, $1.line); +// } + | VEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2); + } + | VEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3); + } + | VEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4); + } + | BVEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(2); + } + | BVEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(3); + } + | BVEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtBool, qual, $1.line); + $$.setAggregate(4); + } + | IVEC2 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(2); + } + | IVEC3 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(3); + } + | IVEC4 { + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtInt, qual, $1.line); + $$.setAggregate(4); + } + | MATRIX2 { + FRAG_VERT_ONLY("mat2", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(2, true); + } + | MATRIX3 { + FRAG_VERT_ONLY("mat3", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(3, true); + } + | MATRIX4 { + FRAG_VERT_ONLY("mat4", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtFloat, qual, $1.line); + $$.setAggregate(4, true); + } + | SAMPLER2D { + FRAG_VERT_ONLY("sampler2D", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSampler2D, qual, $1.line); + } + | SAMPLERCUBE { + FRAG_VERT_ONLY("samplerCube", $1.line); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtSamplerCube, qual, $1.line); + } + | struct_specifier { + FRAG_VERT_ONLY("struct", $1.line); + $$ = $1; + $$.qualifier = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + } + | TYPE_NAME { + // + // This is for user defined type names. The lexical phase looked up the + // type. + // + TType& structure = static_cast($1.symbol)->getType(); + TQualifier qual = parseContext.symbolTable.atGlobalLevel() ? EvqGlobal : EvqTemporary; + $$.setBasic(EbtStruct, qual, $1.line); + $$.userDef = &structure; + } + ; + +struct_specifier + : STRUCT IDENTIFIER LEFT_BRACE struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($4, *$2.string); + TVariable* userTypeDef = new TVariable($2.string, *structure, true); + if (! parseContext.symbolTable.insert(*userTypeDef)) { + parseContext.error($2.line, "redefinition", $2.string->c_str(), "struct"); + parseContext.recover(); + } + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + } + | STRUCT LEFT_BRACE struct_declaration_list RIGHT_BRACE { + TType* structure = new TType($3, TString("")); + $$.setBasic(EbtStruct, EvqTemporary, $1.line); + $$.userDef = structure; + } + ; + +struct_declaration_list + : struct_declaration { + $$ = $1; + } + | struct_declaration_list struct_declaration { + $$ = $1; + for (unsigned int i = 0; i < $2->size(); ++i) { + for (unsigned int j = 0; j < $$->size(); ++j) { + if ((*$$)[j].type->getFieldName() == (*$2)[i].type->getFieldName()) { + parseContext.error((*$2)[i].line, "duplicate field name in structure:", "struct", (*$2)[i].type->getFieldName().c_str()); + parseContext.recover(); + } + } + $$->push_back((*$2)[i]); + } + } + ; + +struct_declaration + : type_specifier struct_declarator_list SEMICOLON { + $$ = $2; + + if (parseContext.voidErrorCheck($1.line, (*$2)[0].type->getFieldName(), $1)) { + parseContext.recover(); + } + for (unsigned int i = 0; i < $$->size(); ++i) { + // + // Careful not to replace already know aspects of type, like array-ness + // + (*$$)[i].type->setType($1.type, $1.size, $1.matrix, $1.userDef); + + // don't allow arrays of arrays + if ((*$$)[i].type->isArray()) { + if (parseContext.arrayTypeErrorCheck($1.line, $1)) + parseContext.recover(); + } + if ($1.array) + (*$$)[i].type->setArraySize($1.arraySize); + if ($1.userDef) + (*$$)[i].type->setTypeName($1.userDef->getTypeName()); + } + } + ; + +struct_declarator_list + : struct_declarator { + $$ = NewPoolTTypeList(); + $$->push_back($1); + } + | struct_declarator_list COMMA struct_declarator { + $$->push_back($3); + } + ; + +struct_declarator + : IDENTIFIER { + $$.type = new TType(EbtVoid); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + } + | IDENTIFIER LEFT_BRACKET constant_expression RIGHT_BRACKET { + $$.type = new TType(EbtVoid); + $$.line = $1.line; + $$.type->setFieldName(*$1.string); + + int size; + if (parseContext.arraySizeErrorCheck($2.line, $3, size)) + parseContext.recover(); + $$.type->setArraySize(size); + } + ; + +initializer + : assignment_expression { $$ = $1; } + ; + +declaration_statement + : declaration { $$ = $1; } + ; + +statement + : compound_statement { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +// Grammar Note: No labeled statements; 'goto' is not supported. + +simple_statement + : declaration_statement { $$ = $1; } + | expression_statement { $$ = $1; } + | selection_statement { $$ = $1; } + | iteration_statement { $$ = $1; } + | jump_statement { $$ = $1; } + ; + +compound_statement + : LEFT_BRACE RIGHT_BRACE { $$ = 0; } + | LEFT_BRACE { parseContext.symbolTable.push(); } statement_list { parseContext.symbolTable.pop(); } RIGHT_BRACE { + if ($3 != 0) + $3->setOperator(EOpSequence); + $$ = $3; + } + ; + +statement_no_new_scope + : compound_statement_no_new_scope { $$ = $1; } + | simple_statement { $$ = $1; } + ; + +compound_statement_no_new_scope + // Statement that doesn't create a new scope, for selection_statement, iteration_statement + : LEFT_BRACE RIGHT_BRACE { + $$ = 0; + } + | LEFT_BRACE statement_list RIGHT_BRACE { + if ($2) + $2->setOperator(EOpSequence); + $$ = $2; + } + ; + +statement_list + : statement { + $$ = parseContext.intermediate.makeAggregate($1, 0); + } + | statement_list statement { + $$ = parseContext.intermediate.growAggregate($1, $2, 0); + } + ; + +expression_statement + : SEMICOLON { $$ = 0; } + | expression SEMICOLON { $$ = static_cast($1); } + ; + +selection_statement + : IF LEFT_PAREN expression RIGHT_PAREN selection_rest_statement { + if (parseContext.boolErrorCheck($1.line, $3)) + parseContext.recover(); + $$ = parseContext.intermediate.addSelection($3, $5, $1.line); + } + ; + +selection_rest_statement + : statement ELSE statement { + $$.node1 = $1; + $$.node2 = $3; + } + | statement { + $$.node1 = $1; + $$.node2 = 0; + } + ; + +// Grammar Note: No 'switch'. Switch statements not supported. + +condition + // In 1996 c++ draft, conditions can include single declarations + : expression { + $$ = $1; + if (parseContext.boolErrorCheck($1->getLine(), $1)) + parseContext.recover(); + } + | fully_specified_type IDENTIFIER EQUAL initializer { + TIntermNode* intermNode; + if (parseContext.structQualifierErrorCheck($2.line, $1)) + parseContext.recover(); + if (parseContext.boolErrorCheck($2.line, $1)) + parseContext.recover(); + + if (!parseContext.executeInitializer($2.line, *$2.string, $1, $4, intermNode)) + $$ = $4; + else { + parseContext.recover(); + $$ = 0; + } + } + ; + +iteration_statement + : WHILE LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } condition RIGHT_PAREN statement_no_new_scope { + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.addLoop(0, $6, $4, 0, true, $1.line); + --parseContext.loopNestingLevel; + } + | DO { ++parseContext.loopNestingLevel; } statement WHILE LEFT_PAREN expression RIGHT_PAREN SEMICOLON { + if (parseContext.boolErrorCheck($8.line, $6)) + parseContext.recover(); + + $$ = parseContext.intermediate.addLoop(0, $3, $6, 0, false, $4.line); + --parseContext.loopNestingLevel; + } + | FOR LEFT_PAREN { parseContext.symbolTable.push(); ++parseContext.loopNestingLevel; } for_init_statement for_rest_statement RIGHT_PAREN statement_no_new_scope { + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.addLoop($4, $7, reinterpret_cast($5.node1), reinterpret_cast($5.node2), true, $1.line); + --parseContext.loopNestingLevel; + } + ; + +for_init_statement + : expression_statement { + $$ = $1; + } + | declaration_statement { + $$ = $1; + } + ; + +conditionopt + : condition { + $$ = $1; + } + | /* May be null */ { + $$ = 0; + } + ; + +for_rest_statement + : conditionopt SEMICOLON { + $$.node1 = $1; + $$.node2 = 0; + } + | conditionopt SEMICOLON expression { + $$.node1 = $1; + $$.node2 = $3; + } + ; + +jump_statement + : CONTINUE SEMICOLON { + if (parseContext.loopNestingLevel <= 0) { + parseContext.error($1.line, "continue statement only allowed in loops", "", ""); + parseContext.recover(); + } + $$ = parseContext.intermediate.addBranch(EOpContinue, $1.line); + } + | BREAK SEMICOLON { + if (parseContext.loopNestingLevel <= 0) { + parseContext.error($1.line, "break statement only allowed in loops", "", ""); + parseContext.recover(); + } + $$ = parseContext.intermediate.addBranch(EOpBreak, $1.line); + } + | RETURN SEMICOLON { + $$ = parseContext.intermediate.addBranch(EOpReturn, $1.line); + if (parseContext.currentFunctionType->getBasicType() != EbtVoid) { + parseContext.error($1.line, "non-void function must return a value", "return", ""); + parseContext.recover(); + } + } + | RETURN expression SEMICOLON { + $$ = parseContext.intermediate.addBranch(EOpReturn, $2, $1.line); + parseContext.functionReturnsValue = true; + if (parseContext.currentFunctionType->getBasicType() == EbtVoid) { + parseContext.error($1.line, "void function cannot return a value", "return", ""); + parseContext.recover(); + } else if (*(parseContext.currentFunctionType) != $2->getType()) { + parseContext.error($1.line, "function return is not matching type:", "return", ""); + parseContext.recover(); + } + } + | DISCARD SEMICOLON { + FRAG_ONLY("discard", $1.line); + $$ = parseContext.intermediate.addBranch(EOpKill, $1.line); + } + ; + +// Grammar Note: No 'goto'. Gotos are not supported. + +translation_unit + : external_declaration { + $$ = $1; + parseContext.treeRoot = $$; + } + | translation_unit external_declaration { + $$ = parseContext.intermediate.growAggregate($1, $2, 0); + parseContext.treeRoot = $$; + } + ; + +external_declaration + : function_definition { + $$ = $1; + } + | declaration { + $$ = $1; + } + ; + +function_definition + : function_prototype { + TFunction& function = *($1.function); + TFunction* prevDec = static_cast(parseContext.symbolTable.find(function.getMangledName())); + // + // Note: 'prevDec' could be 'function' if this is the first time we've seen function + // as it would have just been put in the symbol table. Otherwise, we're looking up + // an earlier occurance. + // + if (prevDec->isDefined()) { + // + // Then this function already has a body. + // + parseContext.error($1.line, "function already has a body", function.getName().c_str(), ""); + parseContext.recover(); + } + prevDec->setDefined(); + + // + // Raise error message if main function takes any parameters or return anything other than void + // + if (function.getName() == "main") { + if (function.getParamCount() > 0) { + parseContext.error($1.line, "function cannot take any parameter(s)", function.getName().c_str(), ""); + parseContext.recover(); + } + if (function.getReturnType().getBasicType() != EbtVoid) { + parseContext.error($1.line, "", function.getReturnType().getBasicString(), "main function cannot return a value"); + parseContext.recover(); + } + } + + // + // New symbol table scope for body of function plus its arguments + // + parseContext.symbolTable.push(); + + // + // Remember the return type for later checking for RETURN statements. + // + parseContext.currentFunctionType = &(prevDec->getReturnType()); + parseContext.functionReturnsValue = false; + + // + // Insert parameters into the symbol table. + // If the parameter has no name, it's not an error, just don't insert it + // (could be used for unused args). + // + // Also, accumulate the list of parameters into the HIL, so lower level code + // knows where to find parameters. + // + TIntermAggregate* paramNodes = new TIntermAggregate; + for (int i = 0; i < function.getParamCount(); i++) { + TParameter& param = function[i]; + if (param.name != 0) { + TVariable *variable = new TVariable(param.name, *param.type); + // + // Insert the parameters with name in the symbol table. + // + if (! parseContext.symbolTable.insert(*variable)) { + parseContext.error($1.line, "redefinition", variable->getName().c_str(), ""); + parseContext.recover(); + delete variable; + } + // + // Transfer ownership of name pointer to symbol table. + // + param.name = 0; + + // + // Add the parameter to the HIL + // + paramNodes = parseContext.intermediate.growAggregate( + paramNodes, + parseContext.intermediate.addSymbol(variable->getUniqueId(), + variable->getName(), + variable->getType(), $1.line), + $1.line); + } else { + paramNodes = parseContext.intermediate.growAggregate(paramNodes, parseContext.intermediate.addSymbol(0, "", *param.type, $1.line), $1.line); + } + } + parseContext.intermediate.setAggregateOperator(paramNodes, EOpParameters, $1.line); + $1.intermAggregate = paramNodes; + parseContext.loopNestingLevel = 0; + } + compound_statement_no_new_scope { + //?? Check that all paths return a value if return type != void ? + // May be best done as post process phase on intermediate code + if (parseContext.currentFunctionType->getBasicType() != EbtVoid && ! parseContext.functionReturnsValue) { + parseContext.error($1.line, "function does not return a value:", "", $1.function->getName().c_str()); + parseContext.recover(); + } + parseContext.symbolTable.pop(); + $$ = parseContext.intermediate.growAggregate($1.intermAggregate, $3, 0); + parseContext.intermediate.setAggregateOperator($$, EOpFunction, $1.line); + $$->getAsAggregate()->setName($1.function->getMangledName().c_str()); + $$->getAsAggregate()->setType($1.function->getReturnType()); + + // store the pragma information for debug and optimize and other vendor specific + // information. This information can be queried from the parse tree + $$->getAsAggregate()->setOptimize(parseContext.contextPragma.optimize); + $$->getAsAggregate()->setDebug(parseContext.contextPragma.debug); + $$->getAsAggregate()->addToPragmaTable(parseContext.contextPragma.pragmaTable); + } + ; + +%% diff --git a/Compiler/intermOut.cpp b/Compiler/intermOut.cpp new file mode 100644 index 000000000..6e30b86af --- /dev/null +++ b/Compiler/intermOut.cpp @@ -0,0 +1,455 @@ +// +// Copyright (c) 2002-2010 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 "localintermediate.h" + +// +// Two purposes: +// 1. Show an example of how to iterate tree. Functions can +// also directly call Traverse() on children themselves to +// have finer grained control over the process than shown here. +// See the last function for how to get started. +// 2. Print out a text based description of the tree. +// + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TOutputTraverser : public TIntermTraverser { +public: + TOutputTraverser(TInfoSink& i) : infoSink(i) { } + TInfoSink& infoSink; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); +}; + +TString TType::getCompleteString() const +{ + char buf[100]; + char *p = &buf[0]; + + if (qualifier != EvqTemporary && qualifier != EvqGlobal) + p += sprintf(p, "%s ", getQualifierString()); + if (array) + p += sprintf(p, "array of "); + if (matrix) + p += sprintf(p, "%dX%d matrix of ", size, size); + else if (size > 1) + p += sprintf(p, "%d-component vector of ", size); + + sprintf(p, "%s", getBasicString()); + + return TString(buf); +} + +// +// Helper functions for printing, not part of traversing. +// + +void OutputTreeText(TInfoSink& infoSink, TIntermNode* node, const int depth) +{ + int i; + + infoSink.debug << FormatSourceLoc(node->getLine()); + + for (i = 0; i < depth; ++i) + infoSink.debug << " "; +} + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TOutputTraverser::visitSymbol(TIntermSymbol* node) +{ + OutputTreeText(infoSink, node, depth); + + char buf[100]; + sprintf(buf, "'%s' (%s)\n", + node->getSymbol().c_str(), + node->getCompleteString().c_str()); + + infoSink.debug << buf; +} + +bool TOutputTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TInfoSink& out = infoSink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpAssign: out.debug << "move second child to first child"; break; + case EOpAddAssign: out.debug << "add second child into first child"; break; + case EOpSubAssign: out.debug << "subtract second child into first child"; break; + case EOpMulAssign: out.debug << "multiply second child into first child"; break; + case EOpVectorTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; + case EOpVectorTimesScalarAssign: out.debug << "vector scale second child into first child"; break; + case EOpMatrixTimesScalarAssign: out.debug << "matrix scale second child into first child"; break; + case EOpMatrixTimesMatrixAssign: out.debug << "matrix mult second child into first child"; break; + case EOpDivAssign: out.debug << "divide second child into first child"; break; + case EOpModAssign: out.debug << "mod second child into first child"; break; + case EOpAndAssign: out.debug << "and second child into first child"; break; + case EOpInclusiveOrAssign: out.debug << "or second child into first child"; break; + case EOpExclusiveOrAssign: out.debug << "exclusive or second child into first child"; break; + case EOpLeftShiftAssign: out.debug << "left shift second child into first child"; break; + case EOpRightShiftAssign: out.debug << "right shift second child into first child"; break; + + case EOpIndexDirect: out.debug << "direct index"; break; + case EOpIndexIndirect: out.debug << "indirect index"; break; + case EOpIndexDirectStruct: out.debug << "direct index for structure"; break; + case EOpVectorSwizzle: out.debug << "vector swizzle"; break; + + case EOpAdd: out.debug << "add"; break; + case EOpSub: out.debug << "subtract"; break; + case EOpMul: out.debug << "component-wise multiply"; break; + case EOpDiv: out.debug << "divide"; break; + case EOpMod: out.debug << "mod"; break; + case EOpRightShift: out.debug << "right-shift"; break; + case EOpLeftShift: out.debug << "left-shift"; break; + case EOpAnd: out.debug << "bitwise and"; break; + case EOpInclusiveOr: out.debug << "inclusive-or"; break; + case EOpExclusiveOr: out.debug << "exclusive-or"; break; + case EOpEqual: out.debug << "Compare Equal"; break; + case EOpNotEqual: out.debug << "Compare Not Equal"; break; + case EOpLessThan: out.debug << "Compare Less Than"; break; + case EOpGreaterThan: out.debug << "Compare Greater Than"; break; + case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; + + case EOpVectorTimesScalar: out.debug << "vector-scale"; break; + case EOpVectorTimesMatrix: out.debug << "vector-times-matrix"; break; + case EOpMatrixTimesVector: out.debug << "matrix-times-vector"; break; + case EOpMatrixTimesScalar: out.debug << "matrix-scale"; break; + case EOpMatrixTimesMatrix: out.debug << "matrix-multiply"; break; + + case EOpLogicalOr: out.debug << "logical-or"; break; + case EOpLogicalXor: out.debug << "logical-xor"; break; + case EOpLogicalAnd: out.debug << "logical-and"; break; + default: out.debug << ""; + } + + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool TOutputTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + TInfoSink& out = infoSink; + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpNegative: out.debug << "Negate value"; break; + case EOpVectorLogicalNot: + case EOpLogicalNot: out.debug << "Negate conditional"; break; + case EOpBitwiseNot: out.debug << "Bitwise not"; break; + + case EOpPostIncrement: out.debug << "Post-Increment"; break; + case EOpPostDecrement: out.debug << "Post-Decrement"; break; + case EOpPreIncrement: out.debug << "Pre-Increment"; break; + case EOpPreDecrement: out.debug << "Pre-Decrement"; break; + + case EOpConvIntToBool: out.debug << "Convert int to bool"; break; + case EOpConvFloatToBool:out.debug << "Convert float to bool";break; + case EOpConvBoolToFloat:out.debug << "Convert bool to float";break; + case EOpConvIntToFloat: out.debug << "Convert int to float"; break; + case EOpConvFloatToInt: out.debug << "Convert float to int"; break; + case EOpConvBoolToInt: out.debug << "Convert bool to int"; break; + + case EOpRadians: out.debug << "radians"; break; + case EOpDegrees: out.debug << "degrees"; break; + case EOpSin: out.debug << "sine"; break; + case EOpCos: out.debug << "cosine"; break; + case EOpTan: out.debug << "tangent"; break; + case EOpAsin: out.debug << "arc sine"; break; + case EOpAcos: out.debug << "arc cosine"; break; + case EOpAtan: out.debug << "arc tangent"; break; + + case EOpExp: out.debug << "exp"; break; + case EOpLog: out.debug << "log"; break; + case EOpExp2: out.debug << "exp2"; break; + case EOpLog2: out.debug << "log2"; break; + case EOpSqrt: out.debug << "sqrt"; break; + case EOpInverseSqrt: out.debug << "inverse sqrt"; break; + + case EOpAbs: out.debug << "Absolute value"; break; + case EOpSign: out.debug << "Sign"; break; + case EOpFloor: out.debug << "Floor"; break; + case EOpCeil: out.debug << "Ceiling"; break; + case EOpFract: out.debug << "Fraction"; break; + + case EOpLength: out.debug << "length"; break; + case EOpNormalize: out.debug << "normalize"; break; +// case EOpDPdx: out.debug << "dPdx"; break; +// case EOpDPdy: out.debug << "dPdy"; break; +// case EOpFwidth: out.debug << "fwidth"; break; + + case EOpAny: out.debug << "any"; break; + case EOpAll: out.debug << "all"; break; + + default: out.debug.message(EPrefixError, "Bad unary op"); + } + + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool TOutputTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + TInfoSink& out = infoSink; + + if (node->getOp() == EOpNull) { + out.debug.message(EPrefixError, "node is still EOpNull!"); + return true; + } + + OutputTreeText(out, node, depth); + + switch (node->getOp()) { + case EOpSequence: out.debug << "Sequence\n"; return true; + case EOpComma: out.debug << "Comma\n"; return true; + case EOpFunction: out.debug << "Function Definition: " << node->getName(); break; + case EOpFunctionCall: out.debug << "Function Call: " << node->getName(); break; + case EOpParameters: out.debug << "Function Parameters: "; break; + + case EOpConstructFloat: out.debug << "Construct float"; break; + case EOpConstructVec2: out.debug << "Construct vec2"; break; + case EOpConstructVec3: out.debug << "Construct vec3"; break; + case EOpConstructVec4: out.debug << "Construct vec4"; break; + case EOpConstructBool: out.debug << "Construct bool"; break; + case EOpConstructBVec2: out.debug << "Construct bvec2"; break; + case EOpConstructBVec3: out.debug << "Construct bvec3"; break; + case EOpConstructBVec4: out.debug << "Construct bvec4"; break; + case EOpConstructInt: out.debug << "Construct int"; break; + case EOpConstructIVec2: out.debug << "Construct ivec2"; break; + case EOpConstructIVec3: out.debug << "Construct ivec3"; break; + case EOpConstructIVec4: out.debug << "Construct ivec4"; break; + case EOpConstructMat2: out.debug << "Construct mat2"; break; + case EOpConstructMat3: out.debug << "Construct mat3"; break; + case EOpConstructMat4: out.debug << "Construct mat4"; break; + case EOpConstructStruct: out.debug << "Construct structure"; break; + + case EOpLessThan: out.debug << "Compare Less Than"; break; + case EOpGreaterThan: out.debug << "Compare Greater Than"; break; + case EOpLessThanEqual: out.debug << "Compare Less Than or Equal"; break; + case EOpGreaterThanEqual: out.debug << "Compare Greater Than or Equal"; break; + case EOpVectorEqual: out.debug << "Equal"; break; + case EOpVectorNotEqual: out.debug << "NotEqual"; break; + + case EOpMod: out.debug << "mod"; break; + case EOpPow: out.debug << "pow"; break; + + case EOpAtan: out.debug << "arc tangent"; break; + + case EOpMin: out.debug << "min"; break; + case EOpMax: out.debug << "max"; break; + case EOpClamp: out.debug << "clamp"; break; + case EOpMix: out.debug << "mix"; break; + case EOpStep: out.debug << "step"; break; + case EOpSmoothStep: out.debug << "smoothstep"; break; + + case EOpDistance: out.debug << "distance"; break; + case EOpDot: out.debug << "dot-product"; break; + case EOpCross: out.debug << "cross-product"; break; + case EOpFaceForward: out.debug << "face-forward"; break; + case EOpReflect: out.debug << "reflect"; break; + case EOpRefract: out.debug << "refract"; break; + case EOpMul: out.debug << "component-wise multiply"; break; + + case EOpItof: out.debug << "itof"; break; + case EOpFtoi: out.debug << "ftoi"; break; + case EOpSkipPixels: out.debug << "skipPixels"; break; + case EOpReadInput: out.debug << "readInput"; break; + case EOpWritePixel: out.debug << "writePixel"; break; + case EOpBitmapLsb: out.debug << "bitmapLSB"; break; + case EOpBitmapMsb: out.debug << "bitmapMSB"; break; + case EOpWriteOutput: out.debug << "writeOutput"; break; + case EOpReadPixel: out.debug << "readPixel"; break; + + default: out.debug.message(EPrefixError, "Bad aggregation op"); + } + + if (node->getOp() != EOpSequence && node->getOp() != EOpParameters) + out.debug << " (" << node->getCompleteString() << ")"; + + out.debug << "\n"; + + return true; +} + +bool TOutputTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + TInfoSink& out = infoSink; + + OutputTreeText(out, node, depth); + + out.debug << "Test condition and select"; + out.debug << " (" << node->getCompleteString() << ")\n"; + + ++depth; + + OutputTreeText(infoSink, node, depth); + out.debug << "Condition\n"; + node->getCondition()->traverse(this); + + OutputTreeText(infoSink, node, depth); + if (node->getTrueBlock()) { + out.debug << "true case\n"; + node->getTrueBlock()->traverse(this); + } else + out.debug << "true case is null\n"; + + if (node->getFalseBlock()) { + OutputTreeText(infoSink, node, depth); + out.debug << "false case\n"; + node->getFalseBlock()->traverse(this); + } + + --depth; + + return false; +} + +void TOutputTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + TInfoSink& out = infoSink; + + int size = node->getType().getObjectSize(); + + for (int i = 0; i < size; i++) { + OutputTreeText(out, node, depth); + switch (node->getUnionArrayPointer()[i].getType()) { + case EbtBool: + if (node->getUnionArrayPointer()[i].getBConst()) + out.debug << "true"; + else + out.debug << "false"; + + out.debug << " (" << "const bool" << ")"; + + out.debug << "\n"; + break; + case EbtFloat: + { + char buf[300]; + sprintf(buf, "%f (%s)", node->getUnionArrayPointer()[i].getFConst(), "const float"); + + out.debug << buf << "\n"; + } + break; + case EbtInt: + { + char buf[300]; + sprintf(buf, "%d (%s)", node->getUnionArrayPointer()[i].getIConst(), "const int"); + + out.debug << buf << "\n"; + break; + } + default: + out.info.message(EPrefixInternalError, "Unknown constant", node->getLine()); + break; + } + } +} + +bool TOutputTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + TInfoSink& out = infoSink; + + OutputTreeText(out, node, depth); + + out.debug << "Loop with condition "; + if (! node->testFirst()) + out.debug << "not "; + out.debug << "tested first\n"; + + ++depth; + + OutputTreeText(infoSink, node, depth); + if (node->getTest()) { + out.debug << "Loop Condition\n"; + node->getTest()->traverse(this); + } else + out.debug << "No loop condition\n"; + + OutputTreeText(infoSink, node, depth); + if (node->getBody()) { + out.debug << "Loop Body\n"; + node->getBody()->traverse(this); + } else + out.debug << "No loop body\n"; + + if (node->getTerminal()) { + OutputTreeText(infoSink, node, depth); + out.debug << "Loop Terminal Expression\n"; + node->getTerminal()->traverse(this); + } + + --depth; + + return false; +} + +bool TOutputTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + TInfoSink& out = infoSink; + + OutputTreeText(out, node, depth); + + switch (node->getFlowOp()) { + case EOpKill: out.debug << "Branch: Kill"; break; + case EOpBreak: out.debug << "Branch: Break"; break; + case EOpContinue: out.debug << "Branch: Continue"; break; + case EOpReturn: out.debug << "Branch: Return"; break; + default: out.debug << "Branch: Unknown Branch"; break; + } + + if (node->getExpression()) { + out.debug << " with expression\n"; + ++depth; + node->getExpression()->traverse(this); + --depth; + } else + out.debug << "\n"; + + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +void TIntermediate::outputTree(TIntermNode* root) +{ + if (root == 0) + return; + + TOutputTraverser it(infoSink); + + root->traverse(&it); +} diff --git a/Compiler/intermediate.h b/Compiler/intermediate.h new file mode 100644 index 000000000..f80691e3c --- /dev/null +++ b/Compiler/intermediate.h @@ -0,0 +1,508 @@ +// +// Copyright (c) 2002-2010 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. +// + +// +// Definition of the in-memory high-level intermediate representation +// of shaders. This is a tree that parser creates. +// +// Nodes in the tree are defined as a hierarchy of classes derived from +// TIntermNode. Each is a node in a tree. There is no preset branching factor; +// each node can have it's own type of list of children. +// + +#ifndef __INTERMEDIATE_H +#define __INTERMEDIATE_H + +#include "Common.h" +#include "Types.h" +#include "ConstantUnion.h" + +// +// Operators used by the high-level (parse tree) representation. +// +enum TOperator { + EOpNull, // if in a node, should only mean a node is still being built + EOpSequence, // denotes a list of statements, or parameters, etc. + EOpFunctionCall, + EOpFunction, // For function definition + EOpParameters, // an aggregate listing the parameters to a function + EOpDeclaration, + + // + // Unary operators + // + + EOpNegative, + EOpLogicalNot, + EOpVectorLogicalNot, + EOpBitwiseNot, + + EOpPostIncrement, + EOpPostDecrement, + EOpPreIncrement, + EOpPreDecrement, + + EOpConvIntToBool, + EOpConvFloatToBool, + EOpConvBoolToFloat, + EOpConvIntToFloat, + EOpConvFloatToInt, + EOpConvBoolToInt, + + // + // binary operations + // + + EOpAdd, + EOpSub, + EOpMul, + EOpDiv, + EOpMod, + EOpRightShift, + EOpLeftShift, + EOpAnd, + EOpInclusiveOr, + EOpExclusiveOr, + EOpEqual, + EOpNotEqual, + EOpVectorEqual, + EOpVectorNotEqual, + EOpLessThan, + EOpGreaterThan, + EOpLessThanEqual, + EOpGreaterThanEqual, + EOpComma, + + EOpVectorTimesScalar, + EOpVectorTimesMatrix, + EOpMatrixTimesVector, + EOpMatrixTimesScalar, + + EOpLogicalOr, + EOpLogicalXor, + EOpLogicalAnd, + + EOpIndexDirect, + EOpIndexIndirect, + EOpIndexDirectStruct, + + EOpVectorSwizzle, + + // + // Built-in functions potentially mapped to operators + // + + EOpRadians, + EOpDegrees, + EOpSin, + EOpCos, + EOpTan, + EOpAsin, + EOpAcos, + EOpAtan, + + EOpPow, + EOpExp, + EOpLog, + EOpExp2, + EOpLog2, + EOpSqrt, + EOpInverseSqrt, + + EOpAbs, + EOpSign, + EOpFloor, + EOpCeil, + EOpFract, + EOpMin, + EOpMax, + EOpClamp, + EOpMix, + EOpStep, + EOpSmoothStep, + + EOpLength, + EOpDistance, + EOpDot, + EOpCross, + EOpNormalize, + EOpFaceForward, + EOpReflect, + EOpRefract, + +// EOpDPdx, // Fragment only +// EOpDPdy, // Fragment only +// EOpFwidth, // Fragment only + + EOpMatrixTimesMatrix, + + EOpAny, + EOpAll, + + EOpItof, // pack/unpack only + EOpFtoi, // pack/unpack only + EOpSkipPixels, // pack/unpack only + EOpReadInput, // unpack only + EOpWritePixel, // unpack only + EOpBitmapLsb, // unpack only + EOpBitmapMsb, // unpack only + EOpWriteOutput, // pack only + EOpReadPixel, // pack only + + // + // Branch + // + + EOpKill, // Fragment only + EOpReturn, + EOpBreak, + EOpContinue, + + // + // Constructors + // + + EOpConstructInt, + EOpConstructBool, + EOpConstructFloat, + EOpConstructVec2, + EOpConstructVec3, + EOpConstructVec4, + EOpConstructBVec2, + EOpConstructBVec3, + EOpConstructBVec4, + EOpConstructIVec2, + EOpConstructIVec3, + EOpConstructIVec4, + EOpConstructMat2, + EOpConstructMat3, + EOpConstructMat4, + EOpConstructStruct, + + // + // moves + // + + EOpAssign, + EOpInitialize, + EOpAddAssign, + EOpSubAssign, + EOpMulAssign, + EOpVectorTimesMatrixAssign, + EOpVectorTimesScalarAssign, + EOpMatrixTimesScalarAssign, + EOpMatrixTimesMatrixAssign, + EOpDivAssign, + EOpModAssign, + EOpAndAssign, + EOpInclusiveOrAssign, + EOpExclusiveOrAssign, + EOpLeftShiftAssign, + EOpRightShiftAssign, + + // + // Array operators + // + + EOpArrayLength, +}; + +class TIntermTraverser; +class TIntermAggregate; +class TIntermBinary; +class TIntermConstantUnion; +class TIntermSelection; +class TIntermTyped; +class TIntermSymbol; +class TInfoSink; + +// +// Base class for the tree nodes +// +class TIntermNode { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermNode() : line(0) {} + virtual TSourceLoc getLine() const { return line; } + virtual void setLine(TSourceLoc l) { line = l; } + virtual void traverse(TIntermTraverser*) = 0; + virtual TIntermTyped* getAsTyped() { return 0; } + virtual TIntermConstantUnion* getAsConstantUnion() { return 0; } + virtual TIntermAggregate* getAsAggregate() { return 0; } + virtual TIntermBinary* getAsBinaryNode() { return 0; } + virtual TIntermSelection* getAsSelectionNode() { return 0; } + virtual TIntermSymbol* getAsSymbolNode() { return 0; } + virtual ~TIntermNode() { } +protected: + TSourceLoc line; +}; + +// +// This is just to help yacc. +// +struct TIntermNodePair { + TIntermNode* node1; + TIntermNode* node2; +}; + +class TIntermSymbol; +class TIntermBinary; + +// +// Intermediate class for nodes that have a type. +// +class TIntermTyped : public TIntermNode { +public: + TIntermTyped(const TType& t) : type(t) { } + virtual TIntermTyped* getAsTyped() { return this; } + virtual void setType(const TType& t) { type = t; } + virtual TType getType() const { return type; } + virtual TType* getTypePointer() { return &type; } + + virtual TBasicType getBasicType() const { return type.getBasicType(); } + virtual TQualifier getQualifier() const { return type.getQualifier(); } + virtual int getNominalSize() const { return type.getNominalSize(); } + virtual int getSize() const { return type.getInstanceSize(); } + virtual bool isMatrix() const { return type.isMatrix(); } + virtual bool isArray() const { return type.isArray(); } + virtual bool isVector() const { return type.isVector(); } + const char* getBasicString() const { return type.getBasicString(); } + const char* getQualifierString() const { return type.getQualifierString(); } + TString getCompleteString() const { return type.getCompleteString(); } + +protected: + TType type; +}; + +// +// Handle for, do-while, and while loops. +// +class TIntermLoop : public TIntermNode { +public: + TIntermLoop(TIntermNode *init, TIntermNode* aBody, TIntermTyped* aTest, TIntermTyped* aTerminal, bool testFirst) : + init(init), + body(aBody), + test(aTest), + terminal(aTerminal), + first(testFirst) { } + virtual void traverse(TIntermTraverser*); + TIntermNode *getInit() { return init; } + TIntermNode *getBody() { return body; } + TIntermTyped *getTest() { return test; } + TIntermTyped *getTerminal() { return terminal; } + bool testFirst() { return first; } +protected: + TIntermNode *init; + TIntermNode *body; // code to loop over + TIntermTyped *test; // exit condition associated with loop, could be 0 for 'for' loops + TIntermTyped *terminal; // exists for for-loops + bool first; // true for while and for, not for do-while +}; + +// +// Handle break, continue, return, and kill. +// +class TIntermBranch : public TIntermNode { +public: + TIntermBranch(TOperator op, TIntermTyped* e) : + flowOp(op), + expression(e) { } + virtual void traverse(TIntermTraverser*); + TOperator getFlowOp() { return flowOp; } + TIntermTyped* getExpression() { return expression; } +protected: + TOperator flowOp; + TIntermTyped* expression; // non-zero except for "return exp;" statements +}; + +// +// Nodes that correspond to symbols or constants in the source code. +// +class TIntermSymbol : public TIntermTyped { +public: + // if symbol is initialized as symbol(sym), the memory comes from the poolallocator of sym. If sym comes from + // per process globalpoolallocator, then it causes increased memory usage per compile + // it is essential to use "symbol = sym" to assign to symbol + TIntermSymbol(int i, const TString& sym, const TType& t) : + TIntermTyped(t), id(i) { symbol = sym;} + virtual int getId() const { return id; } + virtual const TString& getSymbol() const { return symbol; } + virtual void traverse(TIntermTraverser*); + virtual TIntermSymbol* getAsSymbolNode() { return this; } +protected: + int id; + TString symbol; +}; + +class TIntermConstantUnion : public TIntermTyped { +public: + TIntermConstantUnion(constUnion *unionPointer, const TType& t) : TIntermTyped(t), unionArrayPointer(unionPointer) { } + constUnion* getUnionArrayPointer() const { return unionArrayPointer; } + void setUnionArrayPointer(constUnion *c) { unionArrayPointer = c; } + virtual TIntermConstantUnion* getAsConstantUnion() { return this; } + virtual void traverse(TIntermTraverser* ); + virtual TIntermTyped* fold(TOperator, TIntermTyped*, TInfoSink&); +protected: + constUnion *unionArrayPointer; +}; + +// +// Intermediate class for node types that hold operators. +// +class TIntermOperator : public TIntermTyped { +public: + TOperator getOp() const { return op; } + bool modifiesState() const; + bool isConstructor() const; + virtual bool promote(TInfoSink&) { return true; } +protected: + TIntermOperator(TOperator o) : TIntermTyped(TType(EbtFloat)), op(o) {} + TIntermOperator(TOperator o, TType& t) : TIntermTyped(t), op(o) {} + TOperator op; +}; + +// +// Nodes for all the basic binary math operators. +// +class TIntermBinary : public TIntermOperator { +public: + TIntermBinary(TOperator o) : TIntermOperator(o) {} + virtual void traverse(TIntermTraverser*); + virtual void setLeft(TIntermTyped* n) { left = n; } + virtual void setRight(TIntermTyped* n) { right = n; } + virtual TIntermTyped* getLeft() const { return left; } + virtual TIntermTyped* getRight() const { return right; } + virtual TIntermBinary* getAsBinaryNode() { return this; } + virtual bool promote(TInfoSink&); +protected: + TIntermTyped* left; + TIntermTyped* right; +}; + +// +// Nodes for unary math operators. +// +class TIntermUnary : public TIntermOperator { +public: + TIntermUnary(TOperator o, TType& t) : TIntermOperator(o, t), operand(0) {} + TIntermUnary(TOperator o) : TIntermOperator(o), operand(0) {} + virtual void traverse(TIntermTraverser*); + virtual void setOperand(TIntermTyped* o) { operand = o; } + virtual TIntermTyped* getOperand() { return operand; } + virtual bool promote(TInfoSink&); +protected: + TIntermTyped* operand; +}; + +typedef TVector TIntermSequence; +typedef TVector TQualifierList; +// +// Nodes that operate on an arbitrary sized set of children. +// +class TIntermAggregate : public TIntermOperator { +public: + TIntermAggregate() : TIntermOperator(EOpNull), userDefined(false), pragmaTable(0) { } + TIntermAggregate(TOperator o) : TIntermOperator(o), pragmaTable(0) { } + ~TIntermAggregate() { delete pragmaTable; } + virtual TIntermAggregate* getAsAggregate() { return this; } + virtual void setOperator(TOperator o) { op = o; } + virtual TIntermSequence& getSequence() { return sequence; } + virtual void setName(const TString& n) { name = n; } + virtual const TString& getName() const { return name; } + virtual void traverse(TIntermTraverser*); + virtual void setUserDefined() { userDefined = true; } + virtual bool isUserDefined() { return userDefined; } + virtual TQualifierList& getQualifier() { return qualifier; } + void setOptimize(bool o) { optimize = o; } + void setDebug(bool d) { debug = d; } + bool getOptimize() { return optimize; } + bool getDebug() { return debug; } + void addToPragmaTable(const TPragmaTable& pTable); + const TPragmaTable& getPragmaTable() const { return *pragmaTable; } +protected: + TIntermAggregate(const TIntermAggregate&); // disallow copy constructor + TIntermAggregate& operator=(const TIntermAggregate&); // disallow assignment operator + TIntermSequence sequence; + TQualifierList qualifier; + TString name; + bool userDefined; // used for user defined function names + bool optimize; + bool debug; + TPragmaTable *pragmaTable; +}; + +// +// For if tests. Simplified since there is no switch statement. +// +class TIntermSelection : public TIntermTyped { +public: + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB) : + TIntermTyped(TType(EbtVoid)), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + TIntermSelection(TIntermTyped* cond, TIntermNode* trueB, TIntermNode* falseB, const TType& type) : + TIntermTyped(type), condition(cond), trueBlock(trueB), falseBlock(falseB) {} + virtual void traverse(TIntermTraverser*); + virtual TIntermNode* getCondition() const { return condition; } + virtual TIntermNode* getTrueBlock() const { return trueBlock; } + virtual TIntermNode* getFalseBlock() const { return falseBlock; } + virtual TIntermSelection* getAsSelectionNode() { return this; } +protected: + TIntermTyped* condition; + TIntermNode* trueBlock; + TIntermNode* falseBlock; +}; + +enum Visit +{ + PreVisit, + InVisit, + PostVisit +}; + +// +// For traversing the tree. User should derive from this, +// put their traversal specific data in it, and then pass +// it to a Traverse method. +// +// When using this, just fill in the methods for nodes you want visited. +// Return false from a pre-visit to skip visiting that node's subtree. +// +class TIntermTraverser +{ +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermTraverser(bool preVisit = true, bool inVisit = false, bool postVisit = false, bool rightToLeft = false) : + preVisit(preVisit), + inVisit(inVisit), + postVisit(postVisit), + rightToLeft(rightToLeft) + { + depth = 0; + } + + virtual void visitSymbol(TIntermSymbol*) {} + virtual void visitConstantUnion(TIntermConstantUnion*) {} + virtual bool visitBinary(Visit visit, TIntermBinary*) {return true;} + virtual bool visitUnary(Visit visit, TIntermUnary*) {return true;} + virtual bool visitSelection(Visit visit, TIntermSelection*) {return true;} + virtual bool visitAggregate(Visit visit, TIntermAggregate*) {return true;} + virtual bool visitLoop(Visit visit, TIntermLoop*) {return true;} + virtual bool visitBranch(Visit visit, TIntermBranch*) {return true;} + + void incrementDepth() {depth++;} + void decrementDepth() {depth--;} + + const bool preVisit; + const bool inVisit; + const bool postVisit; + const bool rightToLeft; + +protected: + int depth; +}; + +#endif // __INTERMEDIATE_H diff --git a/Compiler/localintermediate.h b/Compiler/localintermediate.h new file mode 100644 index 000000000..b9cd3f20a --- /dev/null +++ b/Compiler/localintermediate.h @@ -0,0 +1,58 @@ +// +// Copyright (c) 2002-2010 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 _LOCAL_INTERMEDIATE_INCLUDED_ +#define _LOCAL_INTERMEDIATE_INCLUDED_ + +#include "intermediate.h" +#include "ShaderLang.h" +#include "SymbolTable.h" + +struct TVectorFields { + int offsets[4]; + int num; +}; + +// +// Set of helper functions to help parse and build the tree. +// +class TInfoSink; +class TIntermediate { +public: + POOL_ALLOCATOR_NEW_DELETE(GlobalPoolAllocator) + + TIntermediate(TInfoSink& i) : infoSink(i) { } + TIntermSymbol* addSymbol(int Id, const TString&, const TType&, TSourceLoc); + TIntermTyped* addConversion(TOperator, const TType&, TIntermTyped*); + TIntermTyped* addBinaryMath(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc, TSymbolTable&); + TIntermTyped* addAssign(TOperator op, TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermTyped* addIndex(TOperator op, TIntermTyped* base, TIntermTyped* index, TSourceLoc); + TIntermTyped* addUnaryMath(TOperator op, TIntermNode* child, TSourceLoc, TSymbolTable&); + TIntermAggregate* growAggregate(TIntermNode* left, TIntermNode* right, TSourceLoc); + TIntermAggregate* makeAggregate(TIntermNode* node, TSourceLoc); + TIntermAggregate* setAggregateOperator(TIntermNode*, TOperator, TSourceLoc); + TIntermNode* addSelection(TIntermTyped* cond, TIntermNodePair code, TSourceLoc); + TIntermTyped* addSelection(TIntermTyped* cond, TIntermTyped* trueBlock, TIntermTyped* falseBlock, TSourceLoc); + TIntermTyped* addComma(TIntermTyped* left, TIntermTyped* right, TSourceLoc); + TIntermConstantUnion* addConstantUnion(constUnion*, const TType&, TSourceLoc); + TIntermTyped* promoteConstantUnion(TBasicType, TIntermConstantUnion*) ; + bool parseConstTree(TSourceLoc, TIntermNode*, constUnion*, TOperator, TSymbolTable&, TType, bool singleConstantParam = false); + TIntermNode* addLoop(TIntermNode*, TIntermNode*, TIntermTyped*, TIntermTyped*, bool testFirst, TSourceLoc); + TIntermBranch* addBranch(TOperator, TSourceLoc); + TIntermBranch* addBranch(TOperator, TIntermTyped*, TSourceLoc); + TIntermTyped* addSwizzle(TVectorFields&, TSourceLoc); + bool postProcess(TIntermNode*, EShLanguage); + void remove(TIntermNode*); + void outputTree(TIntermNode*); + +protected: + TInfoSink& infoSink; + +private: + void operator=(TIntermediate&); // prevent assignments +}; + +#endif // _LOCAL_INTERMEDIATE_INCLUDED_ diff --git a/Compiler/osinclude.h b/Compiler/osinclude.h new file mode 100644 index 000000000..ddeb34eda --- /dev/null +++ b/Compiler/osinclude.h @@ -0,0 +1,41 @@ +// +// Copyright (c) 2002-2010 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 __OSINCLUDE_H +#define __OSINCLUDE_H + +// +// This file contains contains the window's specific datatypes and +// declares any windows specific functions. +// + +#if !(defined(_WIN32) || defined(_WIN64)) +#error Trying to include a windows specific file in a non windows build. +#endif + +#define STRICT +#define VC_EXTRALEAN 1 +#include +#include + + +// +// Thread Local Storage Operations +// +typedef DWORD OS_TLSIndex; +#define OS_INVALID_TLS_INDEX (TLS_OUT_OF_INDEXES) + +OS_TLSIndex OS_AllocTLSIndex(); +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue); +bool OS_FreeTLSIndex(OS_TLSIndex nIndex); + +inline void* OS_GetTLSValue(OS_TLSIndex nIndex) +{ + assert(nIndex != OS_INVALID_TLS_INDEX); + return TlsGetValue(nIndex); +} + +#endif // __OSINCLUDE_H diff --git a/Compiler/ossource.cpp b/Compiler/ossource.cpp new file mode 100644 index 000000000..ed93efe05 --- /dev/null +++ b/Compiler/ossource.cpp @@ -0,0 +1,57 @@ +// +// Copyright (c) 2002-2010 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 "osinclude.h" +// +// This file contains contains the window's specific functions +// + +#if !(defined(_WIN32) || defined(_WIN64)) +#error Trying to build a windows specific file in a non windows build. +#endif + + +// +// Thread Local Storage Operations +// +OS_TLSIndex OS_AllocTLSIndex() +{ + DWORD dwIndex = TlsAlloc(); + if (dwIndex == TLS_OUT_OF_INDEXES) { + assert(0 && "OS_AllocTLSIndex(): Unable to allocate Thread Local Storage"); + return OS_INVALID_TLS_INDEX; + } + + return dwIndex; +} + + +bool OS_SetTLSValue(OS_TLSIndex nIndex, void *lpvValue) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsSetValue(nIndex, lpvValue)) + return true; + else + return false; +} + + +bool OS_FreeTLSIndex(OS_TLSIndex nIndex) +{ + if (nIndex == OS_INVALID_TLS_INDEX) { + assert(0 && "OS_SetTLSValue(): Invalid TLS Index"); + return false; + } + + if (TlsFree(nIndex)) + return true; + else + return false; +} diff --git a/Compiler/parseConst.cpp b/Compiler/parseConst.cpp new file mode 100644 index 000000000..39606e961 --- /dev/null +++ b/Compiler/parseConst.cpp @@ -0,0 +1,227 @@ +// +// Copyright (c) 2002-2010 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 "ParseHelper.h" + +// +// Use this class to carry along data from node to node in +// the traversal +// +class TConstTraverser : public TIntermTraverser { +public: + TConstTraverser(constUnion* cUnion, bool singleConstParam, TOperator constructType, TInfoSink& sink, TSymbolTable& symTable, TType& t) : unionArray(cUnion), type(t), + constructorType(constructType), singleConstantParam(singleConstParam), infoSink(sink), symbolTable(symTable), error(false), isMatrix(false), matrixSize(0) + { + index = 0; + } + + bool error; + +protected: + void visitSymbol(TIntermSymbol*); + void visitConstantUnion(TIntermConstantUnion*); + bool visitBinary(Visit visit, TIntermBinary*); + bool visitUnary(Visit visit, TIntermUnary*); + bool visitSelection(Visit visit, TIntermSelection*); + bool visitAggregate(Visit visit, TIntermAggregate*); + bool visitLoop(Visit visit, TIntermLoop*); + bool visitBranch(Visit visit, TIntermBranch*); + + int index; + constUnion *unionArray; + TType type; + TOperator constructorType; + bool singleConstantParam; + TInfoSink& infoSink; + TSymbolTable& symbolTable; + int size; // size of the constructor ( 4 for vec4) + bool isMatrix; + int matrixSize; // dimension of the matrix (nominal size and not the instance size) +}; + +// +// The rest of the file are the traversal functions. The last one +// is the one that starts the traversal. +// +// Return true from interior nodes to have the external traversal +// continue on to children. If you process children yourself, +// return false. +// + +void TConstTraverser::visitSymbol(TIntermSymbol* node) +{ + infoSink.info.message(EPrefixInternalError, "Symbol Node found in constant constructor", node->getLine()); + return; + +} + +bool TConstTraverser::visitBinary(Visit visit, TIntermBinary* node) +{ + TQualifier qualifier = node->getType().getQualifier(); + + if (qualifier != EvqConst) { + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to %s", type.getCompleteString().c_str()); + infoSink.info.message(EPrefixError, buf, node->getLine()); + error = true; + return false; + } + + infoSink.info.message(EPrefixInternalError, "Binary Node found in constant constructor", node->getLine()); + + return false; +} + +bool TConstTraverser::visitUnary(Visit visit, TIntermUnary* node) +{ + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to '%s'", type.getCompleteString().c_str()); + infoSink.info.message(EPrefixError, buf, node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitAggregate(Visit visit, TIntermAggregate* node) +{ + if (!node->isConstructor() && node->getOp() != EOpComma) { + char buf[200]; + sprintf(buf, "'constructor' : assigning non-constant to '%s'", type.getCompleteString().c_str()); + infoSink.info.message(EPrefixError, buf, node->getLine()); + error = true; + return false; + } + + if (node->getSequence().size() == 0) { + error = true; + return false; + } + + bool flag = node->getSequence().size() == 1 && node->getSequence()[0]->getAsTyped()->getAsConstantUnion(); + if (flag) + { + singleConstantParam = true; + constructorType = node->getOp(); + size = node->getType().getObjectSize(); + + if (node->getType().isMatrix()) { + isMatrix = true; + matrixSize = node->getType().getNominalSize(); + } + } + + for (TIntermSequence::iterator p = node->getSequence().begin(); + p != node->getSequence().end(); p++) { + + if (node->getOp() == EOpComma) + index = 0; + + (*p)->traverse(this); + } + if (flag) + { + singleConstantParam = false; + constructorType = EOpNull; + size = 0; + isMatrix = false; + matrixSize = 0; + } + return false; +} + +bool TConstTraverser::visitSelection(Visit visit, TIntermSelection* node) +{ + infoSink.info.message(EPrefixInternalError, "Selection Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +void TConstTraverser::visitConstantUnion(TIntermConstantUnion* node) +{ + constUnion* leftUnionArray = unionArray; + int instanceSize = type.getObjectSize(); + + if (index >= instanceSize) + return; + + if (!singleConstantParam) { + int size = node->getType().getObjectSize(); + + constUnion *rightUnionArray = node->getUnionArrayPointer(); + for (int i=0; i < size; i++) { + if (index >= instanceSize) + return; + leftUnionArray[index] = rightUnionArray[i]; + + (index)++; + } + } else { + int totalSize = index + size; + constUnion *rightUnionArray = node->getUnionArrayPointer(); + if (!isMatrix) { + int count = 0; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + + leftUnionArray[i] = rightUnionArray[count]; + + (index)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } else { // for matrix constructors + int count = 0; + int element = index; + for (int i = index; i < totalSize; i++) { + if (i >= instanceSize) + return; + if (element - i == 0 || (i - element) % (matrixSize + 1) == 0 ) + leftUnionArray[i] = rightUnionArray[count]; + else + leftUnionArray[i].setFConst(0.0f); + + (element)++; + + if (node->getType().getObjectSize() > 1) + count++; + } + } + } +} + +bool TConstTraverser::visitLoop(Visit visit, TIntermLoop* node) +{ + infoSink.info.message(EPrefixInternalError, "Loop Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +bool TConstTraverser::visitBranch(Visit visit, TIntermBranch* node) +{ + infoSink.info.message(EPrefixInternalError, "Branch Node found in constant constructor", node->getLine()); + error = true; + return false; +} + +// +// This function is the one to call externally to start the traversal. +// Individual functions can be initialized to 0 to skip processing of that +// type of node. It's children will still be processed. +// +bool TIntermediate::parseConstTree(TSourceLoc line, TIntermNode* root, constUnion* unionArray, TOperator constructorType, TSymbolTable& symbolTable, TType t, bool singleConstantParam) +{ + if (root == 0) + return false; + + TConstTraverser it(unionArray, singleConstantParam, constructorType, infoSink, symbolTable, t); + + root->traverse(&it); + if (it.error) + return true; + else + return false; +} diff --git a/Compiler/unistd.h b/Compiler/unistd.h new file mode 100644 index 000000000..c7c914709 --- /dev/null +++ b/Compiler/unistd.h @@ -0,0 +1 @@ +// This is a NULL file and is meant to be empty diff --git a/Include/Config.h b/Include/Config.h new file mode 100644 index 000000000..42fe56eb0 --- /dev/null +++ b/Include/Config.h @@ -0,0 +1,115 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Config.h: Defines the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.4] section 3.4 page 15. + +#ifndef INCLUDE_CONFIG_H_ +#define INCLUDE_CONFIG_H_ + +#define EGLAPI +#include +#include + +#include + +#include "angleutils.h" + +namespace egl +{ +class Config +{ + public: + Config(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample); + + void setDefaults(); + void set(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample); + EGLConfig getHandle() const; + + const D3DDISPLAYMODE mDisplayMode; + const D3DFORMAT mRenderTargetFormat; + const D3DFORMAT mDepthStencilFormat; + const EGLint mMultiSample; + + EGLint mBufferSize; // Depth of the color buffer + EGLint mRedSize; // Bits of Red in the color buffer + EGLint mGreenSize; // Bits of Green in the color buffer + EGLint mBlueSize; // Bits of Blue in the color buffer + EGLint mLuminanceSize; // Bits of Luminance in the color buffer + EGLint mAlphaSize; // Bits of Alpha in the color buffer + EGLint mAlphaMaskSize; // Bits of Alpha Mask in the mask buffer + EGLBoolean mBindToTextureRGB; // True if bindable to RGB textures. + EGLBoolean mBindToTextureRGBA; // True if bindable to RGBA textures. + EGLenum mColorBufferType; // Color buffer type + EGLenum mConfigCaveat; // Any caveats for the configuration + EGLint mConfigID; // Unique EGLConfig identifier + EGLint mConformant; // Whether contexts created with this config are conformant + EGLint mDepthSize; // Bits of Z in the depth buffer + EGLint mLevel; // Frame buffer level + EGLBoolean mMatchNativePixmap; // Match the native pixmap format + EGLint mMaxPBufferWidth; // Maximum width of pbuffer + EGLint mMaxPBufferHeight; // Maximum height of pbuffer + EGLint mMaxPBufferPixels; // Maximum size of pbuffer + EGLint mMaxSwapInterval; // Maximum swap interval + EGLint mMinSwapInterval; // Minimum swap interval + EGLBoolean mNativeRenderable; // EGL_TRUE if native rendering APIs can render to surface + EGLint mNativeVisualID; // Handle of corresponding native visual + EGLint mNativeVisualType; // Native visual type of the associated visual + EGLint mRenderableType; // Which client rendering APIs are supported. + EGLint mSampleBuffers; // Number of multisample buffers + EGLint mSamples; // Number of samples per pixel + EGLint mStencilSize; // Bits of Stencil in the stencil buffer + EGLint mSurfaceType; // Which types of EGL surfaces are supported. + EGLenum mTransparentType; // Type of transparency supported + EGLint mTransparentRedValue; // Transparent red value + EGLint mTransparentGreenValue; // Transparent green value + EGLint mTransparentBlueValue; // Transparent blue value +}; + +// Function object used by STL sorting routines for ordering Configs according to [EGL] section 3.4.1 page 24. +class SortConfig +{ + public: + explicit SortConfig(const EGLint *attribList); + + bool operator()(const Config *x, const Config *y) const; + bool operator()(const Config &x, const Config &y) const; + + private: + void scanForWantedComponents(const EGLint *attribList); + EGLint wantedComponentsSize(const Config &config) const; + + bool mWantRed; + bool mWantGreen; + bool mWantBlue; + bool mWantAlpha; + bool mWantLuminance; +}; + +class ConfigSet +{ + public: + ConfigSet(); + + void add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample); + void enumerate(); + size_t size() const; + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + const egl::Config *get(EGLConfig configHandle); + + typedef std::set Set; + typedef Set::iterator Iterator; + Set mSet; + + private: + DISALLOW_COPY_AND_ASSIGN(ConfigSet); + + static const EGLint mSortAttribs[]; +}; +} + +#endif // INCLUDE_CONFIG_H_ diff --git a/Include/Context.h b/Include/Context.h new file mode 100644 index 000000000..86a4d14b5 --- /dev/null +++ b/Include/Context.h @@ -0,0 +1,292 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Context.h: Defines the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#ifndef INCLUDE_CONTEXT_H_ +#define INCLUDE_CONTEXT_H_ + +#define GL_APICALL +#include +#define EGLAPI +#include +#include + +#include + +#include "angleutils.h" + +namespace egl +{ +class Display; +class Surface; +class Config; +} + +namespace gl +{ +class Buffer; +class Shader; +class Program; +class Texture; +class Texture2D; +class TextureCubeMap; +class Framebuffer; +class Renderbuffer; +class Colorbuffer; +class Depthbuffer; +class Stencilbuffer; + +enum +{ + MAX_VERTEX_ATTRIBS = 8, + MAX_VERTEX_UNIFORM_VECTORS = 128, + MAX_VARYING_VECTORS = 8, + MAX_COMBINED_TEXTURE_IMAGE_UNITS = 8, + MAX_VERTEX_TEXTURE_IMAGE_UNITS = 0, + MAX_TEXTURE_IMAGE_UNITS = 8, + MAX_FRAGMENT_UNIFORM_VECTORS = 16, + MAX_RENDERBUFFER_SIZE = 4096, // FIXME: Verify + MAX_DRAW_BUFFERS = 1, + + IMPLEMENTATION_COLOR_READ_FORMAT = GL_RGB, + IMPLEMENTATION_COLOR_READ_TYPE = GL_UNSIGNED_SHORT_5_6_5 +}; + +struct Color +{ + float red; + float green; + float blue; + float alpha; +}; + +// Helper structure describing a single vertex attribute array +struct Array +{ + Array(); + + bool enabled; + GLuint boundBuffer; + GLint size; + GLenum type; + GLboolean normalized; + GLsizei stride; + const void *pointer; +}; + +// Helper structure to store all raw state +struct State +{ + Color colorClearValue; + GLclampf depthClearValue; + int stencilClearValue; + + bool cullFace; + GLenum cullMode; + GLenum frontFace; + bool depthTest; + GLenum depthFunc; + bool blend; + GLenum sourceBlendRGB; + GLenum destBlendRGB; + GLenum sourceBlendAlpha; + GLenum destBlendAlpha; + GLenum blendEquationRGB; + GLenum blendEquationAlpha; + Color blendColor; + bool stencilTest; + GLenum stencilFunc; + GLint stencilRef; + GLuint stencilMask; + GLenum stencilFail; + GLenum stencilPassDepthFail; + GLenum stencilPassDepthPass; + GLuint stencilWritemask; + GLenum stencilBackFunc; + GLint stencilBackRef; + GLuint stencilBackMask; + GLenum stencilBackFail; + GLenum stencilBackPassDepthFail; + GLenum stencilBackPassDepthPass; + GLuint stencilBackWritemask; + bool polygonOffsetFill; + bool sampleAlphaToCoverage; + bool sampleCoverage; + GLclampf sampleCoverageValue; + GLboolean sampleCoverageInvert; + bool scissorTest; + bool dither; + + GLint viewportX; + GLint viewportY; + GLsizei viewportWidth; + GLsizei viewportHeight; + float zNear; + float zFar; + + GLint scissorX; + GLint scissorY; + GLsizei scissorWidth; + GLsizei scissorHeight; + + bool colorMaskRed; + bool colorMaskGreen; + bool colorMaskBlue; + bool colorMaskAlpha; + bool depthMask; + + int activeSampler; // Active texture unit selector - GL_TEXTURE0 + GLuint arrayBuffer; + GLuint elementArrayBuffer; + GLuint texture2D; + GLuint textureCubeMap; + GLuint framebuffer; + GLuint renderbuffer; + GLuint currentProgram; + + Array vertexAttribute[MAX_VERTEX_ATTRIBS]; + GLuint samplerTexture[MAX_TEXTURE_IMAGE_UNITS]; + + unsigned int startIndex; +}; + +class Context : public State +{ + public: + Context(const egl::Config *config); + + ~Context(); + + void makeCurrent(egl::Display *display, egl::Surface *surface); + + void setClearColor(float red, float green, float blue, float alpha); + void setClearDepth(float depth); + void setClearStencil(int stencil); + + GLuint createBuffer(); + GLuint createShader(GLenum type); + GLuint createProgram(); + GLuint createTexture(); + GLuint createFramebuffer(); + GLuint createRenderbuffer(); + + void deleteBuffer(GLuint buffer); + void deleteShader(GLuint shader); + void deleteProgram(GLuint program); + void deleteTexture(GLuint texture); + void deleteFramebuffer(GLuint framebuffer); + void deleteRenderbuffer(GLuint renderbuffer); + + void bindArrayBuffer(GLuint buffer); + void bindElementArrayBuffer(GLuint buffer); + void bindTexture2D(GLuint texture); + void bindTextureCubeMap(GLuint texture); + void bindFramebuffer(GLuint framebuffer); + void bindRenderbuffer(GLuint renderbuffer); + void useProgram(GLuint program); + + void setFramebufferZero(Framebuffer *framebuffer); + void setColorbufferZero(Colorbuffer *renderbuffer); + void setDepthbufferZero(Depthbuffer *depthBuffer); + void setStencilbufferZero(Stencilbuffer *stencilBuffer); + void setRenderbuffer(Renderbuffer *renderbuffer); + + Buffer *getBuffer(GLuint handle); + Shader *getShader(GLuint handle); + Program *getProgram(GLuint handle); + Texture *getTexture(GLuint handle); + Framebuffer *getFramebuffer(GLuint handle); + Renderbuffer *getRenderbuffer(GLuint handle); + Colorbuffer *getColorbuffer(GLuint handle); + Depthbuffer *getDepthbuffer(GLuint handle); + Stencilbuffer *getStencilbuffer(GLuint handle); + + Buffer *getArrayBuffer(); + Buffer *getElementArrayBuffer(); + Program *getCurrentProgram(); + Texture2D *getTexture2D(); + TextureCubeMap *getTextureCubeMap(); + Texture *getSamplerTexture(unsigned int sampler); + Framebuffer *getFramebuffer(); + + bool applyRenderTarget(bool ignoreViewport); + void applyState(); + void applyVertexBuffer(int count); + void applyIndexBuffer(const void *indices, int length); + void applyShaders(); + void applyTextures(); + + void readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); + void clear(GLbitfield mask); + void drawArrays(GLenum mode, GLint first, GLsizei count); + void drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices); + void finish(); + void flush(); + + void recordInvalidEnum(); + void recordInvalidValue(); + void recordInvalidOperation(); + void recordOutOfMemory(); + void recordInvalidFramebufferOperation(); + + GLenum getError(); + + private: + DISALLOW_COPY_AND_ASSIGN(Context); + + void detachBuffer(GLuint buffer); + void detachTexture(GLuint texture); + void detachFramebuffer(GLuint framebuffer); + void detachRenderbuffer(GLuint renderbuffer); + + const egl::Config *const mConfig; + + Texture2D *mTexture2DZero; + TextureCubeMap *mTextureCubeMapZero; + + Colorbuffer *mColorbufferZero; + Depthbuffer *mDepthbufferZero; + Stencilbuffer *mStencilbufferZero; + + typedef std::map BufferMap; + BufferMap mBufferMap; + + typedef std::map ShaderMap; + ShaderMap mShaderMap; + + typedef std::map ProgramMap; + ProgramMap mProgramMap; + + typedef std::map TextureMap; + TextureMap mTextureMap; + + typedef std::map FramebufferMap; + FramebufferMap mFramebufferMap; + + typedef std::map RenderbufferMap; + RenderbufferMap mRenderbufferMap; + + // Recorded errors + bool mInvalidEnum; + bool mInvalidValue; + bool mInvalidOperation; + bool mOutOfMemory; + bool mInvalidFramebufferOperation; +}; +} + +extern "C" +{ +// Exported functions for use by EGL +gl::Context *glCreateContext(const egl::Config *config); +void glDestroyContext(gl::Context *context); +void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface); +gl::Context *glGetCurrentContext(); +} + +#endif // INCLUDE_CONTEXT_H_ diff --git a/Include/Display.h b/Include/Display.h new file mode 100644 index 000000000..db58a74e0 --- /dev/null +++ b/Include/Display.h @@ -0,0 +1,74 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Display.h: Defines the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#ifndef INCLUDE_DISPLAY_H_ +#define INCLUDE_DISPLAY_H_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include + +#include "Config.h" +#include "Surface.h" +#include "Context.h" + +#include + +namespace egl +{ +class Display +{ + public: + Display(HDC deviceContext); + + ~Display(); + + bool initialize(); + void terminate(); + + bool getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig); + bool getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value); + + egl::Surface *createWindowSurface(HWND window, EGLConfig config); + EGLContext createContext(EGLConfig configHandle); + + void destroySurface(egl::Surface *surface); + void destroyContext(gl::Context *context); + + bool isInitialized(); + bool isValidConfig(EGLConfig config); + bool isValidContext(gl::Context *context); + bool isValidSurface(egl::Surface *surface); + bool hasExistingWindowSurface(HWND window); + + virtual IDirect3DDevice9 *getDevice(); + + private: + DISALLOW_COPY_AND_ASSIGN(Display); + const HDC mDc; + + UINT mAdapter; + D3DDEVTYPE mDeviceType; + IDirect3D9 *mD3d9; + IDirect3DDevice9 *mDevice; + + typedef std::set SurfaceSet; + SurfaceSet mSurfaceSet; + + ConfigSet mConfigSet; + + typedef std::set ContextSet; + ContextSet mContextSet; +}; +} + +#endif // INCLUDE_DISPLAY_H_ diff --git a/Include/EGL/egl.h b/Include/EGL/egl.h new file mode 100644 index 000000000..22eba930e --- /dev/null +++ b/Include/EGL/egl.h @@ -0,0 +1,329 @@ +/* -*- mode: c; tab-width: 8; -*- */ +/* vi: set sw=4 ts=8: */ +/* Reference version of egl.h for EGL 1.4. + */ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#ifndef __egl_h_ +#define __egl_h_ + +/* All platform-dependent types and macro boilerplate (such as EGLAPI + * and EGLAPIENTRY) should go in eglplatform.h. + */ +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* EGL Types */ +/* EGLint is defined in eglplatform.h */ +typedef unsigned int EGLBoolean; +typedef unsigned int EGLenum; +typedef void *EGLConfig; +typedef void *EGLContext; +typedef void *EGLDisplay; +typedef void *EGLSurface; +typedef void *EGLClientBuffer; + +/* EGL Versioning */ +#define EGL_VERSION_1_0 1 +#define EGL_VERSION_1_1 1 +#define EGL_VERSION_1_2 1 +#define EGL_VERSION_1_3 1 +#define EGL_VERSION_1_4 1 + +/* EGL Enumerants. Bitmasks and other exceptional cases aside, most + * enums are assigned unique values starting at 0x3000. + */ + +/* EGL aliases */ +#define EGL_FALSE 0 +#define EGL_TRUE 1 + +/* Out-of-band handle values */ +#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0) +#define EGL_NO_CONTEXT ((EGLContext)0) +#define EGL_NO_DISPLAY ((EGLDisplay)0) +#define EGL_NO_SURFACE ((EGLSurface)0) + +/* Out-of-band attribute value */ +#define EGL_DONT_CARE ((EGLint)-1) + +/* Errors / GetError return values */ +#define EGL_SUCCESS 0x3000 +#define EGL_NOT_INITIALIZED 0x3001 +#define EGL_BAD_ACCESS 0x3002 +#define EGL_BAD_ALLOC 0x3003 +#define EGL_BAD_ATTRIBUTE 0x3004 +#define EGL_BAD_CONFIG 0x3005 +#define EGL_BAD_CONTEXT 0x3006 +#define EGL_BAD_CURRENT_SURFACE 0x3007 +#define EGL_BAD_DISPLAY 0x3008 +#define EGL_BAD_MATCH 0x3009 +#define EGL_BAD_NATIVE_PIXMAP 0x300A +#define EGL_BAD_NATIVE_WINDOW 0x300B +#define EGL_BAD_PARAMETER 0x300C +#define EGL_BAD_SURFACE 0x300D +#define EGL_CONTEXT_LOST 0x300E /* EGL 1.1 - IMG_power_management */ + +/* Reserved 0x300F-0x301F for additional errors */ + +/* Config attributes */ +#define EGL_BUFFER_SIZE 0x3020 +#define EGL_ALPHA_SIZE 0x3021 +#define EGL_BLUE_SIZE 0x3022 +#define EGL_GREEN_SIZE 0x3023 +#define EGL_RED_SIZE 0x3024 +#define EGL_DEPTH_SIZE 0x3025 +#define EGL_STENCIL_SIZE 0x3026 +#define EGL_CONFIG_CAVEAT 0x3027 +#define EGL_CONFIG_ID 0x3028 +#define EGL_LEVEL 0x3029 +#define EGL_MAX_PBUFFER_HEIGHT 0x302A +#define EGL_MAX_PBUFFER_PIXELS 0x302B +#define EGL_MAX_PBUFFER_WIDTH 0x302C +#define EGL_NATIVE_RENDERABLE 0x302D +#define EGL_NATIVE_VISUAL_ID 0x302E +#define EGL_NATIVE_VISUAL_TYPE 0x302F +#define EGL_PRESERVED_RESOURCES 0x3030 +#define EGL_SAMPLES 0x3031 +#define EGL_SAMPLE_BUFFERS 0x3032 +#define EGL_SURFACE_TYPE 0x3033 +#define EGL_TRANSPARENT_TYPE 0x3034 +#define EGL_TRANSPARENT_BLUE_VALUE 0x3035 +#define EGL_TRANSPARENT_GREEN_VALUE 0x3036 +#define EGL_TRANSPARENT_RED_VALUE 0x3037 +#define EGL_NONE 0x3038 /* Attrib list terminator */ +#define EGL_BIND_TO_TEXTURE_RGB 0x3039 +#define EGL_BIND_TO_TEXTURE_RGBA 0x303A +#define EGL_MIN_SWAP_INTERVAL 0x303B +#define EGL_MAX_SWAP_INTERVAL 0x303C +#define EGL_LUMINANCE_SIZE 0x303D +#define EGL_ALPHA_MASK_SIZE 0x303E +#define EGL_COLOR_BUFFER_TYPE 0x303F +#define EGL_RENDERABLE_TYPE 0x3040 +#define EGL_MATCH_NATIVE_PIXMAP 0x3041 /* Pseudo-attribute (not queryable) */ +#define EGL_CONFORMANT 0x3042 + +/* Reserved 0x3041-0x304F for additional config attributes */ + +/* Config attribute values */ +#define EGL_SLOW_CONFIG 0x3050 /* EGL_CONFIG_CAVEAT value */ +#define EGL_NON_CONFORMANT_CONFIG 0x3051 /* EGL_CONFIG_CAVEAT value */ +#define EGL_TRANSPARENT_RGB 0x3052 /* EGL_TRANSPARENT_TYPE value */ +#define EGL_RGB_BUFFER 0x308E /* EGL_COLOR_BUFFER_TYPE value */ +#define EGL_LUMINANCE_BUFFER 0x308F /* EGL_COLOR_BUFFER_TYPE value */ + +/* More config attribute values, for EGL_TEXTURE_FORMAT */ +#define EGL_NO_TEXTURE 0x305C +#define EGL_TEXTURE_RGB 0x305D +#define EGL_TEXTURE_RGBA 0x305E +#define EGL_TEXTURE_2D 0x305F + +/* Config attribute mask bits */ +#define EGL_PBUFFER_BIT 0x0001 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_PIXMAP_BIT 0x0002 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_WINDOW_BIT 0x0004 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200 /* EGL_SURFACE_TYPE mask bits */ +#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400 /* EGL_SURFACE_TYPE mask bits */ + +#define EGL_OPENGL_ES_BIT 0x0001 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENVG_BIT 0x0002 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_ES2_BIT 0x0004 /* EGL_RENDERABLE_TYPE mask bits */ +#define EGL_OPENGL_BIT 0x0008 /* EGL_RENDERABLE_TYPE mask bits */ + +/* QueryString targets */ +#define EGL_VENDOR 0x3053 +#define EGL_VERSION 0x3054 +#define EGL_EXTENSIONS 0x3055 +#define EGL_CLIENT_APIS 0x308D + +/* QuerySurface / SurfaceAttrib / CreatePbufferSurface targets */ +#define EGL_HEIGHT 0x3056 +#define EGL_WIDTH 0x3057 +#define EGL_LARGEST_PBUFFER 0x3058 +#define EGL_TEXTURE_FORMAT 0x3080 +#define EGL_TEXTURE_TARGET 0x3081 +#define EGL_MIPMAP_TEXTURE 0x3082 +#define EGL_MIPMAP_LEVEL 0x3083 +#define EGL_RENDER_BUFFER 0x3086 +#define EGL_VG_COLORSPACE 0x3087 +#define EGL_VG_ALPHA_FORMAT 0x3088 +#define EGL_HORIZONTAL_RESOLUTION 0x3090 +#define EGL_VERTICAL_RESOLUTION 0x3091 +#define EGL_PIXEL_ASPECT_RATIO 0x3092 +#define EGL_SWAP_BEHAVIOR 0x3093 +#define EGL_MULTISAMPLE_RESOLVE 0x3099 + +/* EGL_RENDER_BUFFER values / BindTexImage / ReleaseTexImage buffer targets */ +#define EGL_BACK_BUFFER 0x3084 +#define EGL_SINGLE_BUFFER 0x3085 + +/* OpenVG color spaces */ +#define EGL_VG_COLORSPACE_sRGB 0x3089 /* EGL_VG_COLORSPACE value */ +#define EGL_VG_COLORSPACE_LINEAR 0x308A /* EGL_VG_COLORSPACE value */ + +/* OpenVG alpha formats */ +#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B /* EGL_ALPHA_FORMAT value */ +#define EGL_VG_ALPHA_FORMAT_PRE 0x308C /* EGL_ALPHA_FORMAT value */ + +/* Constant scale factor by which fractional display resolutions & + * aspect ratio are scaled when queried as integer values. + */ +#define EGL_DISPLAY_SCALING 10000 + +/* Unknown display resolution/aspect ratio */ +#define EGL_UNKNOWN ((EGLint)-1) + +/* Back buffer swap behaviors */ +#define EGL_BUFFER_PRESERVED 0x3094 /* EGL_SWAP_BEHAVIOR value */ +#define EGL_BUFFER_DESTROYED 0x3095 /* EGL_SWAP_BEHAVIOR value */ + +/* CreatePbufferFromClientBuffer buffer types */ +#define EGL_OPENVG_IMAGE 0x3096 + +/* QueryContext targets */ +#define EGL_CONTEXT_CLIENT_TYPE 0x3097 + +/* CreateContext attributes */ +#define EGL_CONTEXT_CLIENT_VERSION 0x3098 + +/* Multisample resolution behaviors */ +#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A /* EGL_MULTISAMPLE_RESOLVE value */ +#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B /* EGL_MULTISAMPLE_RESOLVE value */ + +/* BindAPI/QueryAPI targets */ +#define EGL_OPENGL_ES_API 0x30A0 +#define EGL_OPENVG_API 0x30A1 +#define EGL_OPENGL_API 0x30A2 + +/* GetCurrentSurface targets */ +#define EGL_DRAW 0x3059 +#define EGL_READ 0x305A + +/* WaitNative engines */ +#define EGL_CORE_NATIVE_ENGINE 0x305B + +/* EGL 1.2 tokens renamed for consistency in EGL 1.3 */ +#define EGL_COLORSPACE EGL_VG_COLORSPACE +#define EGL_ALPHA_FORMAT EGL_VG_ALPHA_FORMAT +#define EGL_COLORSPACE_sRGB EGL_VG_COLORSPACE_sRGB +#define EGL_COLORSPACE_LINEAR EGL_VG_COLORSPACE_LINEAR +#define EGL_ALPHA_FORMAT_NONPRE EGL_VG_ALPHA_FORMAT_NONPRE +#define EGL_ALPHA_FORMAT_PRE EGL_VG_ALPHA_FORMAT_PRE + +/* EGL extensions must request enum blocks from the Khronos + * API Registrar, who maintains the enumerant registry. Submit + * a bug in Khronos Bugzilla against task "Registry". + */ + + + +/* EGL Functions */ + +EGLAPI EGLint EGLAPIENTRY eglGetError(void); + +EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay(EGLNativeDisplayType display_id); +EGLAPI EGLBoolean EGLAPIENTRY eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor); +EGLAPI EGLBoolean EGLAPIENTRY eglTerminate(EGLDisplay dpy); + +EGLAPI const char * EGLAPIENTRY eglQueryString(EGLDisplay dpy, EGLint name); + +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, + EGLint config_size, EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, + EGLConfig *configs, EGLint config_size, + EGLint *num_config); +EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, + EGLint attribute, EGLint *value); + +EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, + EGLNativeWindowType win, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, + const EGLint *attrib_list); +EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, + EGLNativePixmapType pixmap, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI(EGLenum api); +EGLAPI EGLenum EGLAPIENTRY eglQueryAPI(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient(void); + +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread(void); + +EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer( + EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, + EGLConfig config, const EGLint *attrib_list); + +EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, + EGLint attribute, EGLint value); +EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); +EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer); + + +EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval(EGLDisplay dpy, EGLint interval); + + +EGLAPI EGLContext EGLAPIENTRY eglCreateContext(EGLDisplay dpy, EGLConfig config, + EGLContext share_context, + const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext(EGLDisplay dpy, EGLContext ctx); +EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, + EGLSurface read, EGLContext ctx); + +EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext(void); +EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface(EGLint readdraw); +EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay(void); +EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext(EGLDisplay dpy, EGLContext ctx, + EGLint attribute, EGLint *value); + +EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL(void); +EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative(EGLint engine); +EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers(EGLDisplay dpy, EGLSurface surface); +EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, + EGLNativePixmapType target); + +/* This is a generic function pointer type, whose name indicates it must + * be cast to the proper type *and calling convention* before use. + */ +typedef void (*__eglMustCastToProperFunctionPointerType)(void); + +/* Now, define eglGetProcAddress using the generic function ptr. type */ +EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY + eglGetProcAddress(const char *procname); + +#ifdef __cplusplus +} +#endif + +#endif /* __egl_h_ */ diff --git a/Include/EGL/eglext.h b/Include/EGL/eglext.h new file mode 100644 index 000000000..6969cf239 --- /dev/null +++ b/Include/EGL/eglext.h @@ -0,0 +1,137 @@ +#ifndef __eglext_h_ +#define __eglext_h_ + +#ifdef __cplusplus +extern "C" { +#endif + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +#include + +/*************************************************************/ + +/* Header file version number */ +/* Current version at http://www.khronos.org/registry/egl/ */ +#define EGL_EGLEXT_VERSION 3 + +#ifndef EGL_KHR_config_attribs +#define EGL_KHR_config_attribs 1 +#define EGL_CONFORMANT_KHR 0x3042 /* EGLConfig attribute */ +#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040 /* EGL_SURFACE_TYPE bitfield */ +#endif + +#ifndef EGL_KHR_lock_surface +#define EGL_KHR_lock_surface 1 +#define EGL_READ_SURFACE_BIT_KHR 0x0001 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_WRITE_SURFACE_BIT_KHR 0x0002 /* EGL_LOCK_USAGE_HINT_KHR bitfield */ +#define EGL_LOCK_SURFACE_BIT_KHR 0x0080 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100 /* EGL_SURFACE_TYPE bitfield */ +#define EGL_MATCH_FORMAT_KHR 0x3043 /* EGLConfig attribute */ +#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGB_565_KHR 0x30C1 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_FORMAT_RGBA_8888_KHR 0x30C3 /* EGL_MATCH_FORMAT_KHR value */ +#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4 /* eglLockSurfaceKHR attribute */ +#define EGL_LOCK_USAGE_HINT_KHR 0x30C5 /* eglLockSurfaceKHR attribute */ +#define EGL_BITMAP_POINTER_KHR 0x30C6 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PITCH_KHR 0x30C7 /* eglQuerySurface attribute */ +#define EGL_BITMAP_ORIGIN_KHR 0x30C8 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9 /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC /* eglQuerySurface attribute */ +#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD /* eglQuerySurface attribute */ +#define EGL_LOWER_LEFT_KHR 0x30CE /* EGL_BITMAP_ORIGIN_KHR value */ +#define EGL_UPPER_LEFT_KHR 0x30CF /* EGL_BITMAP_ORIGIN_KHR value */ +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay display, EGLSurface surface); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay display, EGLSurface surface); +#endif + +#ifndef EGL_KHR_image +#define EGL_KHR_image 1 +#define EGL_NATIVE_PIXMAP_KHR 0x30B0 /* eglCreateImageKHR target */ +typedef void *EGLImageKHR; +#define EGL_NO_IMAGE_KHR ((EGLImageKHR)0) +#ifdef EGL_EGLEXT_PROTOTYPES +EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image); +#endif /* EGL_EGLEXT_PROTOTYPES */ +typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); +typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image); +#endif + +#ifndef EGL_KHR_vg_parent_image +#define EGL_KHR_vg_parent_image 1 +#define EGL_VG_PARENT_IMAGE_KHR 0x30BA /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_2D_image +#define EGL_KHR_gl_texture_2D_image 1 +#define EGL_GL_TEXTURE_2D_KHR 0x30B1 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_texture_cubemap_image +#define EGL_KHR_gl_texture_cubemap_image 1 +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_gl_texture_3D_image +#define EGL_KHR_gl_texture_3D_image 1 +#define EGL_GL_TEXTURE_3D_KHR 0x30B2 /* eglCreateImageKHR target */ +#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_gl_renderbuffer_image +#define EGL_KHR_gl_renderbuffer_image 1 +#define EGL_GL_RENDERBUFFER_KHR 0x30B9 /* eglCreateImageKHR target */ +#endif + +#ifndef EGL_KHR_image_base +#define EGL_KHR_image_base 1 +/* Most interfaces defined by EGL_KHR_image_pixmap above */ +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 /* eglCreateImageKHR attribute */ +#endif + +#ifndef EGL_KHR_image_pixmap +#define EGL_KHR_image_pixmap 1 +/* Interfaces defined by EGL_KHR_image above */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/Include/EGL/eglplatform.h b/Include/EGL/eglplatform.h new file mode 100644 index 000000000..1b789bf24 --- /dev/null +++ b/Include/EGL/eglplatform.h @@ -0,0 +1,113 @@ +#ifndef __eglplatform_h_ +#define __eglplatform_h_ + +/* +** Copyright (c) 2007-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Platform-specific types and definitions for egl.h + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "EGL" component "Registry". + */ + +#include + +/* Macros used in EGL function prototype declarations. + * + * EGL functions should be prototyped as: + * + * EGLAPI return-type EGLAPIENTRY eglFunction(arguments); + * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments); + * + * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h + */ + +#ifndef EGLAPI +#define EGLAPI KHRONOS_APICALL +#endif + +#define EGLAPIENTRY KHRONOS_APIENTRY +#define EGLAPIENTRYP KHRONOS_APIENTRY* + +/* The types NativeDisplayType, NativeWindowType, and NativePixmapType + * are aliases of window-system-dependent types, such as X Display * or + * Windows Device Context. They must be defined in platform-specific + * code below. The EGL-prefixed versions of Native*Type are the same + * types, renamed in EGL 1.3 so all types in the API start with "EGL". + */ + +#if defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */ +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN 1 +#endif +#include + +typedef HDC EGLNativeDisplayType; +typedef HBITMAP EGLNativePixmapType; +typedef HWND EGLNativeWindowType; + +#elif defined(SUPPORT_X11) + +/* X11 (tentative) */ +#include +#include + +typedef Display *EGLNativeDisplayType; +typedef Pixmap EGLNativePixmapType; +typedef Window EGLNativeWindowType; + +#else + +#if defined(_WIN64) || __WORDSIZE == 64 +typedef khronos_int64_t EGLNativeDisplayType; +#else +typedef int EGLNativeDisplayType; +#endif +typedef void *EGLNativeWindowType; +typedef void *EGLNativePixmapType; + +#endif + +/* EGL 1.2 types, renamed for consistency in EGL 1.3 */ +typedef EGLNativeDisplayType NativeDisplayType; +typedef EGLNativePixmapType NativePixmapType; +typedef EGLNativeWindowType NativeWindowType; + + +/* Define EGLint. This must be a signed integral type large enough to contain + * all legal attribute names and values passed into and out of EGL, whether + * their type is boolean, bitmask, enumerant (symbolic constant), integer, + * handle, or other. While in general a 32-bit integer will suffice, if + * handles are 64 bit types, then EGLint should be defined as a signed 64-bit + * integer type. + */ + #if defined(_WIN64) || __WORDSIZE == 64 +typedef khronos_int64_t EGLint; +#else +typedef khronos_int32_t EGLint; +#endif + +#endif /* __eglplatform_h */ diff --git a/Include/GLES2/gl2.h b/Include/GLES2/gl2.h new file mode 100644 index 000000000..59e376c5a --- /dev/null +++ b/Include/GLES2/gl2.h @@ -0,0 +1,620 @@ +#ifndef __gl2_h_ +#define __gl2_h_ + +/* $Revision: 8784 $ on $Date:: 2009-09-02 09:49:17 -0700 #$ */ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +/*------------------------------------------------------------------------- + * Data type definitions + *-----------------------------------------------------------------------*/ + +typedef void GLvoid; +typedef unsigned int GLenum; +typedef unsigned char GLboolean; +typedef unsigned int GLbitfield; +typedef khronos_int8_t GLbyte; +typedef short GLshort; +typedef int GLint; +typedef int GLsizei; +typedef khronos_uint8_t GLubyte; +typedef unsigned short GLushort; +typedef unsigned int GLuint; +typedef khronos_float_t GLfloat; +typedef khronos_float_t GLclampf; +typedef khronos_int32_t GLfixed; + +/* GL types for handling large vertex buffer objects */ +typedef khronos_intptr_t GLintptr; +typedef khronos_ssize_t GLsizeiptr; + +/* OpenGL ES core versions */ +#define GL_ES_VERSION_2_0 1 + +/* ClearBufferMask */ +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 + +/* Boolean */ +#define GL_FALSE 0 +#define GL_TRUE 1 + +/* BeginMode */ +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 + +/* AlphaFunction (not supported in ES20) */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* BlendingFactorDest */ +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 + +/* BlendingFactorSrc */ +/* GL_ZERO */ +/* GL_ONE */ +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +/* GL_SRC_ALPHA */ +/* GL_ONE_MINUS_SRC_ALPHA */ +/* GL_DST_ALPHA */ +/* GL_ONE_MINUS_DST_ALPHA */ + +/* BlendEquationSeparate */ +#define GL_FUNC_ADD 0x8006 +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 /* same as BLEND_EQUATION */ +#define GL_BLEND_EQUATION_ALPHA 0x883D + +/* BlendSubtract */ +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B + +/* Separate Blend Functions */ +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 +#define GL_BLEND_COLOR 0x8005 + +/* Buffer Objects */ +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 + +#define GL_STREAM_DRAW 0x88E0 +#define GL_STATIC_DRAW 0x88E4 +#define GL_DYNAMIC_DRAW 0x88E8 + +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 + +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 + +/* CullFaceMode */ +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 + +/* DepthFunction */ +/* GL_NEVER */ +/* GL_LESS */ +/* GL_EQUAL */ +/* GL_LEQUAL */ +/* GL_GREATER */ +/* GL_NOTEQUAL */ +/* GL_GEQUAL */ +/* GL_ALWAYS */ + +/* EnableCap */ +#define GL_TEXTURE_2D 0x0DE1 +#define GL_CULL_FACE 0x0B44 +#define GL_BLEND 0x0BE2 +#define GL_DITHER 0x0BD0 +#define GL_STENCIL_TEST 0x0B90 +#define GL_DEPTH_TEST 0x0B71 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 + +/* ErrorCode */ +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 + +/* FrontFaceDirection */ +#define GL_CW 0x0900 +#define GL_CCW 0x0901 + +/* GetPName */ +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +/* GL_SCISSOR_TEST */ +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +/* GL_POLYGON_OFFSET_FILL */ +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB + +/* GetTextureParameter */ +/* GL_TEXTURE_MAG_FILTER */ +/* GL_TEXTURE_MIN_FILTER */ +/* GL_TEXTURE_WRAP_S */ +/* GL_TEXTURE_WRAP_T */ + +#define GL_NUM_COMPRESSED_TEXTURE_FORMATS 0x86A2 +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 + +/* HintMode */ +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 + +/* HintTarget */ +#define GL_GENERATE_MIPMAP_HINT 0x8192 + +/* DataType */ +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_FIXED 0x140C + +/* PixelFormat */ +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A + +/* PixelType */ +/* GL_UNSIGNED_BYTE */ +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 + +/* Shaders */ +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_ACTIVE_UNIFORM_MAX_LENGTH 0x8B87 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_ATTRIBUTE_MAX_LENGTH 0x8B8A +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D + +/* StencilFunction */ +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 + +/* StencilOp */ +/* GL_ZERO */ +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 + +/* StringName */ +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_EXTENSIONS 0x1F03 + +/* TextureMagFilter */ +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 + +/* TextureMinFilter */ +/* GL_NEAREST */ +/* GL_LINEAR */ +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 + +/* TextureParameterName */ +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 + +/* TextureTarget */ +/* GL_TEXTURE_2D */ +#define GL_TEXTURE 0x1702 + +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C + +/* TextureUnit */ +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 + +/* TextureWrapMode */ +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 + +/* Uniform Types */ +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 + +/* Vertex Arrays */ +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F + +/* Read Format */ +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B + +/* Shader Source */ +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 +#define GL_SHADER_COMPILER 0x8DFA + +/* Shader Binary */ +#define GL_SHADER_BINARY_FORMATS 0x8DF8 +#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9 + +/* Shader Precision-Specified Types */ +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 + +/* Framebuffer Object. */ +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 + +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX 0x1901 +#define GL_STENCIL_INDEX8 0x8D48 + +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 + +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 + +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 + +#define GL_NONE 0 + +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD + +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 + +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 + +/*------------------------------------------------------------------------- + * GL core functions. + *-----------------------------------------------------------------------*/ + +GL_APICALL void GL_APIENTRY glActiveTexture (GLenum texture); +GL_APICALL void GL_APIENTRY glAttachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glBindAttribLocation (GLuint program, GLuint index, const char* name); +GL_APICALL void GL_APIENTRY glBindBuffer (GLenum target, GLuint buffer); +GL_APICALL void GL_APIENTRY glBindFramebuffer (GLenum target, GLuint framebuffer); +GL_APICALL void GL_APIENTRY glBindRenderbuffer (GLenum target, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glBindTexture (GLenum target, GLuint texture); +GL_APICALL void GL_APIENTRY glBlendColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +GL_APICALL void GL_APIENTRY glBlendEquation ( GLenum mode ); +GL_APICALL void GL_APIENTRY glBlendEquationSeparate (GLenum modeRGB, GLenum modeAlpha); +GL_APICALL void GL_APIENTRY glBlendFunc (GLenum sfactor, GLenum dfactor); +GL_APICALL void GL_APIENTRY glBlendFuncSeparate (GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha); +GL_APICALL void GL_APIENTRY glBufferData (GLenum target, GLsizeiptr size, const void* data, GLenum usage); +GL_APICALL void GL_APIENTRY glBufferSubData (GLenum target, GLintptr offset, GLsizeiptr size, const void* data); +GL_APICALL GLenum GL_APIENTRY glCheckFramebufferStatus (GLenum target); +GL_APICALL void GL_APIENTRY glClear (GLbitfield mask); +GL_APICALL void GL_APIENTRY glClearColor (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +GL_APICALL void GL_APIENTRY glClearDepthf (GLclampf depth); +GL_APICALL void GL_APIENTRY glClearStencil (GLint s); +GL_APICALL void GL_APIENTRY glColorMask (GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +GL_APICALL void GL_APIENTRY glCompileShader (GLuint shader); +GL_APICALL void GL_APIENTRY glCompressedTexImage2D (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data); +GL_APICALL void GL_APIENTRY glCopyTexImage2D (GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +GL_APICALL void GL_APIENTRY glCopyTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL GLuint GL_APIENTRY glCreateProgram (void); +GL_APICALL GLuint GL_APIENTRY glCreateShader (GLenum type); +GL_APICALL void GL_APIENTRY glCullFace (GLenum mode); +GL_APICALL void GL_APIENTRY glDeleteBuffers (GLsizei n, const GLuint* buffers); +GL_APICALL void GL_APIENTRY glDeleteFramebuffers (GLsizei n, const GLuint* framebuffers); +GL_APICALL void GL_APIENTRY glDeleteProgram (GLuint program); +GL_APICALL void GL_APIENTRY glDeleteRenderbuffers (GLsizei n, const GLuint* renderbuffers); +GL_APICALL void GL_APIENTRY glDeleteShader (GLuint shader); +GL_APICALL void GL_APIENTRY glDeleteTextures (GLsizei n, const GLuint* textures); +GL_APICALL void GL_APIENTRY glDepthFunc (GLenum func); +GL_APICALL void GL_APIENTRY glDepthMask (GLboolean flag); +GL_APICALL void GL_APIENTRY glDepthRangef (GLclampf zNear, GLclampf zFar); +GL_APICALL void GL_APIENTRY glDetachShader (GLuint program, GLuint shader); +GL_APICALL void GL_APIENTRY glDisable (GLenum cap); +GL_APICALL void GL_APIENTRY glDisableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glDrawArrays (GLenum mode, GLint first, GLsizei count); +GL_APICALL void GL_APIENTRY glDrawElements (GLenum mode, GLsizei count, GLenum type, const void* indices); +GL_APICALL void GL_APIENTRY glEnable (GLenum cap); +GL_APICALL void GL_APIENTRY glEnableVertexAttribArray (GLuint index); +GL_APICALL void GL_APIENTRY glFinish (void); +GL_APICALL void GL_APIENTRY glFlush (void); +GL_APICALL void GL_APIENTRY glFramebufferRenderbuffer (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer); +GL_APICALL void GL_APIENTRY glFramebufferTexture2D (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +GL_APICALL void GL_APIENTRY glFrontFace (GLenum mode); +GL_APICALL void GL_APIENTRY glGenBuffers (GLsizei n, GLuint* buffers); +GL_APICALL void GL_APIENTRY glGenerateMipmap (GLenum target); +GL_APICALL void GL_APIENTRY glGenFramebuffers (GLsizei n, GLuint* framebuffers); +GL_APICALL void GL_APIENTRY glGenRenderbuffers (GLsizei n, GLuint* renderbuffers); +GL_APICALL void GL_APIENTRY glGenTextures (GLsizei n, GLuint* textures); +GL_APICALL void GL_APIENTRY glGetActiveAttrib (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); +GL_APICALL void GL_APIENTRY glGetActiveUniform (GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name); +GL_APICALL void GL_APIENTRY glGetAttachedShaders (GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders); +GL_APICALL int GL_APIENTRY glGetAttribLocation (GLuint program, const char* name); +GL_APICALL void GL_APIENTRY glGetBooleanv (GLenum pname, GLboolean* params); +GL_APICALL void GL_APIENTRY glGetBufferParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL GLenum GL_APIENTRY glGetError (void); +GL_APICALL void GL_APIENTRY glGetFloatv (GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetFramebufferAttachmentParameteriv (GLenum target, GLenum attachment, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetIntegerv (GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetProgramiv (GLuint program, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetProgramInfoLog (GLuint program, GLsizei bufsize, GLsizei* length, char* infolog); +GL_APICALL void GL_APIENTRY glGetRenderbufferParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetShaderiv (GLuint shader, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetShaderInfoLog (GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog); +GL_APICALL void GL_APIENTRY glGetShaderPrecisionFormat (GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision); +GL_APICALL void GL_APIENTRY glGetShaderSource (GLuint shader, GLsizei bufsize, GLsizei* length, char* source); +GL_APICALL const GLubyte* GL_APIENTRY glGetString (GLenum name); +GL_APICALL void GL_APIENTRY glGetTexParameterfv (GLenum target, GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetTexParameteriv (GLenum target, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetUniformfv (GLuint program, GLint location, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetUniformiv (GLuint program, GLint location, GLint* params); +GL_APICALL int GL_APIENTRY glGetUniformLocation (GLuint program, const char* name); +GL_APICALL void GL_APIENTRY glGetVertexAttribfv (GLuint index, GLenum pname, GLfloat* params); +GL_APICALL void GL_APIENTRY glGetVertexAttribiv (GLuint index, GLenum pname, GLint* params); +GL_APICALL void GL_APIENTRY glGetVertexAttribPointerv (GLuint index, GLenum pname, void** pointer); +GL_APICALL void GL_APIENTRY glHint (GLenum target, GLenum mode); +GL_APICALL GLboolean GL_APIENTRY glIsBuffer (GLuint buffer); +GL_APICALL GLboolean GL_APIENTRY glIsEnabled (GLenum cap); +GL_APICALL GLboolean GL_APIENTRY glIsFramebuffer (GLuint framebuffer); +GL_APICALL GLboolean GL_APIENTRY glIsProgram (GLuint program); +GL_APICALL GLboolean GL_APIENTRY glIsRenderbuffer (GLuint renderbuffer); +GL_APICALL GLboolean GL_APIENTRY glIsShader (GLuint shader); +GL_APICALL GLboolean GL_APIENTRY glIsTexture (GLuint texture); +GL_APICALL void GL_APIENTRY glLineWidth (GLfloat width); +GL_APICALL void GL_APIENTRY glLinkProgram (GLuint program); +GL_APICALL void GL_APIENTRY glPixelStorei (GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glPolygonOffset (GLfloat factor, GLfloat units); +GL_APICALL void GL_APIENTRY glReadPixels (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels); +GL_APICALL void GL_APIENTRY glReleaseShaderCompiler (void); +GL_APICALL void GL_APIENTRY glRenderbufferStorage (GLenum target, GLenum internalformat, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glSampleCoverage (GLclampf value, GLboolean invert); +GL_APICALL void GL_APIENTRY glScissor (GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glShaderBinary (GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length); +GL_APICALL void GL_APIENTRY glShaderSource (GLuint shader, GLsizei count, const char** string, const GLint* length); +GL_APICALL void GL_APIENTRY glStencilFunc (GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilFuncSeparate (GLenum face, GLenum func, GLint ref, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMask (GLuint mask); +GL_APICALL void GL_APIENTRY glStencilMaskSeparate (GLenum face, GLuint mask); +GL_APICALL void GL_APIENTRY glStencilOp (GLenum fail, GLenum zfail, GLenum zpass); +GL_APICALL void GL_APIENTRY glStencilOpSeparate (GLenum face, GLenum fail, GLenum zfail, GLenum zpass); +GL_APICALL void GL_APIENTRY glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels); +GL_APICALL void GL_APIENTRY glTexParameterf (GLenum target, GLenum pname, GLfloat param); +GL_APICALL void GL_APIENTRY glTexParameterfv (GLenum target, GLenum pname, const GLfloat* params); +GL_APICALL void GL_APIENTRY glTexParameteri (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glTexParameteriv (GLenum target, GLenum pname, const GLint* params); +GL_APICALL void GL_APIENTRY glTexSubImage2D (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels); +GL_APICALL void GL_APIENTRY glUniform1f (GLint location, GLfloat x); +GL_APICALL void GL_APIENTRY glUniform1fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform1i (GLint location, GLint x); +GL_APICALL void GL_APIENTRY glUniform1iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform2f (GLint location, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glUniform2fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform2i (GLint location, GLint x, GLint y); +GL_APICALL void GL_APIENTRY glUniform2iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform3f (GLint location, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glUniform3fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform3i (GLint location, GLint x, GLint y, GLint z); +GL_APICALL void GL_APIENTRY glUniform3iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniform4f (GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glUniform4fv (GLint location, GLsizei count, const GLfloat* v); +GL_APICALL void GL_APIENTRY glUniform4i (GLint location, GLint x, GLint y, GLint z, GLint w); +GL_APICALL void GL_APIENTRY glUniform4iv (GLint location, GLsizei count, const GLint* v); +GL_APICALL void GL_APIENTRY glUniformMatrix2fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUniformMatrix3fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUniformMatrix4fv (GLint location, GLsizei count, GLboolean transpose, const GLfloat* value); +GL_APICALL void GL_APIENTRY glUseProgram (GLuint program); +GL_APICALL void GL_APIENTRY glValidateProgram (GLuint program); +GL_APICALL void GL_APIENTRY glVertexAttrib1f (GLuint indx, GLfloat x); +GL_APICALL void GL_APIENTRY glVertexAttrib1fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib2f (GLuint indx, GLfloat x, GLfloat y); +GL_APICALL void GL_APIENTRY glVertexAttrib2fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib3f (GLuint indx, GLfloat x, GLfloat y, GLfloat z); +GL_APICALL void GL_APIENTRY glVertexAttrib3fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttrib4f (GLuint indx, GLfloat x, GLfloat y, GLfloat z, GLfloat w); +GL_APICALL void GL_APIENTRY glVertexAttrib4fv (GLuint indx, const GLfloat* values); +GL_APICALL void GL_APIENTRY glVertexAttribPointer (GLuint indx, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr); +GL_APICALL void GL_APIENTRY glViewport (GLint x, GLint y, GLsizei width, GLsizei height); + +#ifdef __cplusplus +} +#endif + +#endif /* __gl2_h_ */ diff --git a/Include/GLES2/gl2ext.h b/Include/GLES2/gl2ext.h new file mode 100644 index 000000000..27cf711ba --- /dev/null +++ b/Include/GLES2/gl2ext.h @@ -0,0 +1,610 @@ +#ifndef __gl2ext_h_ +#define __gl2ext_h_ + +/* $Revision: 8936 $ on $Date:: 2009-09-17 17:16:47 -0700 #$ */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +#ifndef GL_APIENTRYP +# define GL_APIENTRYP GL_APIENTRY* +#endif + +/*------------------------------------------------------------------------* + * OES extension tokens + *------------------------------------------------------------------------*/ + +/* GL_OES_compressed_ETC1_RGB8_texture */ +#ifndef GL_OES_compressed_ETC1_RGB8_texture +#define GL_ETC1_RGB8_OES 0x8D64 +#endif + +/* GL_OES_compressed_paletted_texture */ +#ifndef GL_OES_compressed_paletted_texture +#define GL_PALETTE4_RGB8_OES 0x8B90 +#define GL_PALETTE4_RGBA8_OES 0x8B91 +#define GL_PALETTE4_R5_G6_B5_OES 0x8B92 +#define GL_PALETTE4_RGBA4_OES 0x8B93 +#define GL_PALETTE4_RGB5_A1_OES 0x8B94 +#define GL_PALETTE8_RGB8_OES 0x8B95 +#define GL_PALETTE8_RGBA8_OES 0x8B96 +#define GL_PALETTE8_R5_G6_B5_OES 0x8B97 +#define GL_PALETTE8_RGBA4_OES 0x8B98 +#define GL_PALETTE8_RGB5_A1_OES 0x8B99 +#endif + +/* GL_OES_depth24 */ +#ifndef GL_OES_depth24 +#define GL_DEPTH_COMPONENT24_OES 0x81A6 +#endif + +/* GL_OES_depth32 */ +#ifndef GL_OES_depth32 +#define GL_DEPTH_COMPONENT32_OES 0x81A7 +#endif + +/* GL_OES_depth_texture */ +/* No new tokens introduced by this extension. */ + +/* GL_OES_EGL_image */ +#ifndef GL_OES_EGL_image +typedef void* GLeglImageOES; +#endif + +/* GL_OES_get_program_binary */ +#ifndef GL_OES_get_program_binary +#define GL_PROGRAM_BINARY_LENGTH_OES 0x8741 +#define GL_NUM_PROGRAM_BINARY_FORMATS_OES 0x87FE +#define GL_PROGRAM_BINARY_FORMATS_OES 0x87FF +#endif + +/* GL_OES_mapbuffer */ +#ifndef GL_OES_mapbuffer +#define GL_WRITE_ONLY_OES 0x88B9 +#define GL_BUFFER_ACCESS_OES 0x88BB +#define GL_BUFFER_MAPPED_OES 0x88BC +#define GL_BUFFER_MAP_POINTER_OES 0x88BD +#endif + +/* GL_OES_packed_depth_stencil */ +#ifndef GL_OES_packed_depth_stencil +#define GL_DEPTH_STENCIL_OES 0x84F9 +#define GL_UNSIGNED_INT_24_8_OES 0x84FA +#define GL_DEPTH24_STENCIL8_OES 0x88F0 +#endif + +/* GL_OES_rgb8_rgba8 */ +#ifndef GL_OES_rgb8_rgba8 +#define GL_RGB8_OES 0x8051 +#define GL_RGBA8_OES 0x8058 +#endif + +/* GL_OES_standard_derivatives */ +#ifndef GL_OES_standard_derivatives +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT_OES 0x8B8B +#endif + +/* GL_OES_stencil1 */ +#ifndef GL_OES_stencil1 +#define GL_STENCIL_INDEX1_OES 0x8D46 +#endif + +/* GL_OES_stencil4 */ +#ifndef GL_OES_stencil4 +#define GL_STENCIL_INDEX4_OES 0x8D47 +#endif + +/* GL_OES_texture3D */ +#ifndef GL_OES_texture3D +#define GL_TEXTURE_WRAP_R_OES 0x8072 +#define GL_TEXTURE_3D_OES 0x806F +#define GL_TEXTURE_BINDING_3D_OES 0x806A +#define GL_MAX_3D_TEXTURE_SIZE_OES 0x8073 +#define GL_SAMPLER_3D_OES 0x8B5F +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_3D_ZOFFSET_OES 0x8CD4 +#endif + +/* GL_OES_texture_half_float */ +#ifndef GL_OES_texture_half_float +#define GL_HALF_FLOAT_OES 0x8D61 +#endif + +/* GL_OES_vertex_half_float */ +/* GL_HALF_FLOAT_OES defined in GL_OES_texture_half_float already. */ + +/* GL_OES_vertex_type_10_10_10_2 */ +#ifndef GL_OES_vertex_type_10_10_10_2 +#define GL_UNSIGNED_INT_10_10_10_2_OES 0x8DF6 +#define GL_INT_10_10_10_2_OES 0x8DF7 +#endif + +/*------------------------------------------------------------------------* + * AMD extension tokens + *------------------------------------------------------------------------*/ + +/* GL_AMD_compressed_3DC_texture */ +#ifndef GL_AMD_compressed_3DC_texture +#define GL_3DC_X_AMD 0x87F9 +#define GL_3DC_XY_AMD 0x87FA +#endif + +/* GL_AMD_compressed_ATC_texture */ +#ifndef GL_AMD_compressed_ATC_texture +#define GL_ATC_RGB_AMD 0x8C92 +#define GL_ATC_RGBA_EXPLICIT_ALPHA_AMD 0x8C93 +#define GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD 0x87EE +#endif + +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_Z400_BINARY_AMD 0x8740 +#endif + +/* GL_AMD_performance_monitor */ +#ifndef GL_AMD_performance_monitor +#define GL_COUNTER_TYPE_AMD 0x8BC0 +#define GL_COUNTER_RANGE_AMD 0x8BC1 +#define GL_UNSIGNED_INT64_AMD 0x8BC2 +#define GL_PERCENTAGE_AMD 0x8BC3 +#define GL_PERFMON_RESULT_AVAILABLE_AMD 0x8BC4 +#define GL_PERFMON_RESULT_SIZE_AMD 0x8BC5 +#define GL_PERFMON_RESULT_AMD 0x8BC6 +#endif + +/*------------------------------------------------------------------------* + * EXT extension tokens + *------------------------------------------------------------------------*/ + +/* GL_EXT_texture_filter_anisotropic */ +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE +#define GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT 0x84FF +#endif + +/* GL_EXT_texture_type_2_10_10_10_REV */ +#ifndef GL_EXT_texture_type_2_10_10_10_REV +#define GL_UNSIGNED_INT_2_10_10_10_REV_EXT 0x8368 +#endif + +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_BGRA 0x80E1 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_COLOR_EXT 0x1800 +#define GL_DEPTH_EXT 0x1801 +#define GL_STENCIL_EXT 0x1802 +#endif + +#ifndef GL_EXT_blend_minmax +#define GL_MIN_EXT 0x8007 +#define GL_MAX_EXT 0x8008 +#endif + +/*------------------------------------------------------------------------* + * IMG extension tokens + *------------------------------------------------------------------------*/ + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_BGRA 0x80E1 +#define GL_UNSIGNED_SHORT_4_4_4_4_REV 0x8365 +#define GL_UNSIGNED_SHORT_1_5_5_5_REV 0x8366 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#endif + +/*------------------------------------------------------------------------* + * NV extension tokens + *------------------------------------------------------------------------*/ + +/* GL_NV_fence */ +#ifndef GL_NV_fence +#define GL_ALL_COMPLETED_NV 0x84F2 +#define GL_FENCE_STATUS_NV 0x84F3 +#define GL_FENCE_CONDITION_NV 0x84F4 +#endif + +/*------------------------------------------------------------------------* + * QCOM extension tokens + *------------------------------------------------------------------------*/ + +/* GL_QCOM_driver_control */ +/* No new tokens introduced by this extension. */ + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_PERFMON_GLOBAL_MODE_QCOM 0x8FA0 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_WRITEONLY_RENDERING_AMD 0x8823 +#endif + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_TEXTURE_WIDTH_QCOM 0x8BD2 +#define GL_TEXTURE_HEIGHT_QCOM 0x8BD3 +#define GL_TEXTURE_DEPTH_QCOM 0x8BD4 +#define GL_TEXTURE_INTERNAL_FORMAT_QCOM 0x8BD5 +#define GL_TEXTURE_FORMAT_QCOM 0x8BD6 +#define GL_TEXTURE_TYPE_QCOM 0x8BD7 +#define GL_TEXTURE_IMAGE_VALID_QCOM 0x8BD8 +#define GL_TEXTURE_NUM_LEVELS_QCOM 0x8BD9 +#define GL_TEXTURE_TARGET_QCOM 0x8BDA +#define GL_TEXTURE_OBJECT_VALID_QCOM 0x8BDB +#define GL_STATE_RESTORE 0x8BDC +#endif + +/* GL_QCOM_extended_get2 */ +/* No new tokens introduced by this extension. */ + +/*------------------------------------------------------------------------* + * End of extension tokens, start of corresponding extension functions + *------------------------------------------------------------------------*/ + +/*------------------------------------------------------------------------* + * OES extension functions + *------------------------------------------------------------------------*/ + +/* GL_OES_compressed_ETC1_RGB8_texture */ +#ifndef GL_OES_compressed_ETC1_RGB8_texture +#define GL_OES_compressed_ETC1_RGB8_texture 1 +#endif + +/* GL_OES_compressed_paletted_texture */ +#ifndef GL_OES_compressed_paletted_texture +#define GL_OES_compressed_paletted_texture 1 +#endif + +/* GL_OES_EGL_image */ +#ifndef GL_OES_EGL_image +#define GL_OES_EGL_image 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glEGLImageTargetTexture2DOES (GLenum target, GLeglImageOES image); +GL_APICALL void GL_APIENTRY glEGLImageTargetRenderbufferStorageOES (GLenum target, GLeglImageOES image); +#endif +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) (GLenum target, GLeglImageOES image); +typedef void (GL_APIENTRYP PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC) (GLenum target, GLeglImageOES image); +#endif + +/* GL_OES_depth24 */ +#ifndef GL_OES_depth24 +#define GL_OES_depth24 1 +#endif + +/* GL_OES_depth32 */ +#ifndef GL_OES_depth32 +#define GL_OES_depth32 1 +#endif + +/* GL_OES_depth_texture */ +#ifndef GL_OES_depth_texture +#define GL_OES_depth_texture 1 +#endif + +/* GL_OES_element_index_uint */ +#ifndef GL_OES_element_index_uint +#define GL_OES_element_index_uint 1 +#endif + +/* GL_OES_fbo_render_mipmap */ +#ifndef GL_OES_fbo_render_mipmap +#define GL_OES_fbo_render_mipmap 1 +#endif + +/* GL_OES_fragment_precision_high */ +#ifndef GL_OES_fragment_precision_high +#define GL_OES_fragment_precision_high 1 +#endif + +/* GL_OES_get_program_binary */ +#ifndef GL_OES_get_program_binary +#define GL_OES_get_program_binary 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetProgramBinaryOES (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +GL_APICALL void GL_APIENTRY glProgramBinaryOES (GLuint program, GLenum binaryFormat, const void *binary, GLint length); +#endif +typedef void (GL_APIENTRYP PFNGLGETPROGRAMBINARYOESPROC) (GLuint program, GLsizei bufSize, GLsizei *length, GLenum *binaryFormat, void *binary); +typedef void (GL_APIENTRYP PFNGLPROGRAMBINARYOESPROC) (GLuint program, GLenum binaryFormat, const void *binary, GLint length); +#endif + +/* GL_OES_mapbuffer */ +#ifndef GL_OES_mapbuffer +#define GL_OES_mapbuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void* GL_APIENTRY glMapBufferOES (GLenum target, GLenum access); +GL_APICALL GLboolean GL_APIENTRY glUnmapBufferOES (GLenum target); +GL_APICALL void GL_APIENTRY glGetBufferPointervOES (GLenum target, GLenum pname, void** params); +#endif +typedef void* (GL_APIENTRYP PFNGLMAPBUFFEROESPROC) (GLenum target, GLenum access); +typedef GLboolean (GL_APIENTRYP PFNGLUNMAPBUFFEROESPROC) (GLenum target); +typedef void (GL_APIENTRYP PFNGLGETBUFFERPOINTERVOESPROC) (GLenum target, GLenum pname, void** params); +#endif + +/* GL_OES_packed_depth_stencil */ +#ifndef GL_OES_packed_depth_stencil +#define GL_OES_packed_depth_stencil 1 +#endif + +/* GL_OES_rgb8_rgba8 */ +#ifndef GL_OES_rgb8_rgba8 +#define GL_OES_rgb8_rgba8 1 +#endif + +/* GL_OES_standard_derivatives */ +#ifndef GL_OES_standard_derivatives +#define GL_OES_standard_derivatives 1 +#endif + +/* GL_OES_stencil1 */ +#ifndef GL_OES_stencil1 +#define GL_OES_stencil1 1 +#endif + +/* GL_OES_stencil4 */ +#ifndef GL_OES_stencil4 +#define GL_OES_stencil4 1 +#endif + +/* GL_OES_texture_3D */ +#ifndef GL_OES_texture_3D +#define GL_OES_texture_3D 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels); +GL_APICALL void GL_APIENTRY glTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +GL_APICALL void GL_APIENTRY glCopyTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +GL_APICALL void GL_APIENTRY glCompressedTexImage3DOES (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); +GL_APICALL void GL_APIENTRY glCompressedTexSubImage3DOES (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +GL_APICALL void GL_APIENTRY glFramebufferTexture3DOES (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +#endif +typedef void (GL_APIENTRYP PFNGLTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const GLvoid* pixels); +typedef void (GL_APIENTRYP PFNGLTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void* pixels); +typedef void (GL_APIENTRYP PFNGLCOPYTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXIMAGE3DOESPROC) (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void* data); +typedef void (GL_APIENTRYP PFNGLCOMPRESSEDTEXSUBIMAGE3DOESPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLsizei imageSize, const void* data); +typedef void (GL_APIENTRYP PFNGLFRAMEBUFFERTEXTURE3DOES) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +#endif + +/* GL_OES_texture_float_linear */ +#ifndef GL_OES_texture_float_linear +#define GL_OES_texture_float_linear 1 +#endif + +/* GL_OES_texture_half_float_linear */ +#ifndef GL_OES_texture_half_float_linear +#define GL_OES_texture_half_float_linear 1 +#endif + +/* GL_OES_texture_float */ +#ifndef GL_OES_texture_float +#define GL_OES_texture_float 1 +#endif + +/* GL_OES_texture_half_float */ +#ifndef GL_OES_texture_half_float +#define GL_OES_texture_half_float 1 +#endif + +/* GL_OES_texture_npot */ +#ifndef GL_OES_texture_npot +#define GL_OES_texture_npot 1 +#endif + +/* GL_OES_vertex_half_float */ +#ifndef GL_OES_vertex_half_float +#define GL_OES_vertex_half_float 1 +#endif + +/* GL_OES_vertex_type_10_10_10_2 */ +#ifndef GL_OES_vertex_type_10_10_10_2 +#define GL_OES_vertex_type_10_10_10_2 1 +#endif + +/*------------------------------------------------------------------------* + * AMD extension functions + *------------------------------------------------------------------------*/ + +/* GL_AMD_compressed_3DC_texture */ +#ifndef GL_AMD_compressed_3DC_texture +#define GL_AMD_compressed_3DC_texture 1 +#endif + +/* GL_AMD_compressed_ATC_texture */ +#ifndef GL_AMD_compressed_ATC_texture +#define GL_AMD_compressed_ATC_texture 1 +#endif + +/* GL_AMD_program_binary_Z400 */ +#ifndef GL_AMD_program_binary_Z400 +#define GL_AMD_program_binary_Z400 1 +#endif + +/* AMD_performance_monitor */ +#ifndef GL_AMD_performance_monitor +#define GL_AMD_performance_monitor 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupsAMD (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCountersAMD (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +GL_APICALL void GL_APIENTRY glGetPerfMonitorGroupStringAMD (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterStringAMD (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterInfoAMD (GLuint group, GLuint counter, GLenum pname, void *data); +GL_APICALL void GL_APIENTRY glGenPerfMonitorsAMD (GLsizei n, GLuint *monitors); +GL_APICALL void GL_APIENTRY glDeletePerfMonitorsAMD (GLsizei n, GLuint *monitors); +GL_APICALL void GL_APIENTRY glSelectPerfMonitorCountersAMD (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); +GL_APICALL void GL_APIENTRY glBeginPerfMonitorAMD (GLuint monitor); +GL_APICALL void GL_APIENTRY glEndPerfMonitorAMD (GLuint monitor); +GL_APICALL void GL_APIENTRY glGetPerfMonitorCounterDataAMD (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSAMDPROC) (GLint *numGroups, GLsizei groupsSize, GLuint *groups); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSAMDPROC) (GLuint group, GLint *numCounters, GLint *maxActiveCounters, GLsizei counterSize, GLuint *counters); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORGROUPSTRINGAMDPROC) (GLuint group, GLsizei bufSize, GLsizei *length, char *groupString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERSTRINGAMDPROC) (GLuint group, GLuint counter, GLsizei bufSize, GLsizei *length, char *counterString); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERINFOAMDPROC) (GLuint group, GLuint counter, GLenum pname, void *data); +typedef void (GL_APIENTRYP PFNGLGENPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (GL_APIENTRYP PFNGLDELETEPERFMONITORSAMDPROC) (GLsizei n, GLuint *monitors); +typedef void (GL_APIENTRYP PFNGLSELECTPERFMONITORCOUNTERSAMDPROC) (GLuint monitor, GLboolean enable, GLuint group, GLint numCounters, GLuint *countersList); +typedef void (GL_APIENTRYP PFNGLBEGINPERFMONITORAMDPROC) (GLuint monitor); +typedef void (GL_APIENTRYP PFNGLENDPERFMONITORAMDPROC) (GLuint monitor); +typedef void (GL_APIENTRYP PFNGLGETPERFMONITORCOUNTERDATAAMDPROC) (GLuint monitor, GLenum pname, GLsizei dataSize, GLuint *data, GLint *bytesWritten); +#endif + +/*------------------------------------------------------------------------* + * EXT extension functions + *------------------------------------------------------------------------*/ + +/* GL_EXT_texture_filter_anisotropic */ +#ifndef GL_EXT_texture_filter_anisotropic +#define GL_EXT_texture_filter_anisotropic 1 +#endif + +/* GL_EXT_texture_type_2_10_10_10_REV */ +#ifndef GL_EXT_texture_type_2_10_10_10_REV +#define GL_EXT_texture_type_2_10_10_10_REV 1 +#endif + +/* GL_EXT_texture_format_BGRA8888 */ +#ifndef GL_EXT_texture_format_BGRA8888 +#define GL_EXT_texture_format_BGRA8888 1 +#endif + +/* GL_EXT_discard_framebuffer */ +#ifndef GL_EXT_discard_framebuffer +#define GL_EXT_discard_framebuffer 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDiscardFramebufferEXT (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif +typedef void (GL_APIENTRYP PFNGLDISCARDFRAMEBUFFEREXTPROC) (GLenum target, GLsizei numAttachments, const GLenum *attachments); +#endif + +/* GL_EXT_blend_minmax */ +#ifndef GL_EXT_blend_minmax +#define GL_EXT_blend_minmax 1 +#endif + +/*------------------------------------------------------------------------* + * IMG extension functions + *------------------------------------------------------------------------*/ + +/* GL_IMG_read_format */ +#ifndef GL_IMG_read_format +#define GL_IMG_read_format 1 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_IMG_texture_compression_pvrtc 1 +#endif + +/*------------------------------------------------------------------------* + * NV extension functions + *------------------------------------------------------------------------*/ + +/* GL_NV_fence */ +#ifndef GL_NV_fence +#define GL_NV_fence 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glDeleteFencesNV (GLsizei, const GLuint *); +GL_APICALL void GL_APIENTRY glGenFencesNV (GLsizei, GLuint *); +GL_APICALL GLboolean GL_APIENTRY glIsFenceNV (GLuint); +GL_APICALL GLboolean GL_APIENTRY glTestFenceNV (GLuint); +GL_APICALL void GL_APIENTRY glGetFenceivNV (GLuint, GLenum, GLint *); +GL_APICALL void GL_APIENTRY glFinishFenceNV (GLuint); +GL_APICALL void GL_APIENTRY glSetFenceNV (GLuint, GLenum); +#endif +typedef void (GL_APIENTRYP PFNGLDELETEFENCESNVPROC) (GLsizei n, const GLuint *fences); +typedef void (GL_APIENTRYP PFNGLGENFENCESNVPROC) (GLsizei n, GLuint *fences); +typedef GLboolean (GL_APIENTRYP PFNGLISFENCENVPROC) (GLuint fence); +typedef GLboolean (GL_APIENTRYP PFNGLTESTFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLGETFENCEIVNVPROC) (GLuint fence, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLFINISHFENCENVPROC) (GLuint fence); +typedef void (GL_APIENTRYP PFNGLSETFENCENVPROC) (GLuint fence, GLenum condition); +#endif + +/*------------------------------------------------------------------------* + * QCOM extension functions + *------------------------------------------------------------------------*/ + +/* GL_QCOM_driver_control */ +#ifndef GL_QCOM_driver_control +#define GL_QCOM_driver_control 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glGetDriverControlsQCOM (GLint *num, GLsizei size, GLuint *driverControls); +GL_APICALL void GL_APIENTRY glGetDriverControlStringQCOM (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString); +GL_APICALL void GL_APIENTRY glEnableDriverControlQCOM (GLuint driverControl); +GL_APICALL void GL_APIENTRY glDisableDriverControlQCOM (GLuint driverControl); +#endif +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSQCOMPROC) (GLint *num, GLsizei size, GLuint *driverControls); +typedef void (GL_APIENTRYP PFNGLGETDRIVERCONTROLSTRINGQCOMPROC) (GLuint driverControl, GLsizei bufSize, GLsizei *length, char *driverControlString); +typedef void (GL_APIENTRYP PFNGLENABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +typedef void (GL_APIENTRYP PFNGLDISABLEDRIVERCONTROLQCOMPROC) (GLuint driverControl); +#endif + +/* GL_QCOM_perfmon_global_mode */ +#ifndef GL_QCOM_perfmon_global_mode +#define GL_QCOM_perfmon_global_mode 1 +#endif + +/* GL_QCOM_writeonly_rendering */ +#ifndef GL_QCOM_writeonly_rendering +#define GL_QCOM_writeonly_rendering 1 +#endif + +/* GL_QCOM_extended_get */ +#ifndef GL_QCOM_extended_get +#define GL_QCOM_extended_get 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetTexturesQCOM (GLuint *textures, GLint maxTextures, GLint *numTextures); +GL_APICALL void GL_APIENTRY glExtGetBuffersQCOM (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +GL_APICALL void GL_APIENTRY glExtGetRenderbuffersQCOM (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +GL_APICALL void GL_APIENTRY glExtGetFramebuffersQCOM (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +GL_APICALL void GL_APIENTRY glExtGetTexLevelParameterivQCOM (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +GL_APICALL void GL_APIENTRY glExtTexObjectStateOverrideiQCOM (GLenum target, GLenum pname, GLint param); +GL_APICALL void GL_APIENTRY glExtGetTexSubImageQCOM (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels); +GL_APICALL void GL_APIENTRY glExtGetBufferPointervQCOM (GLenum target, void **params); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETTEXTURESQCOMPROC) (GLuint *textures, GLint maxTextures, GLint *numTextures); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERSQCOMPROC) (GLuint *buffers, GLint maxBuffers, GLint *numBuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETRENDERBUFFERSQCOMPROC) (GLuint *renderbuffers, GLint maxRenderbuffers, GLint *numRenderbuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETFRAMEBUFFERSQCOMPROC) (GLuint *framebuffers, GLint maxFramebuffers, GLint *numFramebuffers); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXLEVELPARAMETERIVQCOMPROC) (GLuint texture, GLenum face, GLint level, GLenum pname, GLint *params); +typedef void (GL_APIENTRYP PFNGLEXTTEXOBJECTSTATEOVERRIDEIQCOMPROC) (GLenum target, GLenum pname, GLint param); +typedef void (GL_APIENTRYP PFNGLEXTGETTEXSUBIMAGEQCOMPROC) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, void *texels); +typedef void (GL_APIENTRYP PFNGLEXTGETBUFFERPOINTERVQCOMPROC) (GLenum target, void **params); +#endif + +/* GL_QCOM_extended_get2 */ +#ifndef GL_QCOM_extended_get2 +#define GL_QCOM_extended_get2 1 +#ifdef GL_GLEXT_PROTOTYPES +GL_APICALL void GL_APIENTRY glExtGetShadersQCOM (GLuint *shaders, GLint maxShaders, GLint *numShaders); +GL_APICALL void GL_APIENTRY glExtGetProgramsQCOM (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +GL_APICALL void GL_APIENTRY glExtIsProgramBinaryQCOM (GLuint program); +GL_APICALL void GL_APIENTRY glExtGetProgramBinarySourceQCOM (GLuint program, GLenum shadertype, char *source, GLint *length); +#endif +typedef void (GL_APIENTRYP PFNGLEXTGETSHADERSQCOMPROC) (GLuint *shaders, GLint maxShaders, GLint *numShaders); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMSQCOMPROC) (GLuint *programs, GLint maxPrograms, GLint *numPrograms); +typedef void (GL_APIENTRYP PFNGLEXTISPROGRAMBINARYQCOMPROC) (GLuint program); +typedef void (GL_APIENTRYP PFNGLEXTGETPROGRAMBINARYSOURCEQCOMPROC) (GLuint program, GLenum shadertype, char *source, GLint *length); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __gl2ext_h_ */ diff --git a/Include/GLES2/gl2extimg.h b/Include/GLES2/gl2extimg.h new file mode 100644 index 000000000..042b28d15 --- /dev/null +++ b/Include/GLES2/gl2extimg.h @@ -0,0 +1,51 @@ +#ifndef __gl2extimg_h_ +#define __gl2extimg_h_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/*------------------------------------------------------------------------* + * IMG extension tokens + *------------------------------------------------------------------------*/ + +/* GL_IMG_binary_shader */ +#ifndef GL_IMG_binary_shader +#define GL_SGX_BINARY_IMG 0x8C0A +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 +#endif + + +/* GL_IMG_texture_format_BGRA8888 */ +#define GL_BGRA 0x80E1 + + +/*------------------------------------------------------------------------* + * IMG extension functions + *------------------------------------------------------------------------*/ + +/* GL_IMG_binary_shader */ +#ifndef GL_IMG_binary_shader +#define GL_IMG_binary_shader 1 +#endif + +/* GL_IMG_texture_compression_pvrtc */ +#ifndef GL_IMG_texture_compression_pvrtc +#define GL_IMG_texture_compression_pvrtc 1 +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __gl2extimg_h_ */ diff --git a/Include/GLES2/gl2platform.h b/Include/GLES2/gl2platform.h new file mode 100644 index 000000000..3e9036c16 --- /dev/null +++ b/Include/GLES2/gl2platform.h @@ -0,0 +1,29 @@ +#ifndef __gl2platform_h_ +#define __gl2platform_h_ + +/* $Revision: 7173 $ on $Date:: 2009-01-09 11:18:21 -0800 #$ */ + +/* + * This document is licensed under the SGI Free Software B License Version + * 2.0. For details, see http://oss.sgi.com/projects/FreeB/ . + */ + +/* Platform-specific types and definitions for OpenGL ES 2.X gl2.h + * Last modified on 2008/12/19 + * + * Adopters may modify khrplatform.h and this file to suit their platform. + * You are encouraged to submit all modifications to the Khronos group so that + * they can be included in future versions of this file. Please submit changes + * by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla) + * by filing a bug against product "OpenGL-ES" component "Registry". + */ + +#include + +#ifndef GL_APICALL +#define GL_APICALL KHRONOS_APICALL +#endif + +#define GL_APIENTRY KHRONOS_APIENTRY + +#endif /* __gl2platform_h_ */ diff --git a/Include/KHR/khrplatform.h b/Include/KHR/khrplatform.h new file mode 100644 index 000000000..8341f71b9 --- /dev/null +++ b/Include/KHR/khrplatform.h @@ -0,0 +1,269 @@ +#ifndef __khrplatform_h_ +#define __khrplatform_h_ + +/* +** Copyright (c) 2008-2009 The Khronos Group Inc. +** +** Permission is hereby granted, free of charge, to any person obtaining a +** copy of this software and/or associated documentation files (the +** "Materials"), to deal in the Materials without restriction, including +** without limitation the rights to use, copy, modify, merge, publish, +** distribute, sublicense, and/or sell copies of the Materials, and to +** permit persons to whom the Materials are furnished to do so, subject to +** the following conditions: +** +** The above copyright notice and this permission notice shall be included +** in all copies or substantial portions of the Materials. +** +** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. +*/ + +/* Khronos platform-specific types and definitions. + * + * $Revision: 7820 $ on $Date: 2009-04-03 13:46:26 -0700 (Fri, 03 Apr 2009) $ + * + * Adopters may modify this file to suit their platform. Adopters are + * encouraged to submit platform specific modifications to the Khronos + * group so that they can be included in future versions of this file. + * Please submit changes by sending them to the public Khronos Bugzilla + * (http://khronos.org/bugzilla) by filing a bug against product + * "Khronos (general)" component "Registry". + * + * A predefined template which fills in some of the bug fields can be + * reached using http://tinyurl.com/khrplatform-h-bugreport, but you + * must create a Bugzilla login first. + * + * + * See the Implementer's Guidelines for information about where this file + * should be located on your system and for more details of its use: + * http://www.khronos.org/registry/implementers_guide.pdf + * + * This file should be included as + * #include + * by Khronos client API header files that use its types and defines. + * + * The types in khrplatform.h should only be used to define API-specific types. + * + * Types defined in khrplatform.h: + * khronos_int8_t signed 8 bit + * khronos_uint8_t unsigned 8 bit + * khronos_int16_t signed 16 bit + * khronos_uint16_t unsigned 16 bit + * khronos_int32_t signed 32 bit + * khronos_uint32_t unsigned 32 bit + * khronos_int64_t signed 64 bit + * khronos_uint64_t unsigned 64 bit + * khronos_intptr_t signed same number of bits as a pointer + * khronos_uintptr_t unsigned same number of bits as a pointer + * khronos_ssize_t signed size + * khronos_usize_t unsigned size + * khronos_float_t signed 32 bit floating point + * khronos_time_ns_t unsigned 64 bit time in nanoseconds + * khronos_utime_nanoseconds_t unsigned time interval or absolute time in + * nanoseconds + * khronos_stime_nanoseconds_t signed time interval in nanoseconds + * khronos_boolean_enum_t enumerated boolean type. This should + * only be used as a base type when a client API's boolean type is + * an enum. Client APIs which use an integer or other type for + * booleans cannot use this as the base type for their boolean. + * + * Tokens defined in khrplatform.h: + * + * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values. + * + * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0. + * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0. + * + * Calling convention macros defined in this file: + * KHRONOS_APICALL + * KHRONOS_APIENTRY + * KHRONOS_APIATTRIBUTES + * + * These may be used in function prototypes as: + * + * KHRONOS_APICALL void KHRONOS_APIENTRY funcname( + * int arg1, + * int arg2) KHRONOS_APIATTRIBUTES; + */ + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APICALL + *------------------------------------------------------------------------- + * This precedes the return type of the function in the function prototype. + */ +#if defined(_WIN32) && !defined(__SCITECH_SNAP__) +# define KHRONOS_APICALL __declspec(dllimport) +#elif defined (__SYMBIAN32__) +# define KHRONOS_APICALL IMPORT_C +#else +# define KHRONOS_APICALL +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIENTRY + *------------------------------------------------------------------------- + * This follows the return type of the function and precedes the function + * name in the function prototype. + */ +#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__) + /* Win32 but not WinCE */ +# define KHRONOS_APIENTRY __stdcall +#else +# define KHRONOS_APIENTRY +#endif + +/*------------------------------------------------------------------------- + * Definition of KHRONOS_APIATTRIBUTES + *------------------------------------------------------------------------- + * This follows the closing parenthesis of the function prototype arguments. + */ +#if defined (__ARMCC_2__) +#define KHRONOS_APIATTRIBUTES __softfp +#else +#define KHRONOS_APIATTRIBUTES +#endif + +/*------------------------------------------------------------------------- + * basic type definitions + *-----------------------------------------------------------------------*/ +#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__) + + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__VMS ) || defined(__sgi) + +/* + * Using + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(_WIN32) && !defined(__SCITECH_SNAP__) + +/* + * Win32 + */ +typedef __int32 khronos_int32_t; +typedef unsigned __int32 khronos_uint32_t; +typedef __int64 khronos_int64_t; +typedef unsigned __int64 khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif defined(__sun__) || defined(__digital__) + +/* + * Sun or Digital + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#if defined(__arch64__) || defined(_LP64) +typedef long int khronos_int64_t; +typedef unsigned long int khronos_uint64_t; +#else +typedef long long int khronos_int64_t; +typedef unsigned long long int khronos_uint64_t; +#endif /* __arch64__ */ +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#elif 0 + +/* + * Hypothetical platform with no float or int64 support + */ +typedef int khronos_int32_t; +typedef unsigned int khronos_uint32_t; +#define KHRONOS_SUPPORT_INT64 0 +#define KHRONOS_SUPPORT_FLOAT 0 + +#else + +/* + * Generic fallback + */ +#include +typedef int32_t khronos_int32_t; +typedef uint32_t khronos_uint32_t; +typedef int64_t khronos_int64_t; +typedef uint64_t khronos_uint64_t; +#define KHRONOS_SUPPORT_INT64 1 +#define KHRONOS_SUPPORT_FLOAT 1 + +#endif + + +/* + * Types that are (so far) the same on all platforms + */ +typedef signed char khronos_int8_t; +typedef unsigned char khronos_uint8_t; +typedef signed short int khronos_int16_t; +typedef unsigned short int khronos_uint16_t; +typedef signed long int khronos_intptr_t; +typedef unsigned long int khronos_uintptr_t; +typedef signed long int khronos_ssize_t; +typedef unsigned long int khronos_usize_t; + +#if KHRONOS_SUPPORT_FLOAT +/* + * Float type + */ +typedef float khronos_float_t; +#endif + +#if KHRONOS_SUPPORT_INT64 +/* Time types + * + * These types can be used to represent a time interval in nanoseconds or + * an absolute Unadjusted System Time. Unadjusted System Time is the number + * of nanoseconds since some arbitrary system event (e.g. since the last + * time the system booted). The Unadjusted System Time is an unsigned + * 64 bit value that wraps back to 0 every 584 years. Time intervals + * may be either signed or unsigned. + */ +typedef khronos_uint64_t khronos_utime_nanoseconds_t; +typedef khronos_int64_t khronos_stime_nanoseconds_t; +#endif + +/* + * Dummy value used to pad enum types to 32 bits. + */ +#ifndef KHRONOS_MAX_ENUM +#define KHRONOS_MAX_ENUM 0x7FFFFFFF +#endif + +/* + * Enumerated boolean type + * + * Values other than zero should be considered to be true. Therefore + * comparisons should not be made against KHRONOS_TRUE. + */ +typedef enum { + KHRONOS_FALSE = 0, + KHRONOS_TRUE = 1, + KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM +} khronos_boolean_enum_t; + +#endif /* __khrplatform_h_ */ diff --git a/Include/Surface.h b/Include/Surface.h new file mode 100644 index 000000000..e071a93c4 --- /dev/null +++ b/Include/Surface.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Surface.h: Defines the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#ifndef INCLUDE_SURFACE_H_ +#define INCLUDE_SURFACE_H_ + +#define EGLAPI +#include +#include + +#include "angleutils.h" + +namespace egl +{ +class Surface +{ + public: + Surface(IDirect3DDevice9 *device, IDirect3DSwapChain9 *swapChain, EGLint configID); + + ~Surface(); + + HWND getWindowHandle(); + void swap(); + + EGLint getWidth() const; + EGLint getHeight() const; + + virtual IDirect3DSurface9 *getRenderTarget(); + + private: + DISALLOW_COPY_AND_ASSIGN(Surface); + IDirect3DSwapChain9 *const mSwapChain; + IDirect3DSurface9 *mBackBuffer; + IDirect3DSurface9 *mRenderTarget; + + const EGLint mConfigID; // ID of EGLConfig surface was created with + EGLint mHeight; // Height of surface + EGLint mWidth; // Width of surface +// EGLint horizontalResolution; // Horizontal dot pitch +// EGLint verticalResolution; // Vertical dot pitch +// EGLBoolean largestPBuffer; // If true, create largest pbuffer possible +// EGLBoolean mipmapTexture; // True if texture has mipmaps +// EGLint mipmapLevel; // Mipmap level to render to +// EGLenum multisampleResolve; // Multisample resolve behavior + EGLint mPixelAspectRatio; // Display aspect ratio + EGLenum mRenderBuffer; // Render buffer + EGLenum mSwapBehavior; // Buffer swap behavior +// EGLenum textureFormat; // Format of texture: RGB, RGBA, or no texture +// EGLenum textureTarget; // Type of texture: 2D or no texture +// EGLenum vgAlphaFormat; // Alpha format for OpenVG +// EGLenum vgColorSpace; // Color space for OpenVG +}; +} + +#endif // INCLUDE_SURFACE_H_ diff --git a/Include/angleutils.h b/Include/angleutils.h new file mode 100644 index 000000000..f43074179 --- /dev/null +++ b/Include/angleutils.h @@ -0,0 +1,14 @@ +// +// Copyright (c) 2002-2010 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. +// + +// angleutils.h: Common ANGLE utilities. + +// A macro to disallow the copy constructor and operator= functions +// This must be used in the private: declarations for a class +#define DISALLOW_COPY_AND_ASSIGN(TypeName) \ + TypeName(const TypeName&); \ + void operator=(const TypeName&) + diff --git a/Include/debug.h b/Include/debug.h new file mode 100644 index 000000000..78856754c --- /dev/null +++ b/Include/debug.h @@ -0,0 +1,69 @@ +// +// Copyright (c) 2002-2010 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. +// + +// debug.h: Debugging utilities. + +#ifndef COMMON_DEBUG_H_ +#define COMMON_DEBUG_H_ + +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#include +#include + +namespace gl +{ + // Outputs text to the debugging log + void trace(const char *format, ...); +} + +// A macro to output a trace of a function call and its arguments to the debugging log +#ifndef NDEBUG + #define TRACE(arguments, ...) gl::trace("trace: %s("arguments")\n", __FUNCTION__, __VA_ARGS__) +#else + #define TRACE(...) ((void)0) +#endif + +// A macro to output a function call and its arguments to the debugging log, to denote an item in need of fixing. Will occur even in release mode. +#define FIXME(arguments, ...) gl::trace("fixme: %s("arguments")\n", __FUNCTION__, __VA_ARGS__) + +// A macro to output a function call and its arguments to the debugging log, in case of error. Will occur even in release mode. +#define ERR(arguments, ...) gl::trace("err: %s("arguments")\n", __FUNCTION__, __VA_ARGS__) + +// A macro asserting a condition and outputting failures to the debug log +#define ASSERT(expression) do { \ + if(!(expression)) \ + ERR("\t! Assert failed in %s(%d): "#expression"\n", __FUNCTION__, __LINE__); \ + assert(expression); \ + } while(0) + + +// A macro to indicate unimplemented functionality +#ifndef NDEBUG + #define UNIMPLEMENTED() do { \ + FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ + } while(0) +#else + #define UNIMPLEMENTED() FIXME("\t! Unimplemented: %s(%d)\n", __FUNCTION__, __LINE__) +#endif + +// A macro for code which is not expected to be reached under valid assumptions +#ifndef NDEBUG + #define UNREACHABLE() do { \ + ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__); \ + assert(false); \ + } while(0) +#else + #define UNREACHABLE() ERR("\t! Unreachable reached: %s(%d)\n", __FUNCTION__, __LINE__) +#endif + +// A macro functioning as a compile-time assert to validate constant conditions +#define META_ASSERT(condition) typedef int COMPILE_TIME_ASSERT_##__LINE__[static_cast(condition)?1:-1] + +#endif // COMMON_DEBUG_H_ diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..0513b7d0f --- /dev/null +++ b/LICENSE @@ -0,0 +1,32 @@ +// Copyright (C) 2002-2010 The ANGLE Project Authors. +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// +// Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// +// Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following +// disclaimer in the documentation and/or other materials provided +// with the distribution. +// +// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc. +// Ltd., nor the names of their contributors may be used to endorse +// or promote products derived from this software without specific +// prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS +// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE +// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, +// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN +// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. diff --git a/libEGL/Config.cpp b/libEGL/Config.cpp new file mode 100644 index 000000000..8ad51366a --- /dev/null +++ b/libEGL/Config.cpp @@ -0,0 +1,408 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Config.cpp: Implements the egl::Config class, describing the format, type +// and size for an egl::Surface. Implements EGLConfig and related functionality. +// [EGL 1.4] section 3.4 page 15. + +#include "Config.h" + +#include +#include + +#include "debug.h" + +using namespace std; + +namespace egl +{ +Config::Config(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample) + : mDisplayMode(displayMode), mRenderTargetFormat(renderTargetFormat), mDepthStencilFormat(depthStencilFormat), mMultiSample(multiSample) +{ + set(displayMode, minInterval, maxInterval, renderTargetFormat, depthStencilFormat, multiSample); +} + +void Config::setDefaults() +{ + mBufferSize = 0; + mRedSize = 0; + mGreenSize = 0; + mBlueSize = 0; + mLuminanceSize = 0; + mAlphaSize = 0; + mAlphaMaskSize = 0; + mBindToTextureRGB = EGL_DONT_CARE; + mBindToTextureRGBA = EGL_DONT_CARE; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = EGL_DONT_CARE; + mConfigID = EGL_DONT_CARE; + mConformant = 0; + mDepthSize = 0; + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = 0; + mMaxPBufferHeight = 0; + mMaxPBufferPixels = 0; + mMaxSwapInterval = EGL_DONT_CARE; + mMinSwapInterval = EGL_DONT_CARE; + mNativeRenderable = EGL_DONT_CARE; + mNativeVisualID = 0; + mNativeVisualType = EGL_DONT_CARE; + mRenderableType = EGL_OPENGL_ES_BIT; + mSampleBuffers = 0; + mSamples = 0; + mStencilSize = 0; + mSurfaceType = EGL_WINDOW_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = EGL_DONT_CARE; + mTransparentGreenValue = EGL_DONT_CARE; + mTransparentBlueValue = EGL_DONT_CARE; +} + +void Config::set(D3DDISPLAYMODE displayMode, EGLint minInterval, EGLint maxInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample) +{ + switch (renderTargetFormat) + { + case D3DFMT_A1R5G5B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 5; + mBlueSize = 5; + mAlphaSize = 1; + break; + case D3DFMT_A2R10G10B10: + mBufferSize = 32; + mRedSize = 10; + mGreenSize = 10; + mBlueSize = 10; + mAlphaSize = 2; + break; + case D3DFMT_A8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 8; + break; + case D3DFMT_R5G6B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 6; + mBlueSize = 5; + mAlphaSize = 0; + break; + case D3DFMT_X1R5G5B5: + mBufferSize = 16; + mRedSize = 5; + mGreenSize = 5; + mBlueSize = 5; + mAlphaSize = 0; + break; + case D3DFMT_X8R8G8B8: + mBufferSize = 32; + mRedSize = 8; + mGreenSize = 8; + mBlueSize = 8; + mAlphaSize = 0; + break; + default: + UNREACHABLE(); // Other formats should not be valid + } + + mLuminanceSize = 0; + mAlphaMaskSize = 0; + mBindToTextureRGB = EGL_FALSE; + mBindToTextureRGBA = EGL_FALSE; + mColorBufferType = EGL_RGB_BUFFER; + mConfigCaveat = (displayMode.Format == renderTargetFormat) ? EGL_NONE : EGL_SLOW_CONFIG; + mConfigID = 0; + mConformant = EGL_OPENGL_ES2_BIT; + + switch (depthStencilFormat) + { +// case D3DFMT_D16_LOCKABLE: +// mDepthSize = 16; +// mStencilSize = 0; +// break; + case D3DFMT_D32: + mDepthSize = 32; + mStencilSize = 0; + break; + case D3DFMT_D15S1: + mDepthSize = 16; + mStencilSize = 1; + break; + case D3DFMT_D24S8: + mDepthSize = 24; + mStencilSize = 8; + break; + case D3DFMT_D24X8: + mDepthSize = 24; + mStencilSize = 0; + break; + case D3DFMT_D24X4S4: + mDepthSize = 24; + mStencilSize = 4; + break; + case D3DFMT_D16: + mDepthSize = 16; + mStencilSize = 0; + break; +// case D3DFMT_D32F_LOCKABLE: +// mDepthSize = 32; +// mStencilSize = 0; +// break; +// case D3DFMT_D24FS8: +// mDepthSize = 24; +// mStencilSize = 8; +// break; + default: + UNREACHABLE(); + } + + mLevel = 0; + mMatchNativePixmap = EGL_NONE; + mMaxPBufferWidth = 0; + mMaxPBufferHeight = 0; + mMaxPBufferPixels = 0; + mMaxSwapInterval = maxInterval; + mMinSwapInterval = minInterval; + mNativeRenderable = EGL_FALSE; + mNativeVisualID = 0; + mNativeVisualType = 0; + mRenderableType = EGL_OPENGL_ES2_BIT; + mSampleBuffers = multiSample ? 1 : 0; + mSamples = multiSample; + mSurfaceType = EGL_PBUFFER_BIT | EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT; + mTransparentType = EGL_NONE; + mTransparentRedValue = 0; + mTransparentGreenValue = 0; + mTransparentBlueValue = 0; +} + +EGLConfig Config::getHandle() const +{ + return (EGLConfig)(size_t)mConfigID; +} + +SortConfig::SortConfig(const EGLint *attribList) + : mWantRed(false), mWantGreen(false), mWantBlue(false), mWantAlpha(false), mWantLuminance(false) +{ + scanForWantedComponents(attribList); +} + +void SortConfig::scanForWantedComponents(const EGLint *attribList) +{ + // [EGL] section 3.4.1 page 24 + // Sorting rule #3: by larger total number of color bits, not considering + // components that are 0 or don't-care. + for (const EGLint *attr = attribList; attr[0] != EGL_NONE; attr += 2) + { + if (attr[1] != 0 && attr[1] != EGL_DONT_CARE) + { + switch (attr[0]) + { + case EGL_RED_SIZE: mWantRed = true; break; + case EGL_GREEN_SIZE: mWantGreen = true; break; + case EGL_BLUE_SIZE: mWantBlue = true; break; + case EGL_ALPHA_SIZE: mWantAlpha = true; break; + case EGL_LUMINANCE_SIZE: mWantLuminance = true; break; + } + } + } +} + +EGLint SortConfig::wantedComponentsSize(const Config &config) const +{ + EGLint total = 0; + + if (mWantRed) total += config.mRedSize; + if (mWantGreen) total += config.mGreenSize; + if (mWantBlue) total += config.mBlueSize; + if (mWantAlpha) total += config.mAlphaSize; + if (mWantLuminance) total += config.mLuminanceSize; + + return total; +} + +bool SortConfig::operator()(const Config *x, const Config *y) const +{ + return (*this)(*x, *y); +} + +bool SortConfig::operator()(const Config &x, const Config &y) const +{ + #define SORT(attribute) \ + if (x.attribute != y.attribute) \ + { \ + return x.attribute < y.attribute; \ + } + + META_ASSERT(EGL_NONE < EGL_SLOW_CONFIG && EGL_SLOW_CONFIG < EGL_NON_CONFORMANT_CONFIG); + SORT(mConfigCaveat); + + META_ASSERT(EGL_RGB_BUFFER < EGL_LUMINANCE_BUFFER); + SORT(mColorBufferType); + + // By larger total number of color bits, only considering those that are requested to be > 0. + EGLint xComponentsSize = wantedComponentsSize(x); + EGLint yComponentsSize = wantedComponentsSize(y); + if (xComponentsSize != yComponentsSize) + { + return xComponentsSize > yComponentsSize; + } + + SORT(mBufferSize); + SORT(mSampleBuffers); + SORT(mSamples); + SORT(mDepthSize); + SORT(mStencilSize); + SORT(mAlphaMaskSize); + SORT(mNativeVisualType); + SORT(mConfigID); + + #undef SORT + + return false; +} + +// We'd like to use SortConfig to also eliminate duplicate configs. +// This works as long as we never have two configs with different per-RGB-component layouts, +// but the same total. +// 5551 and 565 are different because R+G+B is different. +// 5551 and 555 are different because bufferSize is different. +const EGLint ConfigSet::mSortAttribs[] = +{ + EGL_RED_SIZE, 1, + EGL_GREEN_SIZE, 1, + EGL_BLUE_SIZE, 1, + EGL_LUMINANCE_SIZE, 1, + // BUT NOT ALPHA + EGL_NONE +}; + +ConfigSet::ConfigSet() + : mSet(SortConfig(mSortAttribs)) +{ +} + +void ConfigSet::add(D3DDISPLAYMODE displayMode, EGLint minSwapInterval, EGLint maxSwapInterval, D3DFORMAT renderTargetFormat, D3DFORMAT depthStencilFormat, EGLint multiSample) +{ + Config config(displayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, multiSample); + + mSet.insert(config); +} + +void ConfigSet::enumerate() +{ + EGLint index = 1; + + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + config->mConfigID = index; + index++; + } +} + +size_t ConfigSet::size() const +{ + return mSet.size(); +} + +bool ConfigSet::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + if (configs) + { + vector passed; + passed.reserve(mSet.size()); + + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + bool match = true; + const EGLint *attribute = attribList; + + while (attribute[0] != EGL_NONE) + { + switch (attribute[0]) + { + case EGL_BUFFER_SIZE: match = config->mBufferSize >= attribute[1]; break; + case EGL_ALPHA_SIZE: match = config->mAlphaSize >= attribute[1]; break; + case EGL_BLUE_SIZE: match = config->mBlueSize >= attribute[1]; break; + case EGL_GREEN_SIZE: match = config->mGreenSize >= attribute[1]; break; + case EGL_RED_SIZE: match = config->mRedSize >= attribute[1]; break; + case EGL_DEPTH_SIZE: match = config->mDepthSize >= attribute[1]; break; + case EGL_STENCIL_SIZE: match = config->mStencilSize >= attribute[1]; break; + case EGL_CONFIG_CAVEAT: match = config->mConfigCaveat == attribute[1]; break; + case EGL_CONFIG_ID: match = config->mConfigID == attribute[1]; break; + case EGL_LEVEL: match = config->mLevel >= attribute[1]; break; + case EGL_NATIVE_RENDERABLE: match = config->mNativeRenderable == attribute[1]; break; + case EGL_NATIVE_VISUAL_TYPE: match = config->mNativeVisualType == attribute[1]; break; + case EGL_SAMPLES: match = config->mSamples >= attribute[1]; break; + case EGL_SAMPLE_BUFFERS: match = config->mSampleBuffers >= attribute[1]; break; + case EGL_SURFACE_TYPE: match = (config->mSurfaceType & attribute[1]) == attribute[1]; break; + case EGL_TRANSPARENT_TYPE: match = config->mTransparentType == attribute[1]; break; + case EGL_TRANSPARENT_BLUE_VALUE: match = config->mTransparentBlueValue == attribute[1]; break; + case EGL_TRANSPARENT_GREEN_VALUE: match = config->mTransparentGreenValue == attribute[1]; break; + case EGL_TRANSPARENT_RED_VALUE: match = config->mTransparentRedValue == attribute[1]; break; + case EGL_BIND_TO_TEXTURE_RGB: match = config->mBindToTextureRGB == attribute[1]; break; + case EGL_BIND_TO_TEXTURE_RGBA: match = config->mBindToTextureRGBA == attribute[1]; break; + case EGL_MIN_SWAP_INTERVAL: match = config->mMinSwapInterval == attribute[1]; break; + case EGL_MAX_SWAP_INTERVAL: match = config->mMaxSwapInterval == attribute[1]; break; + case EGL_LUMINANCE_SIZE: match = config->mLuminanceSize >= attribute[1]; break; + case EGL_ALPHA_MASK_SIZE: match = config->mAlphaMaskSize >= attribute[1]; break; + case EGL_COLOR_BUFFER_TYPE: match = config->mColorBufferType == attribute[1]; break; + case EGL_RENDERABLE_TYPE: match = (config->mRenderableType & attribute[1]) == attribute[1]; break; + case EGL_MATCH_NATIVE_PIXMAP: match = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: match = (config->mConformant & attribute[1]) == attribute[1]; break; + default: + return false; + } + + if (!match) + { + break; + } + + attribute += 2; + } + + if (match) + { + passed.push_back(&*config); + } + } + + sort(passed.begin(), passed.end(), SortConfig(attribList)); + + EGLint index; + for (index = 0; index < configSize && index < static_cast(passed.size()); index++) + { + configs[index] = passed[index]->getHandle(); + } + + *numConfig = index; + } + else + { + *numConfig = (EGLint)mSet.size(); + } + + return true; +} + +const egl::Config *ConfigSet::get(EGLConfig configHandle) +{ + for (Iterator config = mSet.begin(); config != mSet.end(); config++) + { + if (config->getHandle() == configHandle) + { + return &(*config); + } + } + + return NULL; +} +} diff --git a/libEGL/Display.cpp b/libEGL/Display.cpp new file mode 100644 index 000000000..abdf25788 --- /dev/null +++ b/libEGL/Display.cpp @@ -0,0 +1,338 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Display.cpp: Implements the egl::Display class, representing the abstract +// display on which graphics are drawn. Implements EGLDisplay. +// [EGL 1.4] section 2.1.2 page 3. + +#include "Display.h" + +#include "main.h" +#include "debug.h" + +#include + +namespace egl +{ +Display::Display(HDC deviceContext) : mDc(deviceContext) +{ + mD3d9 = NULL; + mDevice = NULL; + + mAdapter = D3DADAPTER_DEFAULT; + mDeviceType = D3DDEVTYPE_HAL; +} + +Display::~Display() +{ + terminate(); +} + +bool Display::initialize() +{ + if (isInitialized()) + { + return true; + } + + mD3d9 = Direct3DCreate9(D3D_SDK_VERSION); + + if (mD3d9) + { + if (mDc != NULL) + { + // UNIMPLEMENTED(); // FIXME: Determine which adapter index the device context corresponds to + } + + D3DCAPS9 caps; + HRESULT result = mD3d9->GetDeviceCaps(mAdapter, mDeviceType, &caps); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(EGL_BAD_ALLOC, false); + } + + if (caps.PixelShaderVersion < D3DPS_VERSION(2, 0) || caps.VertexShaderVersion < D3DVS_VERSION(2, 0)) + { + mD3d9->Release(); + mD3d9 = NULL; + } + else + { + EGLint minSwapInterval = 4; + EGLint maxSwapInterval = 0; + + if (caps.PresentationIntervals & D3DPRESENT_INTERVAL_IMMEDIATE) {minSwapInterval = min(minSwapInterval, 0); maxSwapInterval = max(maxSwapInterval, 0);} + if (caps.PresentationIntervals & D3DPRESENT_INTERVAL_ONE) {minSwapInterval = min(minSwapInterval, 1); maxSwapInterval = max(maxSwapInterval, 1);} + if (caps.PresentationIntervals & D3DPRESENT_INTERVAL_TWO) {minSwapInterval = min(minSwapInterval, 2); maxSwapInterval = max(maxSwapInterval, 2);} + if (caps.PresentationIntervals & D3DPRESENT_INTERVAL_THREE) {minSwapInterval = min(minSwapInterval, 3); maxSwapInterval = max(maxSwapInterval, 3);} + if (caps.PresentationIntervals & D3DPRESENT_INTERVAL_FOUR) {minSwapInterval = min(minSwapInterval, 4); maxSwapInterval = max(maxSwapInterval, 4);} + + const D3DFORMAT adapterFormats[] = + { + D3DFMT_A1R5G5B5, + D3DFMT_A2R10G10B10, + D3DFMT_A8R8G8B8, + D3DFMT_R5G6B5, + D3DFMT_X1R5G5B5, + D3DFMT_X8R8G8B8 + }; + + const D3DFORMAT depthStencilFormats[] = + { + // D3DFMT_D16_LOCKABLE, + D3DFMT_D32, + D3DFMT_D15S1, + D3DFMT_D24S8, + D3DFMT_D24X8, + D3DFMT_D24X4S4, + D3DFMT_D16, + // D3DFMT_D32F_LOCKABLE, + // D3DFMT_D24FS8 + }; + + D3DDISPLAYMODE currentDisplayMode; + mD3d9->GetAdapterDisplayMode(mAdapter, ¤tDisplayMode); + + for (int formatIndex = 0; formatIndex < sizeof(adapterFormats) / sizeof(D3DFORMAT); formatIndex++) + { + D3DFORMAT renderTargetFormat = adapterFormats[formatIndex]; + + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_RENDERTARGET, D3DRTYPE_SURFACE, renderTargetFormat); + + if (SUCCEEDED(result)) + { + for (int depthStencilIndex = 0; depthStencilIndex < sizeof(depthStencilFormats) / sizeof(D3DFORMAT); depthStencilIndex++) + { + D3DFORMAT depthStencilFormat = depthStencilFormats[depthStencilIndex]; + HRESULT result = mD3d9->CheckDeviceFormat(mAdapter, mDeviceType, currentDisplayMode.Format, D3DUSAGE_DEPTHSTENCIL, D3DRTYPE_SURFACE, depthStencilFormat); + + if (SUCCEEDED(result)) + { + HRESULT result = mD3d9->CheckDepthStencilMatch(mAdapter, mDeviceType, currentDisplayMode.Format, renderTargetFormat, depthStencilFormat); // FIXME: Only accept color formats available both in fullscreen and windowed? + + if (SUCCEEDED(result)) + { + // FIXME: Enumerate multi-sampling + + mConfigSet.add(currentDisplayMode, minSwapInterval, maxSwapInterval, renderTargetFormat, depthStencilFormat, 0); + } + } + } + } + } + } + + mConfigSet.enumerate(); + } + + if (!isInitialized()) + { + terminate(); + + return false; + } + + return true; +} + +void Display::terminate() +{ + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + delete *surface; + } + + for (ContextSet::iterator context = mContextSet.begin(); context != mContextSet.end(); context++) + { + glDestroyContext(*context); + } + + if (mDevice) + { + mDevice->Release(); + mDevice = NULL; + } + + if (mD3d9) + { + mD3d9->Release(); + mD3d9 = NULL; + } +} + +bool Display::getConfigs(EGLConfig *configs, const EGLint *attribList, EGLint configSize, EGLint *numConfig) +{ + return mConfigSet.getConfigs(configs, attribList, configSize, numConfig); +} + +bool Display::getConfigAttrib(EGLConfig config, EGLint attribute, EGLint *value) +{ + const egl::Config *configuration = mConfigSet.get(config); + + switch (attribute) + { + case EGL_BUFFER_SIZE: *value = configuration->mBufferSize; break; + case EGL_ALPHA_SIZE: *value = configuration->mAlphaSize; break; + case EGL_BLUE_SIZE: *value = configuration->mBlueSize; break; + case EGL_GREEN_SIZE: *value = configuration->mGreenSize; break; + case EGL_RED_SIZE: *value = configuration->mRedSize; break; + case EGL_DEPTH_SIZE: *value = configuration->mDepthSize; break; + case EGL_STENCIL_SIZE: *value = configuration->mStencilSize; break; + case EGL_CONFIG_CAVEAT: *value = configuration->mConfigCaveat; break; + case EGL_CONFIG_ID: *value = configuration->mConfigID; break; + case EGL_LEVEL: *value = configuration->mLevel; break; + case EGL_NATIVE_RENDERABLE: *value = configuration->mNativeRenderable; break; + case EGL_NATIVE_VISUAL_TYPE: *value = configuration->mNativeVisualType; break; + case EGL_SAMPLES: *value = configuration->mSamples; break; + case EGL_SAMPLE_BUFFERS: *value = configuration->mSampleBuffers; break; + case EGL_SURFACE_TYPE: *value = configuration->mSurfaceType; break; + case EGL_TRANSPARENT_TYPE: *value = configuration->mTransparentType; break; + case EGL_TRANSPARENT_BLUE_VALUE: *value = configuration->mTransparentBlueValue; break; + case EGL_TRANSPARENT_GREEN_VALUE: *value = configuration->mTransparentGreenValue; break; + case EGL_TRANSPARENT_RED_VALUE: *value = configuration->mTransparentRedValue; break; + case EGL_BIND_TO_TEXTURE_RGB: *value = configuration->mBindToTextureRGB; break; + case EGL_BIND_TO_TEXTURE_RGBA: *value = configuration->mBindToTextureRGBA; break; + case EGL_MIN_SWAP_INTERVAL: *value = configuration->mMinSwapInterval; break; + case EGL_MAX_SWAP_INTERVAL: *value = configuration->mMaxSwapInterval; break; + case EGL_LUMINANCE_SIZE: *value = configuration->mLuminanceSize; break; + case EGL_ALPHA_MASK_SIZE: *value = configuration->mAlphaMaskSize; break; + case EGL_COLOR_BUFFER_TYPE: *value = configuration->mColorBufferType; break; + case EGL_RENDERABLE_TYPE: *value = configuration->mRenderableType; break; + case EGL_MATCH_NATIVE_PIXMAP: *value = false; UNIMPLEMENTED(); break; + case EGL_CONFORMANT: *value = configuration->mConformant; break; + default: + return false; + } + + return true; +} + +egl::Surface *Display::createWindowSurface(HWND window, EGLConfig config) +{ + const egl::Config *configuration = mConfigSet.get(config); + + UINT adapter = D3DADAPTER_DEFAULT; + D3DDEVTYPE deviceType = D3DDEVTYPE_HAL; + D3DPRESENT_PARAMETERS presentParameters = {0}; + + presentParameters.AutoDepthStencilFormat = configuration->mDepthStencilFormat; + presentParameters.BackBufferCount = 1; + presentParameters.BackBufferFormat = configuration->mRenderTargetFormat; + presentParameters.BackBufferWidth = 0; + presentParameters.BackBufferHeight = 0; + presentParameters.EnableAutoDepthStencil = configuration->mDepthSize ? TRUE : FALSE; + presentParameters.Flags = 0; + presentParameters.hDeviceWindow = window; + presentParameters.MultiSampleQuality = 0; // FIXME: Unimplemented + presentParameters.MultiSampleType = D3DMULTISAMPLE_NONE; // FIXME: Unimplemented + presentParameters.PresentationInterval = configuration->mMinSwapInterval; + presentParameters.SwapEffect = D3DSWAPEFFECT_COPY; + presentParameters.Windowed = TRUE; // FIXME + + IDirect3DSwapChain9 *swapChain = NULL; + + if (!mDevice) + { + HRESULT result = mD3d9->CreateDevice(adapter, deviceType, window, D3DCREATE_FPU_PRESERVE | D3DCREATE_MIXED_VERTEXPROCESSING | D3DCREATE_NOWINDOWCHANGES, &presentParameters, &mDevice); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(EGL_BAD_ALLOC, (egl::Surface*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + if (mDevice) + { + mDevice->GetSwapChain(0, &swapChain); + } + } + else + { + HRESULT result = mDevice->CreateAdditionalSwapChain(&presentParameters, &swapChain); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(EGL_BAD_ALLOC, (egl::Surface*)NULL); + } + + ASSERT(SUCCEEDED(result)); + } + + Surface *surface = NULL; + + if (swapChain) + { + surface = new Surface(mDevice, swapChain, configuration->mConfigID); + mSurfaceSet.insert(surface); + + swapChain->Release(); + } + + return surface; +} + +EGLContext Display::createContext(EGLConfig configHandle) +{ + const egl::Config *config = mConfigSet.get(configHandle); + + gl::Context *context = glCreateContext(config); + mContextSet.insert(context); + + return context; +} + +void Display::destroySurface(egl::Surface *surface) +{ + delete surface; + mSurfaceSet.erase(surface); +} + +void Display::destroyContext(gl::Context *context) +{ + glDestroyContext(context); + mContextSet.erase(context); +} + +bool Display::isInitialized() +{ + return mD3d9 != NULL && mConfigSet.size() > 0; +} + +bool Display::isValidConfig(EGLConfig config) +{ + return mConfigSet.get(config) != NULL; +} + +bool Display::isValidContext(gl::Context *context) +{ + return mContextSet.find(context) != mContextSet.end(); +} + +bool Display::isValidSurface(egl::Surface *surface) +{ + return mSurfaceSet.find(surface) != mSurfaceSet.end(); +} + +bool Display::hasExistingWindowSurface(HWND window) +{ + for (SurfaceSet::iterator surface = mSurfaceSet.begin(); surface != mSurfaceSet.end(); surface++) + { + if ((*surface)->getWindowHandle() == window) + { + return true; + } + } + + return false; +} + +IDirect3DDevice9 *Display::getDevice() +{ + return mDevice; +} +} diff --git a/libEGL/Surface.cpp b/libEGL/Surface.cpp new file mode 100644 index 000000000..0bfbad99f --- /dev/null +++ b/libEGL/Surface.cpp @@ -0,0 +1,174 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Surface.cpp: Implements the egl::Surface class, representing a drawing surface +// such as the client area of a window, including any back buffers. +// Implements EGLSurface and related functionality. [EGL 1.4] section 2.2 page 3. + +#include "Surface.h" + +#include "main.h" +#include "debug.h" + +namespace egl +{ +Surface::Surface(IDirect3DDevice9 *device, IDirect3DSwapChain9 *swapChain, EGLint configID) : mSwapChain(swapChain), mConfigID(configID) +{ + mBackBuffer = NULL; + mRenderTarget = NULL; + + mPixelAspectRatio = (EGLint)(1.0 * EGL_DISPLAY_SCALING); // FIXME: Determine actual pixel aspect ratio + mRenderBuffer = EGL_BACK_BUFFER; + mSwapBehavior = EGL_BUFFER_PRESERVED; + + if (mSwapChain) + { + mSwapChain->AddRef(); + mSwapChain->GetBackBuffer(0, D3DBACKBUFFER_TYPE_MONO, &mBackBuffer); + + D3DSURFACE_DESC description; + mBackBuffer->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + + HRESULT result = device->CreateRenderTarget(mWidth, mHeight, description.Format, description.MultiSampleType, description.MultiSampleQuality, FALSE, &mRenderTarget, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(EGL_BAD_ALLOC); + + return; + } + + ASSERT(SUCCEEDED(result)); + } +} + +Surface::~Surface() +{ + if (mSwapChain) + { + mSwapChain->Release(); + } + + if (mBackBuffer) + { + mBackBuffer->Release(); + } + + if (mRenderTarget) + { + mRenderTarget->Release(); + } +} + +HWND Surface::getWindowHandle() +{ + if (mSwapChain) + { + D3DPRESENT_PARAMETERS presentParameters; + mSwapChain->GetPresentParameters(&presentParameters); + + return presentParameters.hDeviceWindow; + } + + return NULL; +} + +void Surface::swap() +{ + if (mSwapChain) + { + IDirect3DDevice9 *device; + mSwapChain->GetDevice(&device); + + D3DSURFACE_DESC description; + mBackBuffer->GetDesc(&description); + + // Copy the render target into a texture + IDirect3DTexture9 *texture; + HRESULT result = device->CreateTexture(mWidth, mHeight, 1, D3DUSAGE_RENDERTARGET, description.Format, D3DPOOL_DEFAULT, &texture, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(EGL_BAD_ALLOC); + } + + ASSERT(SUCCEEDED(result)); + + IDirect3DSurface9 *textureSurface; + texture->GetSurfaceLevel(0, &textureSurface); + + device->StretchRect(mRenderTarget, NULL, textureSurface, NULL, D3DTEXF_POINT); + + // Disable all pipeline operations + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE , FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE , FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + device->SetRenderState(D3DRS_COLORWRITEENABLE, D3DCOLORWRITEENABLE_ALPHA | D3DCOLORWRITEENABLE_BLUE | D3DCOLORWRITEENABLE_GREEN | D3DCOLORWRITEENABLE_RED); + device->SetRenderState(D3DRS_SRGBWRITEENABLE, FALSE); + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + + // Just sample the texture + device->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_SELECTARG1); + device->SetTextureStageState(0, D3DTSS_COLORARG1, D3DTA_TEXTURE); + device->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_DISABLE); + device->SetTexture(0, texture); + device->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); + device->SetSamplerState(0, D3DSAMP_SRGBTEXTURE, FALSE); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + device->SetRenderTarget(0, mBackBuffer); + + // Render the texture upside down into the back buffer + float quad[4][6] = {{ 0 - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 0.0f, 1.0f}, + {mWidth - 0.5f, 0 - 0.5f, 0.0f, 1.0f, 1.0f, 1.0f}, + {mWidth - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 1.0f, 0.0f}, + { 0 - 0.5f, mHeight - 0.5f, 0.0f, 1.0f, 0.0f, 0.0f}}; // x, y, z, rhw, u, v + + device->BeginScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, quad, 6 * sizeof(float)); + device->EndScene(); + + result = mSwapChain->Present(NULL, NULL, NULL, NULL, D3DPRESENT_INTERVAL_DEFAULT); // FIXME: Get the swap interval from the associated Display + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY || result == D3DERR_DRIVERINTERNALERROR) + { + return error(EGL_BAD_ALLOC); + } + + textureSurface->Release(); + texture->Release(); + device->Release(); + } +} + +EGLint Surface::getWidth() const +{ + return mWidth; +} + +EGLint Surface::getHeight() const +{ + return mHeight; +} + +IDirect3DSurface9 *Surface::getRenderTarget() +{ + if (mRenderTarget) + { + mRenderTarget->AddRef(); + } + + return mRenderTarget; +} +} diff --git a/libEGL/libEGL.cpp b/libEGL/libEGL.cpp new file mode 100644 index 000000000..8f52e2176 --- /dev/null +++ b/libEGL/libEGL.cpp @@ -0,0 +1,1026 @@ +// +// Copyright (c) 2002-2010 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. +// + +// libEGL.cpp: Implements the exported EGL functions. + +#include "main.h" +#include "Display.h" +#include "Context.h" +#include "debug.h" + +#include + +bool validate(egl::Display *display) +{ + if (display == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, false); + } + + if (!display->isInitialized()) + { + return error(EGL_NOT_INITIALIZED, false); + } + + return true; +} + +bool validate(egl::Display *display, EGLConfig config) +{ + if (!validate(display)) + { + return false; + } + + if (!display->isValidConfig(config)) + { + return error(EGL_BAD_CONFIG, false); + } + + return true; +} + +bool validate(egl::Display *display, gl::Context *context) +{ + if (!validate(display)) + { + return false; + } + + if (!display->isValidContext(context)) + { + return error(EGL_BAD_CONTEXT, false); + } + + return true; +} + +bool validate(egl::Display *display, egl::Surface *surface) +{ + if (!validate(display)) + { + return false; + } + + if (!display->isValidSurface(surface)) + { + return error(EGL_BAD_SURFACE, false); + } + + return true; +} + +extern "C" +{ +EGLint __stdcall eglGetError(void) +{ + TRACE(""); + + EGLint error = egl::getCurrentError(); + + if (error != EGL_SUCCESS) + { + egl::setCurrentError(EGL_SUCCESS); + } + + return error; +} + +EGLDisplay __stdcall eglGetDisplay(EGLNativeDisplayType display_id) +{ + TRACE("EGLNativeDisplayType display_id = 0x%0.8p", display_id); + + try + { + // FIXME: Return the same EGLDisplay handle when display_id already created a display + + if (display_id == EGL_DEFAULT_DISPLAY) + { + return new egl::Display((HDC)NULL); + } + else + { + // FIXME: Check if display_id is a valid display device context + + return new egl::Display((HDC)display_id); + } + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } + + return EGL_NO_DISPLAY; +} + +EGLBoolean __stdcall eglInitialize(EGLDisplay dpy, EGLint *major, EGLint *minor) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLint *major = 0x%0.8p, EGLint *minor = 0x%0.8p", dpy, major, minor); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast(dpy); + + if (!display->initialize()) + { + return error(EGL_NOT_INITIALIZED, EGL_FALSE); + } + + *major = 1; + *minor = 4; + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglTerminate(EGLDisplay dpy) +{ + TRACE("EGLDisplay dpy = 0x%0.8p", dpy); + + try + { + if (dpy == EGL_NO_DISPLAY) + { + return error(EGL_BAD_DISPLAY, EGL_FALSE); + } + + egl::Display *display = static_cast(dpy); + + display->terminate(); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +const char *__stdcall eglQueryString(EGLDisplay dpy, EGLint name) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLint name = %d", dpy, name); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return NULL; + } + + switch (name) + { + case EGL_CLIENT_APIS: + return success("OpenGL_ES"); + case EGL_EXTENSIONS: + return success(""); + case EGL_VENDOR: + return success("TransGaming Inc."); + case EGL_VERSION: + return success("1.4 (git-devel "__DATE__" " __TIME__")"); + } + + return error(EGL_BAD_PARAMETER, (const char*)NULL); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (const char*)NULL); + } + + return NULL; +} + +EGLBoolean __stdcall eglGetConfigs(EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p", dpy, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!display->getConfigs(configs, attribList, config_size, num_config)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglChooseConfig(EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p, EGLConfig *configs = 0x%0.8p, EGLint config_size = %d, EGLint *num_config = 0x%0.8p", dpy, attrib_list, configs, config_size, num_config); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (!num_config) + { + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + const EGLint attribList[] = {EGL_NONE}; + + if (!attrib_list) + { + attrib_list = attribList; + } + + display->getConfigs(configs, attrib_list, config_size, num_config); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglGetConfigAttrib(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p", dpy, config, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_FALSE; + } + + if (!display->getConfigAttrib(config, attribute, value)) + { + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLSurface __stdcall eglCreateWindowSurface(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativeWindowType win = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p", dpy, config, win, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_NO_SURFACE; + } + + HWND window = (HWND)win; + + if (!IsWindow(window)) + { + return error(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE); + } + + if (attrib_list) + { + while (*attrib_list != EGL_NONE) + { + switch (attrib_list[0]) + { + case EGL_RENDER_BUFFER: + switch (attrib_list[1]) + { + case EGL_BACK_BUFFER: + break; + case EGL_SINGLE_BUFFER: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); // Rendering directly to front buffer not supported + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + break; + case EGL_VG_COLORSPACE: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + case EGL_VG_ALPHA_FORMAT: + return error(EGL_BAD_MATCH, EGL_NO_SURFACE); + default: + return error(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE); + } + } + } + + if (display->hasExistingWindowSurface(window)) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + EGLSurface surface = (EGLSurface)display->createWindowSurface(window, config); + + return success(surface); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return EGL_NO_SURFACE; +} + +EGLSurface __stdcall eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p", dpy, config, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_DISPLAY); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return EGL_NO_SURFACE; +} + +EGLSurface __stdcall eglCreatePixmapSurface(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLNativePixmapType pixmap = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p", dpy, config, pixmap, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_DISPLAY); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return EGL_NO_SURFACE; +} + +EGLBoolean __stdcall eglDestroySurface(EGLDisplay dpy, EGLSurface surface) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p", dpy, surface); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + display->destroySurface((egl::Surface*)surface); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglQuerySurface(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p", dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + egl::Surface *eglSurface = (egl::Surface*)surface; + + switch (attribute) + { + case EGL_VG_ALPHA_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VG_COLORSPACE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_CONFIG_ID: + UNIMPLEMENTED(); // FIXME + break; + case EGL_HEIGHT: + *value = eglSurface->getHeight(); + break; + case EGL_HORIZONTAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_LARGEST_PBUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_TEXTURE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MIPMAP_LEVEL: + UNIMPLEMENTED(); // FIXME + break; + case EGL_MULTISAMPLE_RESOLVE: + UNIMPLEMENTED(); // FIXME + break; + case EGL_PIXEL_ASPECT_RATIO: + UNIMPLEMENTED(); // FIXME + break; + case EGL_RENDER_BUFFER: + UNIMPLEMENTED(); // FIXME + break; + case EGL_SWAP_BEHAVIOR: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_FORMAT: + UNIMPLEMENTED(); // FIXME + break; + case EGL_TEXTURE_TARGET: + UNIMPLEMENTED(); // FIXME + break; + case EGL_VERTICAL_RESOLUTION: + UNIMPLEMENTED(); // FIXME + break; + case EGL_WIDTH: + *value = eglSurface->getWidth(); + break; + default: + return error(EGL_BAD_ATTRIBUTE, EGL_FALSE); + } + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglBindAPI(EGLenum api) +{ + TRACE("EGLenum api = 0x%X", api); + + try + { + switch (api) + { + case EGL_OPENGL_API: + case EGL_OPENVG_API: + return error(EGL_BAD_PARAMETER, EGL_FALSE); // Not supported by this implementation + case EGL_OPENGL_ES_API: + break; + default: + return error(EGL_BAD_PARAMETER, EGL_FALSE); + } + + egl::setCurrentAPI(api); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLenum __stdcall eglQueryAPI(void) +{ + TRACE(""); + + try + { + EGLenum API = egl::getCurrentAPI(); + + return success(API); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglWaitClient(void) +{ + TRACE(""); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglReleaseThread(void) +{ + TRACE(""); + + try + { + eglMakeCurrent(EGL_NO_DISPLAY, EGL_NO_CONTEXT, EGL_NO_SURFACE, EGL_NO_SURFACE); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLSurface __stdcall eglCreatePbufferFromClientBuffer(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLenum buftype = 0x%X, EGLClientBuffer buffer = 0x%0.8p, EGLConfig config = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p", dpy, buftype, buffer, config, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_NO_SURFACE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_SURFACE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return EGL_NO_SURFACE; +} + +EGLBoolean __stdcall eglSurfaceAttrib(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint attribute = %d, EGLint value = %d", dpy, surface, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglBindTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglReleaseTexImage(EGLDisplay dpy, EGLSurface surface, EGLint buffer) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLint buffer = %d", dpy, surface, buffer); + + try + { + egl::Display *display = static_cast(dpy); + + if(!validate(display)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglSwapInterval(EGLDisplay dpy, EGLint interval) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLint interval = %d", dpy, interval); + + try + { + egl::Display *display = static_cast(dpy); + + if(!validate(display)) + { + return EGL_FALSE; + } + + // UNIMPLEMENTED(); // FIXME + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLContext __stdcall eglCreateContext(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLConfig config = 0x%0.8p, EGLContext share_context = 0x%0.8p, const EGLint *attrib_list = 0x%0.8p", dpy, config, share_context, attrib_list); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display, config)) + { + return EGL_NO_CONTEXT; + } + + EGLContext context = display->createContext(config); + + return success(context); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } + + return EGL_NO_CONTEXT; +} + +EGLBoolean __stdcall eglDestroyContext(EGLDisplay dpy, EGLContext ctx) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p", dpy, ctx); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (ctx == EGL_NO_CONTEXT) + { + return error(EGL_BAD_CONTEXT, EGL_FALSE); + } + + display->destroyContext((gl::Context*)ctx); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglMakeCurrent(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface draw = 0x%0.8p, EGLSurface read = 0x%0.8p, EGLContext ctx = 0x%0.8p", dpy, draw, read, ctx); + + try + { + egl::Display *display = static_cast(dpy); + gl::Context *context = static_cast(ctx); + + if (ctx != EGL_NO_CONTEXT && !validate(display, context)) + { + return EGL_FALSE; + } + + if ((draw != EGL_NO_SURFACE && !validate(display, static_cast(draw))) || + (read != EGL_NO_SURFACE && !validate(display, static_cast(read)))) + { + return EGL_FALSE; + } + + if (draw != read) + { + UNIMPLEMENTED(); // FIXME + } + + glMakeCurrent(context, display, static_cast(draw)); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLContext __stdcall eglGetCurrentContext(void) +{ + TRACE(""); + + try + { + EGLContext context = glGetCurrentContext(); + + return success(context); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_CONTEXT); + } + + return EGL_NO_CONTEXT; +} + +EGLSurface __stdcall eglGetCurrentSurface(EGLint readdraw) +{ + TRACE("EGLint readdraw = %d", readdraw); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_SURFACE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_SURFACE); + } + + return EGL_NO_SURFACE; +} + +EGLDisplay __stdcall eglGetCurrentDisplay(void) +{ + TRACE(""); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(EGL_NO_DISPLAY); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_NO_DISPLAY); + } + + return EGL_NO_DISPLAY; +} + +EGLBoolean __stdcall eglQueryContext(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLContext ctx = 0x%0.8p, EGLint attribute = %d, EGLint *value = 0x%0.8p", dpy, ctx, attribute, value); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglWaitGL(void) +{ + TRACE(""); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglWaitNative(EGLint engine) +{ + TRACE("EGLint engine = %d", engine); + + try + { + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglSwapBuffers(EGLDisplay dpy, EGLSurface surface) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p", dpy, surface); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + if (surface == EGL_NO_SURFACE) + { + return error(EGL_BAD_SURFACE, EGL_FALSE); + } + + egl::Surface *eglSurface = (egl::Surface*)surface; + eglSurface->swap(); + + return success(EGL_TRUE); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +EGLBoolean __stdcall eglCopyBuffers(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target) +{ + TRACE("EGLDisplay dpy = 0x%0.8p, EGLSurface surface = 0x%0.8p, EGLNativePixmapType target = 0x%0.8p", dpy, surface, target); + + try + { + egl::Display *display = static_cast(dpy); + + if (!validate(display)) + { + return EGL_FALSE; + } + + UNIMPLEMENTED(); // FIXME + + return success(0); + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, EGL_FALSE); + } + + return EGL_FALSE; +} + +__eglMustCastToProperFunctionPointerType __stdcall eglGetProcAddress(const char *procname) +{ + TRACE("const char *procname = \"%s\"", procname); + + try + { + UNIMPLEMENTED(); // FIXME + + return NULL; + } + catch(std::bad_alloc&) + { + return error(EGL_BAD_ALLOC, (__eglMustCastToProperFunctionPointerType)NULL); + } + + return NULL; +} +} diff --git a/libEGL/libEGL.def b/libEGL/libEGL.def new file mode 100644 index 000000000..71a5e6797 --- /dev/null +++ b/libEGL/libEGL.def @@ -0,0 +1,36 @@ +LIBRARY libEGL +EXPORTS + eglBindAPI @14 + eglBindTexImage @20 + eglChooseConfig @7 + eglCopyBuffers @33 + eglCreateContext @23 + eglCreatePbufferFromClientBuffer @18 + eglCreatePbufferSurface @10 + eglCreatePixmapSurface @11 + eglCreateWindowSurface @9 + eglDestroyContext @24 + eglDestroySurface @12 + eglGetConfigAttrib @8 + eglGetConfigs @6 + eglGetCurrentContext @26 + eglGetCurrentDisplay @28 + eglGetCurrentSurface @27 + eglGetDisplay @2 + eglGetError @1 + eglGetProcAddress @34 + eglInitialize @3 + eglMakeCurrent @25 + eglQueryAPI @15 + eglQueryContext @29 + eglQueryString @5 + eglQuerySurface @13 + eglReleaseTexImage @21 + eglReleaseThread @17 + eglSurfaceAttrib @19 + eglSwapBuffers @32 + eglSwapInterval @22 + eglTerminate @4 + eglWaitClient @16 + eglWaitGL @30 + eglWaitNative @31 \ No newline at end of file diff --git a/libEGL/libEGL.vcproj b/libEGL/libEGL.vcproj new file mode 100644 index 000000000..78634f539 --- /dev/null +++ b/libEGL/libEGL.vcproj @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libEGL/main.cpp b/libEGL/main.cpp new file mode 100644 index 000000000..449892f2d --- /dev/null +++ b/libEGL/main.cpp @@ -0,0 +1,116 @@ +// +// Copyright (c) 2002-2010 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. +// + +// main.cpp: DLL entry point and management of thread-local data. + +#include "main.h" + +#include "debug.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + #ifndef NDEBUG + FILE *debug = fopen("debug.txt", "rt"); + + if (debug) + { + fclose(debug); + debug = fopen("debug.txt", "wt"); // Erase + fclose(debug); + } + #endif + + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + egl::Current *current = (egl::Current*)LocalAlloc(LPTR, sizeof(egl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->error = EGL_SUCCESS; + current->API = EGL_OPENGL_ES_API; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace egl +{ +void setCurrentError(EGLint error) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->error = error; +} + +EGLint getCurrentError() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->error; +} + +void setCurrentAPI(EGLenum API) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->API = API; +} + +EGLenum getCurrentAPI() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->API; +} +} + +void error(EGLint errorCode) +{ + egl::setCurrentError(errorCode); +} diff --git a/libEGL/main.h b/libEGL/main.h new file mode 100644 index 000000000..77a28576e --- /dev/null +++ b/libEGL/main.h @@ -0,0 +1,48 @@ +// +// Copyright (c) 2002-2010 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. +// + +// main.h: Management of thread-local data. + +#ifndef LIBEGL_MAIN_H_ +#define LIBEGL_MAIN_H_ + +#define EGLAPI +#include + +namespace egl +{ +struct Current +{ + EGLint error; + EGLenum API; +}; + +void setCurrentError(EGLint error); +EGLint getCurrentError(); + +void setCurrentAPI(EGLenum API); +EGLenum getCurrentAPI(); +} + +void error(EGLint errorCode); + +template +const T &error(EGLint errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +template +const T &success(const T &returnValue) +{ + egl::setCurrentError(EGL_SUCCESS); + + return returnValue; +} + +#endif // LIBEGL_MAIN_H_ diff --git a/libGLESv2/Buffer.cpp b/libGLESv2/Buffer.cpp new file mode 100644 index 000000000..f43922903 --- /dev/null +++ b/libGLESv2/Buffer.cpp @@ -0,0 +1,120 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Buffer.cpp: Implements the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#include "Buffer.h" + +#include "main.h" + +namespace gl +{ +Buffer::Buffer() +{ + mSize = 0; + mData = NULL; + + mVertexBuffer = NULL; + mIndexBuffer = NULL; +} + +Buffer::~Buffer() +{ + erase(); +} + +void Buffer::storeData(GLsizeiptr size, const void *data) +{ + erase(); + + mSize = size; + mData = new unsigned char[size]; + + if (data) + { + memcpy(mData, data, size); + } +} + +IDirect3DVertexBuffer9 *Buffer::getVertexBuffer() +{ + if (!mVertexBuffer) + { + IDirect3DDevice9 *device = getDevice(); + + HRESULT result = device->CreateVertexBuffer(mSize, 0, 0, D3DPOOL_MANAGED, &mVertexBuffer, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (IDirect3DVertexBuffer9*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + if (mVertexBuffer && mData) + { + void *dataStore; + mVertexBuffer->Lock(0, mSize, &dataStore, 0); + memcpy(dataStore, mData, mSize); + mVertexBuffer->Unlock(); + } + } + + return mVertexBuffer; +} + +IDirect3DIndexBuffer9 *Buffer::getIndexBuffer() +{ + if (!mIndexBuffer) + { + IDirect3DDevice9 *device = getDevice(); + + HRESULT result = device->CreateIndexBuffer(mSize, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &mIndexBuffer, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (IDirect3DIndexBuffer9*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + if (mIndexBuffer && mData) + { + void *dataStore; + mIndexBuffer->Lock(0, mSize, &dataStore, 0); + memcpy(dataStore, mData, mSize); + mIndexBuffer->Unlock(); + } + } + + return mIndexBuffer; +} + +void Buffer::erase() +{ + mSize = 0; + + if (mData) + { + delete[] mData; + mData = NULL; + } + + if (mVertexBuffer) + { + mVertexBuffer->Release(); + mVertexBuffer = NULL; + } + + if (mIndexBuffer) + { + mIndexBuffer->Release(); + mIndexBuffer = NULL; + } +} +} diff --git a/libGLESv2/Buffer.h b/libGLESv2/Buffer.h new file mode 100644 index 000000000..44ae5ad99 --- /dev/null +++ b/libGLESv2/Buffer.h @@ -0,0 +1,47 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Buffer.h: Defines the gl::Buffer class, representing storage of vertex and/or +// index data. Implements GL buffer objects and related functionality. +// [OpenGL ES 2.0.24] section 2.9 page 21. + +#ifndef LIBGLESV2_BUFFER_H_ +#define LIBGLESV2_BUFFER_H_ + +#define GL_APICALL +#include +#include + +#include "angleutils.h" + +namespace gl +{ +class Buffer +{ + public: + Buffer(); + + ~Buffer(); + + void storeData(GLsizeiptr size, const void *data); + + IDirect3DVertexBuffer9 *getVertexBuffer(); + IDirect3DIndexBuffer9 *getIndexBuffer(); + + private: + DISALLOW_COPY_AND_ASSIGN(Buffer); + + void erase(); + + unsigned int mSize; + void *mData; + + IDirect3DVertexBuffer9 *mVertexBuffer; + IDirect3DIndexBuffer9 *mIndexBuffer; +}; +} + +#endif // LIBGLESV2_BUFFER_H_ diff --git a/libGLESv2/Context.cpp b/libGLESv2/Context.cpp new file mode 100644 index 000000000..2c6944c7d --- /dev/null +++ b/libGLESv2/Context.cpp @@ -0,0 +1,1819 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Context.cpp: Implements the gl::Context class, managing all GL state and performing +// rendering operations. It is the GLES2 specific implementation of EGLContext. + +#include "Context.h" +#include "main.h" +#include "Display.h" +#include "Buffer.h" +#include "Shader.h" +#include "Program.h" +#include "Texture.h" +#include "FrameBuffer.h" +#include "RenderBuffer.h" +#include "mathutil.h" +#include "utilities.h" + +namespace gl +{ +Array::Array() +{ + enabled = false; + boundBuffer = 0; + size = 4; + type = GL_FLOAT; + normalized = GL_FALSE; + stride = 0; + pointer = NULL; +} + +Context::Context(const egl::Config *config) : mConfig(config) +{ + setClearColor(0.0f, 0.0f, 0.0f, 0.0f); + depthClearValue = 1.0f; + stencilClearValue = 0; + + cullFace = false; + cullMode = GL_BACK; + frontFace = GL_CCW; + depthTest = false; + depthFunc = GL_LESS; + blend = false; + sourceBlendRGB = GL_ONE; + sourceBlendAlpha = GL_ONE; + destBlendRGB = GL_ZERO; + destBlendAlpha = GL_ZERO; + blendEquationRGB = GL_FUNC_ADD; + blendEquationAlpha = GL_FUNC_ADD; + blendColor.red = 0; + blendColor.green = 0; + blendColor.blue = 0; + blendColor.alpha = 0; + stencilTest = false; + stencilFunc = GL_ALWAYS; + stencilRef = 0; + stencilMask = -1; + stencilWritemask = -1; + stencilBackFunc = GL_ALWAYS; + stencilBackRef = 0; + stencilBackMask = - 1; + stencilBackWritemask = -1; + stencilFail = GL_KEEP; + stencilPassDepthFail = GL_KEEP; + stencilPassDepthPass = GL_KEEP; + stencilBackFail = GL_KEEP; + stencilBackPassDepthFail = GL_KEEP; + stencilBackPassDepthPass = GL_KEEP; + polygonOffsetFill = false; + sampleAlphaToCoverage = false; + sampleCoverage = false; + sampleCoverageValue = 1.0f; + sampleCoverageInvert = GL_FALSE; + scissorTest = false; + dither = true; + + viewportX = 0; + viewportY = 0; + viewportWidth = config->mDisplayMode.Width; + viewportHeight = config->mDisplayMode.Height; + zNear = 0.0f; + zFar = 1.0f; + + scissorX = 0; + scissorY = 0; + scissorWidth = config->mDisplayMode.Width; + scissorHeight = config->mDisplayMode.Height; + + colorMaskRed = true; + colorMaskGreen = true; + colorMaskBlue = true; + colorMaskAlpha = true; + depthMask = true; + + // [OpenGL ES 2.0.24] section 3.7 page 83: + // In the initial state, TEXTURE_2D and TEXTURE_CUBE_MAP have twodimensional + // and cube map texture state vectors respectively associated with them. + // In order that access to these initial textures not be lost, they are treated as texture + // objects all of whose names are 0. + + mTexture2DZero = new Texture2D(); + mTextureCubeMapZero = new TextureCubeMap(); + + mColorbufferZero = NULL; + mDepthbufferZero = NULL; + mStencilbufferZero = NULL; + + activeSampler = 0; + arrayBuffer = 0; + elementArrayBuffer = 0; + bindTextureCubeMap(0); + bindTexture2D(0); + bindFramebuffer(0); + bindRenderbuffer(0); + + for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + { + samplerTexture[sampler] = 0; + } + + currentProgram = 0; + + mInvalidEnum = false; + mInvalidValue = false; + mInvalidOperation = false; + mOutOfMemory = false; + mInvalidFramebufferOperation = false; +} + +Context::~Context() +{ + currentProgram = 0; + + delete mTexture2DZero; + delete mTextureCubeMapZero; + + delete mColorbufferZero; + delete mDepthbufferZero; + delete mStencilbufferZero; + + while (!mBufferMap.empty()) + { + deleteBuffer(mBufferMap.begin()->first); + } + + while (!mProgramMap.empty()) + { + deleteProgram(mProgramMap.begin()->first); + } + + while (!mShaderMap.empty()) + { + deleteShader(mShaderMap.begin()->first); + } + + while (!mFramebufferMap.empty()) + { + deleteFramebuffer(mFramebufferMap.begin()->first); + } + + while (!mRenderbufferMap.empty()) + { + deleteRenderbuffer(mRenderbufferMap.begin()->first); + } + + while (!mTextureMap.empty()) + { + deleteTexture(mTextureMap.begin()->first); + } +} + +void Context::makeCurrent(egl::Display *display, egl::Surface *surface) +{ + IDirect3DDevice9 *device = display->getDevice(); + + // Wrap the existing Direct3D 9 resources into GL objects and assign them to the '0' names + IDirect3DSurface9 *defaultRenderTarget = surface->getRenderTarget(); + IDirect3DSurface9 *defaultDepthStencil = NULL; + device->GetDepthStencilSurface(&defaultDepthStencil); + + Framebuffer *framebufferZero = new Framebuffer(); + Colorbuffer *colorbufferZero = new Colorbuffer(defaultRenderTarget); + Depthbuffer *depthbufferZero = new Depthbuffer(defaultDepthStencil); + Stencilbuffer *stencilbufferZero = new Stencilbuffer(defaultDepthStencil); + + setFramebufferZero(framebufferZero); + setColorbufferZero(colorbufferZero); + setDepthbufferZero(depthbufferZero); + setStencilbufferZero(stencilbufferZero); + + framebufferZero->setColorbuffer(GL_RENDERBUFFER, 0); + framebufferZero->setDepthbuffer(GL_RENDERBUFFER, 0); + framebufferZero->setStencilbuffer(GL_RENDERBUFFER, 0); + + defaultRenderTarget->Release(); + + if (defaultDepthStencil) + { + defaultDepthStencil->Release(); + } +} + +void Context::setClearColor(float red, float green, float blue, float alpha) +{ + colorClearValue.red = red; + colorClearValue.green = green; + colorClearValue.blue = blue; + colorClearValue.alpha = alpha; +} + +void Context::setClearDepth(float depth) +{ + depthClearValue = depth; +} + +void Context::setClearStencil(int stencil) +{ + stencilClearValue = stencil; +} + +// Returns an unused buffer name +GLuint Context::createBuffer() +{ + unsigned int handle = 1; + + while (mBufferMap.find(handle) != mBufferMap.end()) + { + handle++; + } + + mBufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused shader/program name +GLuint Context::createShader(GLenum type) +{ + unsigned int handle = 1; + + while (mShaderMap.find(handle) != mShaderMap.end() || mProgramMap.find(handle) != mProgramMap.end()) // Shared name space + { + handle++; + } + + if (type == GL_VERTEX_SHADER) + { + mShaderMap[handle] = new VertexShader(); + } + else if (type == GL_FRAGMENT_SHADER) + { + mShaderMap[handle] = new FragmentShader(); + } + else UNREACHABLE(); + + return handle; +} + +// Returns an unused program/shader name +GLuint Context::createProgram() +{ + unsigned int handle = 1; + + while (mProgramMap.find(handle) != mProgramMap.end() || mShaderMap.find(handle) != mShaderMap.end()) // Shared name space + { + handle++; + } + + mProgramMap[handle] = new Program(); + + return handle; +} + +// Returns an unused texture name +GLuint Context::createTexture() +{ + unsigned int handle = 1; + + while (mTextureMap.find(handle) != mTextureMap.end()) + { + handle++; + } + + mTextureMap[handle] = NULL; + + return handle; +} + +// Returns an unused framebuffer name +GLuint Context::createFramebuffer() +{ + unsigned int handle = 1; + + while (mFramebufferMap.find(handle) != mFramebufferMap.end()) + { + handle++; + } + + mFramebufferMap[handle] = NULL; + + return handle; +} + +// Returns an unused renderbuffer name +GLuint Context::createRenderbuffer() +{ + unsigned int handle = 1; + + while(mRenderbufferMap.find(handle) != mRenderbufferMap.end()) + { + handle++; + } + + mRenderbufferMap[handle] = NULL; + + return handle; +} + +void Context::deleteBuffer(GLuint buffer) +{ + BufferMap::iterator bufferObject = mBufferMap.find(buffer); + + if (bufferObject != mBufferMap.end()) + { + detachBuffer(buffer); + + delete bufferObject->second; + mBufferMap.erase(bufferObject); + } +} + +void Context::deleteShader(GLuint shader) +{ + ShaderMap::iterator shaderObject = mShaderMap.find(shader); + + if (shaderObject != mShaderMap.end()) + { + if (!shaderObject->second->isAttached()) + { + delete shaderObject->second; + mShaderMap.erase(shaderObject); + } + else + { + shaderObject->second->flagForDeletion(); + } + } +} + +void Context::deleteProgram(GLuint program) +{ + ProgramMap::iterator programObject = mProgramMap.find(program); + + if (programObject != mProgramMap.end()) + { + if (program != currentProgram) + { + delete programObject->second; + mProgramMap.erase(programObject); + } + else + { + programObject->second->flagForDeletion(); + } + } +} + +void Context::deleteTexture(GLuint texture) +{ + TextureMap::iterator textureObject = mTextureMap.find(texture); + + if (textureObject != mTextureMap.end()) + { + detachTexture(texture); + + if (texture != 0) + { + delete textureObject->second; + } + + mTextureMap.erase(textureObject); + } +} + +void Context::deleteFramebuffer(GLuint framebuffer) +{ + FramebufferMap::iterator framebufferObject = mFramebufferMap.find(framebuffer); + + if (framebufferObject != mFramebufferMap.end()) + { + detachFramebuffer(framebuffer); + + delete framebufferObject->second; + mFramebufferMap.erase(framebufferObject); + } +} + +void Context::deleteRenderbuffer(GLuint renderbuffer) +{ + RenderbufferMap::iterator renderbufferObject = mRenderbufferMap.find(renderbuffer); + + if (renderbufferObject != mRenderbufferMap.end()) + { + detachRenderbuffer(renderbuffer); + + delete renderbufferObject->second; + mRenderbufferMap.erase(renderbufferObject); + } +} + +void Context::bindArrayBuffer(unsigned int buffer) +{ + if (buffer != 0 && !getBuffer(buffer)) + { + mBufferMap[buffer] = new Buffer(); + } + + arrayBuffer = buffer; +} + +void Context::bindElementArrayBuffer(unsigned int buffer) +{ + if (buffer != 0 && !getBuffer(buffer)) + { + mBufferMap[buffer] = new Buffer(); + } + + elementArrayBuffer = buffer; +} + +void Context::bindTexture2D(GLuint texture) +{ + if (!getTexture(texture) || texture == 0) + { + if (texture != 0) + { + mTextureMap[texture] = new Texture2D(); + } + else // Special case: 0 refers to different initial textures based on the target + { + mTextureMap[0] = mTexture2DZero; + } + } + + texture2D = texture; + + samplerTexture[activeSampler] = texture; +} + +void Context::bindTextureCubeMap(GLuint texture) +{ + if (!getTexture(texture) || texture == 0) + { + if (texture != 0) + { + mTextureMap[texture] = new TextureCubeMap(); + } + else // Special case: 0 refers to different initial textures based on the target + { + mTextureMap[0] = mTextureCubeMapZero; + } + } + + textureCubeMap = texture; + + samplerTexture[activeSampler] = texture; +} + +void Context::bindFramebuffer(GLuint framebuffer) +{ + if (!getFramebuffer(framebuffer)) + { + mFramebufferMap[framebuffer] = new Framebuffer(); + } + + this->framebuffer = framebuffer; +} + +void Context::bindRenderbuffer(GLuint renderbuffer) +{ + if (renderbuffer != 0 && !getRenderbuffer(renderbuffer)) + { + mRenderbufferMap[renderbuffer] = new Renderbuffer(); + } + + this->renderbuffer = renderbuffer; +} + +void Context::useProgram(GLuint program) +{ + Program *programObject = getCurrentProgram(); + + if (programObject && programObject->isFlaggedForDeletion()) + { + deleteProgram(currentProgram); + } + + currentProgram = program; +} + +void Context::setFramebufferZero(Framebuffer *buffer) +{ + delete mFramebufferMap[0]; + mFramebufferMap[0] = buffer; +} + +void Context::setColorbufferZero(Colorbuffer *buffer) +{ + delete mColorbufferZero; + mColorbufferZero = buffer; +} + +void Context::setDepthbufferZero(Depthbuffer *buffer) +{ + delete mDepthbufferZero; + mDepthbufferZero = buffer; +} + +void Context::setStencilbufferZero(Stencilbuffer *buffer) +{ + delete mStencilbufferZero; + mStencilbufferZero = buffer; +} + +void Context::setRenderbuffer(Renderbuffer *buffer) +{ + delete mRenderbufferMap[renderbuffer]; + mRenderbufferMap[renderbuffer] = buffer; +} + +Buffer *Context::getBuffer(unsigned int handle) +{ + BufferMap::iterator buffer = mBufferMap.find(handle); + + if (buffer == mBufferMap.end()) + { + return NULL; + } + else + { + return buffer->second; + } +} + +Shader *Context::getShader(unsigned int handle) +{ + ShaderMap::iterator shader = mShaderMap.find(handle); + + if (shader == mShaderMap.end()) + { + return NULL; + } + else + { + return shader->second; + } +} + +Program *Context::getProgram(unsigned int handle) +{ + ProgramMap::iterator program = mProgramMap.find(handle); + + if (program == mProgramMap.end()) + { + return NULL; + } + else + { + return program->second; + } +} + +Texture *Context::getTexture(unsigned int handle) +{ + TextureMap::iterator texture = mTextureMap.find(handle); + + if (texture == mTextureMap.end()) + { + return NULL; + } + else + { + return texture->second; + } +} + +Framebuffer *Context::getFramebuffer(unsigned int handle) +{ + FramebufferMap::iterator framebuffer = mFramebufferMap.find(handle); + + if (framebuffer == mFramebufferMap.end()) + { + return NULL; + } + else + { + return framebuffer->second; + } +} + +Renderbuffer *Context::getRenderbuffer(unsigned int handle) +{ + RenderbufferMap::iterator renderbuffer = mRenderbufferMap.find(handle); + + if (renderbuffer == mRenderbufferMap.end()) + { + return NULL; + } + else + { + return renderbuffer->second; + } +} + +Colorbuffer *Context::getColorbuffer(GLuint handle) +{ + if (handle != 0) + { + Renderbuffer *renderbuffer = getRenderbuffer(handle); + + if(renderbuffer && renderbuffer->isColorbuffer()) + { + return static_cast(renderbuffer); + } + } + else // Special case: 0 refers to different initial render targets based on the attachment type + { + return mColorbufferZero; + } + + return NULL; +} + +Depthbuffer *Context::getDepthbuffer(GLuint handle) +{ + if (handle != 0) + { + Renderbuffer *renderbuffer = getRenderbuffer(handle); + + if(renderbuffer && renderbuffer->isDepthbuffer()) + { + return static_cast(renderbuffer); + } + } + else // Special case: 0 refers to different initial render targets based on the attachment type + { + return mDepthbufferZero; + } + + return NULL; +} + +Stencilbuffer *Context::getStencilbuffer(GLuint handle) +{ + if (handle != 0) + { + Renderbuffer *renderbuffer = getRenderbuffer(handle); + + if(renderbuffer && renderbuffer->isStencilbuffer()) + { + return static_cast(renderbuffer); + } + } + else + { + return mStencilbufferZero; + } + + return NULL; +} + +Buffer *Context::getArrayBuffer() +{ + return getBuffer(arrayBuffer); +} + +Buffer *Context::getElementArrayBuffer() +{ + return getBuffer(elementArrayBuffer); +} + +Program *Context::getCurrentProgram() +{ + return getProgram(currentProgram); +} + +Texture2D *Context::getTexture2D() +{ + if (texture2D == 0) // Special case: 0 refers to different initial textures based on the target + { + return mTexture2DZero; + } + + return (Texture2D*)getTexture(texture2D); +} + +TextureCubeMap *Context::getTextureCubeMap() +{ + if (textureCubeMap == 0) // Special case: 0 refers to different initial textures based on the target + { + return mTextureCubeMapZero; + } + + return (TextureCubeMap*)getTexture(textureCubeMap); +} + +Texture *Context::getSamplerTexture(unsigned int sampler) +{ + return getTexture(samplerTexture[sampler]); +} + +Framebuffer *Context::getFramebuffer() +{ + return getFramebuffer(framebuffer); +} + +// Applies the render target surface, depth stencil surface, viewport rectangle and +// scissor rectangle to the Direct3D 9 device +bool Context::applyRenderTarget(bool ignoreViewport) +{ + IDirect3DDevice9 *device = getDevice(); + Framebuffer *framebufferObject = getFramebuffer(); + + if (!framebufferObject || framebufferObject->completeness() != GL_FRAMEBUFFER_COMPLETE) + { + return false; + } + + IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); + IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil(); + + device->SetRenderTarget(0, renderTarget); + device->SetDepthStencilSurface(depthStencil); + + D3DVIEWPORT9 viewport; + D3DSURFACE_DESC desc; + renderTarget->GetDesc(&desc); + + if (ignoreViewport) + { + viewport.X = 0; + viewport.Y = 0; + viewport.Width = desc.Width; + viewport.Height = desc.Height; + viewport.MinZ = 0.0f; + viewport.MaxZ = 1.0f; + } + else + { + viewport.X = max(viewportX, 0); + viewport.Y = max(viewportY, 0); + viewport.Width = min(viewportWidth, (int)desc.Width - (int)viewport.X); + viewport.Height = min(viewportHeight, (int)desc.Height - (int)viewport.Y); + viewport.MinZ = clamp01(zNear); + viewport.MaxZ = clamp01(zFar); + } + + device->SetViewport(&viewport); + + if (scissorTest) + { + RECT rect = {scissorX, + scissorY, + scissorX + scissorWidth, + scissorY + scissorHeight}; + + device->SetScissorRect(&rect); + device->SetRenderState(D3DRS_SCISSORTESTENABLE, TRUE); + } + else + { + device->SetRenderState(D3DRS_SCISSORTESTENABLE, FALSE); + } + + if (currentProgram) + { + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + Program *programObject = getCurrentProgram(); + + GLuint halfPixelSize = programObject->getUniformLocation("gl_HalfPixelSize"); + GLfloat xy[2] = {1.0f / description.Width, 1.0f / description.Height}; + programObject->setUniform2fv(halfPixelSize, 1, (GLfloat*)&xy); + } + + return true; +} + +// Applies the fixed-function state (culling, depth test, alpha blending, stenciling, etc) to the Direct3D 9 device +void Context::applyState() +{ + IDirect3DDevice9 *device = getDevice(); + + if (cullFace) + { + device->SetRenderState(D3DRS_CULLMODE, es2dx::ConvertCullMode(cullMode, frontFace)); + } + else + { + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + } + + if (depthTest) + { + device->SetRenderState(D3DRS_ZENABLE, D3DZB_TRUE); + device->SetRenderState(D3DRS_ZFUNC, es2dx::ConvertComparison(depthFunc)); + } + else + { + device->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE); + } + + if (blend) + { + device->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE); + + if (sourceBlendRGB != GL_CONSTANT_ALPHA && sourceBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA && + destBlendRGB != GL_CONSTANT_ALPHA && destBlendRGB != GL_ONE_MINUS_CONSTANT_ALPHA) + { + device->SetRenderState(D3DRS_BLENDFACTOR, es2dx::ConvertColor(blendColor)); + } + else + { + device->SetRenderState(D3DRS_BLENDFACTOR, D3DCOLOR_RGBA(unorm<8>(blendColor.alpha), + unorm<8>(blendColor.alpha), + unorm<8>(blendColor.alpha), + unorm<8>(blendColor.alpha))); + } + + device->SetRenderState(D3DRS_SRCBLEND, es2dx::ConvertBlendFunc(sourceBlendRGB)); + device->SetRenderState(D3DRS_DESTBLEND, es2dx::ConvertBlendFunc(destBlendRGB)); + device->SetRenderState(D3DRS_BLENDOP, es2dx::ConvertBlendOp(blendEquationRGB)); + + if (sourceBlendRGB != sourceBlendAlpha || destBlendRGB != destBlendAlpha || blendEquationRGB != blendEquationAlpha) + { + device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, TRUE); + + device->SetRenderState(D3DRS_SRCBLENDALPHA, es2dx::ConvertBlendFunc(sourceBlendAlpha)); + device->SetRenderState(D3DRS_DESTBLENDALPHA, es2dx::ConvertBlendFunc(destBlendAlpha)); + device->SetRenderState(D3DRS_BLENDOPALPHA, es2dx::ConvertBlendOp(blendEquationAlpha)); + + } + else + { + device->SetRenderState(D3DRS_SEPARATEALPHABLENDENABLE, FALSE); + } + } + else + { + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + } + + if (stencilTest) + { + device->SetRenderState(D3DRS_STENCILENABLE, TRUE); + device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, TRUE); + + // FIXME: Unsupported by D3D9 + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILREF = D3DRS_STENCILREF; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILMASK = D3DRS_STENCILMASK; + const D3DRENDERSTATETYPE D3DRS_CCW_STENCILWRITEMASK = D3DRS_STENCILWRITEMASK; + ASSERT(stencilRef == stencilBackRef); + ASSERT(stencilMask == stencilBackMask); + ASSERT(stencilWritemask == stencilBackWritemask); + + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilWritemask); + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilFunc)); + + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilRef); // FIXME: Clamp to range + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilMask); + + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilFail)); + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilPassDepthFail)); + device->SetRenderState(frontFace == GL_CCW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilPassDepthPass)); + + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILWRITEMASK : D3DRS_CCW_STENCILWRITEMASK, stencilBackWritemask); + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFUNC : D3DRS_CCW_STENCILFUNC, es2dx::ConvertComparison(stencilBackFunc)); + + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILREF : D3DRS_CCW_STENCILREF, stencilBackRef); // FIXME: Clamp to range + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILMASK : D3DRS_CCW_STENCILMASK, stencilBackMask); + + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILFAIL : D3DRS_CCW_STENCILFAIL, es2dx::ConvertStencilOp(stencilBackFail)); + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILZFAIL : D3DRS_CCW_STENCILZFAIL, es2dx::ConvertStencilOp(stencilBackPassDepthFail)); + device->SetRenderState(frontFace == GL_CW ? D3DRS_STENCILPASS : D3DRS_CCW_STENCILPASS, es2dx::ConvertStencilOp(stencilBackPassDepthPass)); + } + else + { + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + device->SetRenderState(D3DRS_COLORWRITEENABLE, es2dx::ConvertColorMask(colorMaskRed, colorMaskGreen, colorMaskBlue, colorMaskAlpha)); + device->SetRenderState(D3DRS_ZWRITEENABLE, depthMask ? TRUE : FALSE); + + if (polygonOffsetFill) + { + UNIMPLEMENTED(); // FIXME + } + + if (sampleAlphaToCoverage) + { + UNIMPLEMENTED(); // FIXME + } + + if (sampleCoverage) + { + UNIMPLEMENTED(); // FIXME: Ignore when SAMPLE_BUFFERS is not one + } + + device->SetRenderState(D3DRS_DITHERENABLE, dither ? TRUE : FALSE); +} + +// Applies the vertex attribute and array bindings to the Direct3D 9 device +void Context::applyVertexBuffer(int count) +{ + IDirect3DDevice9 *device = getDevice(); + Program *programObject = getCurrentProgram(); + IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader(); + + D3DVERTEXELEMENT9 vertexElements[MAX_VERTEX_ATTRIBS + 1]; + D3DVERTEXELEMENT9 *currentElement = &vertexElements[0]; + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + if (vertexAttribute[attributeIndex].enabled && programObject->isActiveAttribute(attributeIndex)) + { + GLuint boundBuffer = vertexAttribute[attributeIndex].boundBuffer; + UINT stride = vertexAttribute[attributeIndex].stride; + GLint size = vertexAttribute[attributeIndex].size; + GLenum type = vertexAttribute[attributeIndex].type; + + if (stride == 0) + { + switch (type) + { + case GL_BYTE: stride = size * sizeof(GLbyte); break; + case GL_UNSIGNED_BYTE: stride = size * sizeof(GLubyte); break; + case GL_SHORT: stride = size * sizeof(GLshort); break; + case GL_UNSIGNED_SHORT: stride = size * sizeof(GLushort); break; + case GL_FIXED: stride = size * sizeof(GLfixed); break; + case GL_FLOAT: stride = size * sizeof(GLfloat); break; + default: UNREACHABLE(); + } + } + + currentElement->Stream = attributeIndex; + + if (boundBuffer) + { + currentElement->Offset = (unsigned short)vertexAttribute[attributeIndex].pointer; + } + else + { + currentElement->Offset = 0; + } + + switch (type) + { + case GL_BYTE: + if (vertexAttribute[attributeIndex].normalized) + { + UNIMPLEMENTED(); // FIXME + } + else + { + UNIMPLEMENTED(); // FIXME + } + break; + case GL_UNSIGNED_BYTE: + if (vertexAttribute[attributeIndex].normalized) + { + switch (size) + { + case 1: UNIMPLEMENTED(); // FIXME + case 2: UNIMPLEMENTED(); // FIXME + case 3: UNIMPLEMENTED(); // FIXME + case 4: currentElement->Type = D3DDECLTYPE_UBYTE4N; break; + default: UNREACHABLE(); + } + } + else + { + UNIMPLEMENTED(); // FIXME + } + break; + case GL_SHORT: + if (vertexAttribute[attributeIndex].normalized) + { + UNIMPLEMENTED(); // FIXME + } + else + { + UNIMPLEMENTED(); // FIXME + } + break; + case GL_UNSIGNED_SHORT: + if (vertexAttribute[attributeIndex].normalized) + { + UNIMPLEMENTED(); // FIXME + } + else + { + UNIMPLEMENTED(); // FIXME + } + break; + case GL_FIXED: + UNIMPLEMENTED(); // FIXME + break; + case GL_FLOAT: + switch (size) + { + case 1: currentElement->Type = D3DDECLTYPE_FLOAT1; break; + case 2: currentElement->Type = D3DDECLTYPE_FLOAT2; break; + case 3: currentElement->Type = D3DDECLTYPE_FLOAT3; break; + case 4: currentElement->Type = D3DDECLTYPE_FLOAT4; break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + + currentElement->Method = D3DDECLMETHOD_DEFAULT; + currentElement->Usage = D3DDECLUSAGE_TEXCOORD; + currentElement->UsageIndex = programObject->getInputMapping(attributeIndex); + + currentElement++; + + if (boundBuffer) + { + Buffer *buffer = getBuffer(boundBuffer); + IDirect3DVertexBuffer9 *streamData = buffer->getVertexBuffer(); + device->SetStreamSource(attributeIndex, streamData, 0, stride); + } + else if (vertexAttribute[attributeIndex].pointer) + { + IDirect3DVertexBuffer9 *vertexBuffer = NULL; + void *data; + + HRESULT result = device->CreateVertexBuffer(stride * count, 0, 0, D3DPOOL_MANAGED, &vertexBuffer, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + vertexBuffer->Lock(0, 0, &data, 0); + memcpy(data, vertexAttribute[attributeIndex].pointer, stride *count); + vertexBuffer->Unlock(); + + device->SetStreamSource(attributeIndex, vertexBuffer, 0, stride); + vertexBuffer->Release(); + } + else UNIMPLEMENTED(); // FIXME + } + else + { + device->SetStreamSource(attributeIndex, NULL, 0, 0); + } + } + + D3DVERTEXELEMENT9 end = D3DDECL_END(); + *currentElement = end; + + IDirect3DVertexDeclaration9 *vertexDeclaration = NULL; + HRESULT result = device->CreateVertexDeclaration(vertexElements, &vertexDeclaration); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + if (vertexDeclaration) + { + device->SetVertexDeclaration(vertexDeclaration); + vertexDeclaration->Release(); // Will only effectively be deleted when no longer in use + } +} + +// Applies the indices and element array bindings to the Direct3D 9 device +void Context::applyIndexBuffer(const void *indices, int length) +{ + IDirect3DDevice9 *device = getDevice(); + + if (elementArrayBuffer) + { + Buffer *buffer = getBuffer(elementArrayBuffer); + IDirect3DIndexBuffer9 *indexBuffer = buffer->getIndexBuffer(); + + device->SetIndices(indexBuffer); + startIndex = (unsigned int)(size_t)indices / 2; // FIXME: Assumes even value and 16-bit indices + } + else if (indices) + { + IDirect3DIndexBuffer9 *indexBuffer = NULL; + void *data; + + HRESULT result = device->CreateIndexBuffer(length, 0, D3DFMT_INDEX16, D3DPOOL_MANAGED, &indexBuffer, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + if (indexBuffer) + { + indexBuffer->Lock(0, length, &data, 0); + memcpy(data, indices, length); + indexBuffer->Unlock(); + + device->SetIndices(indexBuffer); + indexBuffer->Release(); // Will only effectively be deleted when no longer in use + } + + startIndex = 0; + } + else UNREACHABLE(); +} + +// Applies the shaders and shader constants to the Direct3D 9 device +void Context::applyShaders() +{ + IDirect3DDevice9 *device = getDevice(); + Program *programObject = getCurrentProgram(); + IDirect3DVertexShader9 *vertexShader = programObject->getVertexShader(); + IDirect3DPixelShader9 *pixelShader = programObject->getPixelShader(); + + device->SetVertexShader(vertexShader); + device->SetPixelShader(pixelShader); + + programObject->applyUniforms(); +} + +// Applies the textures and sampler states to the Direct3D 9 device +void Context::applyTextures() +{ + IDirect3DDevice9 *device = getDevice(); + Program *programObject = getCurrentProgram(); + + for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + { + unsigned int textureUnit = programObject->getSamplerMapping(sampler); + Texture *texture = getSamplerTexture(textureUnit); + + if (texture && texture->isComplete()) + { + GLenum wrapS = texture->getWrapS(); + GLenum wrapT = texture->getWrapT(); + GLenum minFilter = texture->getMinFilter(); + GLenum magFilter = texture->getMagFilter(); + + device->SetSamplerState(sampler, D3DSAMP_ADDRESSU, es2dx::ConvertTextureWrap(wrapS)); + device->SetSamplerState(sampler, D3DSAMP_ADDRESSV, es2dx::ConvertTextureWrap(wrapT)); + + device->SetSamplerState(sampler, D3DSAMP_MAGFILTER, es2dx::ConvertMagFilter(magFilter)); + D3DTEXTUREFILTERTYPE d3dMinFilter, d3dMipFilter; + es2dx::ConvertMinFilter(minFilter, &d3dMinFilter, &d3dMipFilter); + device->SetSamplerState(sampler, D3DSAMP_MINFILTER, d3dMinFilter); + device->SetSamplerState(sampler, D3DSAMP_MIPFILTER, d3dMipFilter); + + device->SetTexture(sampler, texture->getTexture()); + } + } +} + +void Context::readPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) +{ + Framebuffer *framebuffer = getFramebuffer(); + IDirect3DSurface9 *renderTarget = framebuffer->getRenderTarget(); + IDirect3DDevice9 *device = getDevice(); + + D3DSURFACE_DESC desc; + renderTarget->GetDesc(&desc); + + IDirect3DSurface9 *systemSurface; + HRESULT result = device->CreateOffscreenPlainSurface(desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &systemSurface, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + if (desc.MultiSampleType != D3DMULTISAMPLE_NONE) + { + UNIMPLEMENTED(); // FIXME: Requires resolve using StretchRect into non-multisampled render target + } + + result = device->GetRenderTargetData(renderTarget, systemSurface); + + if (result == D3DERR_DRIVERINTERNALERROR) + { + systemSurface->Release(); + + return error(GL_OUT_OF_MEMORY); + } + + if (FAILED(result)) + { + UNREACHABLE(); + systemSurface->Release(); + + return; // No sensible error to generate + } + + D3DLOCKED_RECT lock; + RECT rect = {max(x, 0), + max(y, 0), + min(x + width, (int)desc.Width), + min(y + height, (int)desc.Height)}; + + result = systemSurface->LockRect(&lock, &rect, D3DLOCK_READONLY); + + if (FAILED(result)) + { + UNREACHABLE(); + systemSurface->Release(); + + return; // No sensible error to generate + } + + unsigned char *source = (unsigned char*)lock.pBits; + unsigned char *dest = (unsigned char*)pixels; + + for (int j = 0; j < rect.bottom - rect.top; j++) + { + for (int i = 0; i < rect.right - rect.left; i++) + { + float r; + float g; + float b; + float a; + + switch (desc.Format) + { + case D3DFMT_R5G6B5: + { + unsigned short rgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch); + + a = 1.0f; + b = (rgb & 0x001F) * (1.0f / 0x001F); + g = (rgb & 0x07E0) * (1.0f / 0x07E0); + r = (rgb & 0xF800) * (1.0f / 0xF800); + } + break; + case D3DFMT_X1R5G5B5: + { + unsigned short xrgb = *(unsigned short*)(source + 2 * i + j * lock.Pitch); + + a = 1.0f; + b = (xrgb & 0x001F) * (1.0f / 0x001F); + g = (xrgb & 0x03E0) * (1.0f / 0x03E0); + r = (xrgb & 0x7C00) * (1.0f / 0x7C00); + } + break; + case D3DFMT_A1R5G5B5: + { + unsigned short argb = *(unsigned short*)(source + 2 * i + j * lock.Pitch); + + a = (argb & 0x8000) ? 1.0f : 0.0f; + b = (argb & 0x001F) * (1.0f / 0x001F); + g = (argb & 0x03E0) * (1.0f / 0x03E0); + r = (argb & 0x7C00) * (1.0f / 0x7C00); + } + break; + case D3DFMT_A8R8G8B8: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + + a = (argb & 0xFF000000) * (1.0f / 0xFF000000); + b = (argb & 0x000000FF) * (1.0f / 0x000000FF); + g = (argb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (argb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_X8R8G8B8: + { + unsigned int xrgb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + + a = 1.0f; + b = (xrgb & 0x000000FF) * (1.0f / 0x000000FF); + g = (xrgb & 0x0000FF00) * (1.0f / 0x0000FF00); + r = (xrgb & 0x00FF0000) * (1.0f / 0x00FF0000); + } + break; + case D3DFMT_A2R10G10B10: + { + unsigned int argb = *(unsigned int*)(source + 4 * i + j * lock.Pitch); + + a = (argb & 0xC0000000) * (1.0f / 0xC0000000); + b = (argb & 0x000003FF) * (1.0f / 0x000003FF); + g = (argb & 0x000FFC00) * (1.0f / 0x000FFC00); + r = (argb & 0x3FF00000) * (1.0f / 0x3FF00000); + } + break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + } + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + dest[4 * (i + j * width) + 0] = (unsigned char)(255 * r + 0.5f); + dest[4 * (i + j * width) + 1] = (unsigned char)(255 * g + 0.5f); + dest[4 * (i + j * width) + 2] = (unsigned char)(255 * b + 0.5f); + dest[4 * (i + j * width) + 3] = (unsigned char)(255 * a + 0.5f); + break; + default: UNREACHABLE(); + } + break; + case IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + } + + systemSurface->UnlockRect(); + + systemSurface->Release(); +} + +void Context::clear(GLbitfield mask) +{ + IDirect3DDevice9 *device = getDevice(); + DWORD flags = 0; + + if (mask & GL_COLOR_BUFFER_BIT) + { + mask &= ~GL_COLOR_BUFFER_BIT; + flags |= D3DCLEAR_TARGET; + } + + if (mask & GL_DEPTH_BUFFER_BIT) + { + mask &= ~GL_DEPTH_BUFFER_BIT; + if (depthMask) + { + flags |= D3DCLEAR_ZBUFFER; + } + } + + Framebuffer *framebufferObject = getFramebuffer(); + IDirect3DSurface9 *depthStencil = framebufferObject->getDepthStencil(); + + GLuint stencilUnmasked = 0x0; + + if ((mask & GL_STENCIL_BUFFER_BIT) && depthStencil) + { + D3DSURFACE_DESC desc; + depthStencil->GetDesc(&desc); + + mask &= ~GL_STENCIL_BUFFER_BIT; + unsigned int stencilSize = es2dx::GetStencilSize(desc.Format); + stencilUnmasked = (0x1 << stencilSize) - 1; + + if (stencilUnmasked != 0x0) + { + flags |= D3DCLEAR_STENCIL; + } + } + + if (mask != 0) + { + return error(GL_INVALID_VALUE); + } + + applyRenderTarget(true); // Clips the clear to the scissor rectangle but not the viewport + + D3DCOLOR color = D3DCOLOR_ARGB(unorm<8>(colorClearValue.alpha), unorm<8>(colorClearValue.red), unorm<8>(colorClearValue.green), unorm<8>(colorClearValue.blue)); + float depth = clamp01(depthClearValue); + int stencil = stencilClearValue & 0x000000FF; + + IDirect3DSurface9 *renderTarget = framebufferObject->getRenderTarget(); + + D3DSURFACE_DESC desc; + renderTarget->GetDesc(&desc); + + bool alphaUnmasked = (es2dx::GetAlphaSize(desc.Format) == 0) || colorMaskAlpha; + + const bool needMaskedStencilClear = (flags & D3DCLEAR_STENCIL) && + (stencilWritemask & stencilUnmasked) != stencilUnmasked; + const bool needMaskedColorClear = (flags & D3DCLEAR_TARGET) && + !(colorMaskRed && colorMaskGreen && + colorMaskBlue && alphaUnmasked); + + if (needMaskedColorClear || needMaskedStencilClear) + { + device->SetRenderState(D3DRS_ZWRITEENABLE, FALSE); + device->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + device->SetRenderState(D3DRS_ZENABLE, FALSE); + device->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); + device->SetRenderState(D3DRS_FILLMODE, D3DFILL_SOLID); + device->SetRenderState(D3DRS_ALPHATESTENABLE, FALSE); + device->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); + device->SetRenderState(D3DRS_CLIPPLANEENABLE, 0); + + if (flags & D3DCLEAR_TARGET) + { + device->SetRenderState(D3DRS_COLORWRITEENABLE, (colorMaskRed ? D3DCOLORWRITEENABLE_RED : 0) | + (colorMaskGreen ? D3DCOLORWRITEENABLE_GREEN : 0) | + (colorMaskBlue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (colorMaskAlpha ? D3DCOLORWRITEENABLE_ALPHA : 0)); + } + else + { + device->SetRenderState(D3DRS_COLORWRITEENABLE, 0); + } + + if (stencilUnmasked != 0x0 && (flags & D3DCLEAR_STENCIL)) + { + device->SetRenderState(D3DRS_STENCILENABLE, TRUE); + device->SetRenderState(D3DRS_TWOSIDEDSTENCILMODE, FALSE); + device->SetRenderState(D3DRS_STENCILFUNC, D3DCMP_ALWAYS); + device->SetRenderState(D3DRS_STENCILREF, stencil); + device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWritemask); + device->SetRenderState(D3DRS_STENCILFAIL, D3DSTENCILOP_REPLACE); + device->SetRenderState(D3DRS_STENCILZFAIL, D3DSTENCILOP_REPLACE); + device->SetRenderState(D3DRS_STENCILPASS, D3DSTENCILOP_REPLACE); + } + else + { + device->SetRenderState(D3DRS_STENCILENABLE, FALSE); + } + + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + device->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE); + + struct Vertex + { + float x, y, z, w; + D3DCOLOR diffuse; + }; + + Vertex quad[4]; + quad[0].x = 0.0f; + quad[0].y = (float)desc.Height; + quad[0].z = 0.0f; + quad[0].w = 1.0f; + quad[0].diffuse = color; + + quad[1].x = (float)desc.Width; + quad[1].y = (float)desc.Height; + quad[1].z = 0.0f; + quad[1].w = 1.0f; + quad[1].diffuse = color; + + quad[2].x = 0.0f; + quad[2].y = 0.0f; + quad[2].z = 0.0f; + quad[2].w = 1.0f; + quad[2].diffuse = color; + + quad[3].x = (float)desc.Width; + quad[3].y = 0.0f; + quad[3].z = 0.0f; + quad[3].w = 1.0f; + quad[3].diffuse = color; + + device->BeginScene(); + device->DrawPrimitiveUP(D3DPT_TRIANGLESTRIP, 2, quad, sizeof(Vertex)); + device->EndScene(); + + if (flags & D3DCLEAR_ZBUFFER) + { + device->SetRenderState(D3DRS_ZENABLE, TRUE); + device->SetRenderState(D3DRS_ZWRITEENABLE, TRUE); + device->Clear(0, NULL, D3DCLEAR_ZBUFFER, color, depth, stencil); + } + } + else + { + device->Clear(0, NULL, flags, color, depth, stencil); + } +} + +void Context::drawArrays(GLenum mode, GLint first, GLsizei count) +{ + if (!currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + IDirect3DDevice9 *device = getDevice(); + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + applyState(); + applyVertexBuffer(count); + applyShaders(); + applyTextures(); + + device->BeginScene(); + device->DrawPrimitive(primitiveType, first, primitiveCount); + device->EndScene(); +} + +void Context::drawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) +{ + if (!currentProgram) + { + return error(GL_INVALID_OPERATION); + } + + if (!indices && !elementArrayBuffer) + { + return error(GL_INVALID_OPERATION); + } + + IDirect3DDevice9 *device = getDevice(); + D3DPRIMITIVETYPE primitiveType; + int primitiveCount; + + if(!es2dx::ConvertPrimitiveType(mode, count, &primitiveType, &primitiveCount)) + return error(GL_INVALID_ENUM); + + if (primitiveCount <= 0) + { + return; + } + + if (!applyRenderTarget(false)) + { + return error(GL_INVALID_FRAMEBUFFER_OPERATION); + } + + applyState(); + applyVertexBuffer(count); + applyIndexBuffer(indices, count * sizeof(unsigned short)); + applyShaders(); + applyTextures(); + + device->BeginScene(); + device->DrawIndexedPrimitive(primitiveType, 0, 0, count, startIndex, primitiveCount); + device->EndScene(); +} + +void Context::finish() +{ + IDirect3DDevice9 *device = getDevice(); + IDirect3DQuery9 *occlusionQuery = NULL; + + HRESULT result = device->CreateQuery(D3DQUERYTYPE_OCCLUSION, &occlusionQuery); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + if (occlusionQuery) + { + occlusionQuery->Issue(D3DISSUE_BEGIN); + + // Render something outside the render target + device->SetPixelShader(NULL); + device->SetVertexShader(NULL); + device->SetFVF(D3DFVF_XYZRHW); + float data[4] = {-1.0f, -1.0f, -1.0f, 1.0f}; + device->BeginScene(); + device->DrawPrimitiveUP(D3DPT_POINTLIST, 1, data, sizeof(data)); + device->EndScene(); + + occlusionQuery->Issue(D3DISSUE_END); + + while (occlusionQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + } + + occlusionQuery->Release(); + } +} + +void Context::flush() +{ + IDirect3DDevice9 *device = getDevice(); + IDirect3DQuery9 *eventQuery = NULL; + + HRESULT result = device->CreateQuery(D3DQUERYTYPE_EVENT, &eventQuery); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(result)); + + if (eventQuery) + { + eventQuery->Issue(D3DISSUE_END); + + while (eventQuery->GetData(NULL, 0, D3DGETDATA_FLUSH) == S_FALSE) + { + // Keep polling, but allow other threads to do something useful first + Sleep(0); + } + + eventQuery->Release(); + } +} + +void Context::recordInvalidEnum() +{ + mInvalidEnum = true; +} + +void Context::recordInvalidValue() +{ + mInvalidValue = true; +} + +void Context::recordInvalidOperation() +{ + mInvalidOperation = true; +} + +void Context::recordOutOfMemory() +{ + mOutOfMemory = true; +} + +void Context::recordInvalidFramebufferOperation() +{ + mInvalidFramebufferOperation = true; +} + +// Get one of the recorded errors and clear its flag, if any. +// [OpenGL ES 2.0.24] section 2.5 page 13. +GLenum Context::getError() +{ + if (mInvalidEnum) + { + mInvalidEnum = false; + + return GL_INVALID_ENUM; + } + + if (mInvalidValue) + { + mInvalidValue = false; + + return GL_INVALID_VALUE; + } + + if (mInvalidOperation) + { + mInvalidOperation = false; + + return GL_INVALID_OPERATION; + } + + if (mOutOfMemory) + { + mOutOfMemory = false; + + return GL_OUT_OF_MEMORY; + } + + if (mInvalidFramebufferOperation) + { + mInvalidFramebufferOperation = false; + + return GL_INVALID_FRAMEBUFFER_OPERATION; + } + + return GL_NO_ERROR; +} + +void Context::detachBuffer(GLuint buffer) +{ + // [OpenGL ES 2.0.24] section 2.9 page 22: + // If a buffer object is deleted while it is bound, all bindings to that object in the current context + // (i.e. in the thread that called Delete-Buffers) are reset to zero. + + if (arrayBuffer == buffer) + { + arrayBuffer = 0; + } + + if (elementArrayBuffer == buffer) + { + elementArrayBuffer = 0; + } + + for (int attribute = 0; attribute < MAX_VERTEX_ATTRIBS; attribute++) + { + if (vertexAttribute[attribute].boundBuffer == buffer) + { + vertexAttribute[attribute].boundBuffer = 0; + } + } +} + +void Context::detachTexture(GLuint texture) +{ + // [OpenGL ES 2.0.24] section 3.8 page 84: + // If a texture object is deleted, it is as if all texture units which are bound to that texture object are + // rebound to texture object zero + + for (int sampler = 0; sampler < MAX_TEXTURE_IMAGE_UNITS; sampler++) + { + if (samplerTexture[sampler] == texture) + { + samplerTexture[sampler] = 0; + } + } + + // [OpenGL ES 2.0.24] section 4.4 page 112: + // If a texture object is deleted while its image is attached to the currently bound framebuffer, then it is + // as if FramebufferTexture2D had been called, with a texture of 0, for each attachment point to which this + // image was attached in the currently bound framebuffer. + + Framebuffer *framebuffer = getFramebuffer(); + + if (framebuffer) + { + framebuffer->detachTexture(texture); + } +} + +void Context::detachFramebuffer(GLuint framebuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 107: + // If a framebuffer that is currently bound to the target FRAMEBUFFER is deleted, it is as though + // BindFramebuffer had been executed with the target of FRAMEBUFFER and framebuffer of zero. + + if (this->framebuffer == framebuffer) + { + bindFramebuffer(0); + } +} + +void Context::detachRenderbuffer(GLuint renderbuffer) +{ + // [OpenGL ES 2.0.24] section 4.4 page 109: + // If a renderbuffer that is currently bound to RENDERBUFFER is deleted, it is as though BindRenderbuffer + // had been executed with the target RENDERBUFFER and name of zero. + + if (this->renderbuffer == renderbuffer) + { + bindRenderbuffer(0); + } + + // [OpenGL ES 2.0.24] section 4.4 page 111: + // If a renderbuffer object is deleted while its image is attached to the currently bound framebuffer, + // then it is as if FramebufferRenderbuffer had been called, with a renderbuffer of 0, for each attachment + // point to which this image was attached in the currently bound framebuffer. + + Framebuffer *framebuffer = getFramebuffer(); + + if (framebuffer) + { + framebuffer->detachRenderbuffer(renderbuffer); + } +} +} + +extern "C" +{ +gl::Context *glCreateContext(const egl::Config *config) +{ + return new gl::Context(config); +} + +void glDestroyContext(gl::Context *context) +{ + delete context; + + if (context == gl::getContext()) + { + gl::makeCurrent(NULL, NULL, NULL); + } +} + +void glMakeCurrent(gl::Context *context, egl::Display *display, egl::Surface *surface) +{ + gl::makeCurrent(context, display, surface); +} + +gl::Context *glGetCurrentContext() +{ + return gl::getContext(); +} +} diff --git a/libGLESv2/Framebuffer.cpp b/libGLESv2/Framebuffer.cpp new file mode 100644 index 000000000..f242abe47 --- /dev/null +++ b/libGLESv2/Framebuffer.cpp @@ -0,0 +1,233 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Framebuffer.cpp: Implements the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#include "Framebuffer.h" + +#include "Renderbuffer.h" +#include "Texture.h" +#include "main.h" + +namespace gl +{ +Framebuffer::Framebuffer() +{ + mColorbufferType = GL_NONE; + mColorbufferHandle = 0; + + mDepthbufferType = GL_NONE; + mDepthbufferHandle = 0; + + mStencilbufferType = GL_NONE; + mStencilbufferHandle = 0; +} + +Framebuffer::~Framebuffer() +{ +} + +void Framebuffer::setColorbuffer(GLenum type, GLuint colorbuffer) +{ + mColorbufferType = type; + mColorbufferHandle = colorbuffer; +} + +void Framebuffer::setDepthbuffer(GLenum type, GLuint depthbuffer) +{ + mDepthbufferType = type; + mDepthbufferHandle = depthbuffer; +} + +void Framebuffer::setStencilbuffer(GLenum type, GLuint stencilbuffer) +{ + mStencilbufferType = type; + mStencilbufferHandle = stencilbuffer; +} + +void Framebuffer::detachTexture(GLuint texture) +{ + if (mColorbufferHandle == texture && mColorbufferType == GL_TEXTURE) + { + mColorbufferType = GL_NONE; + mColorbufferHandle = 0; + } +} + +void Framebuffer::detachRenderbuffer(GLuint renderbuffer) +{ + if (mColorbufferHandle == renderbuffer && mColorbufferType == GL_RENDERBUFFER) + { + mColorbufferType = GL_NONE; + mColorbufferHandle = 0; + } + + if (mDepthbufferHandle == renderbuffer && mDepthbufferType == GL_RENDERBUFFER) + { + mDepthbufferType = GL_NONE; + mDepthbufferHandle = 0; + } + + if (mStencilbufferHandle == renderbuffer && mStencilbufferType == GL_RENDERBUFFER) + { + mStencilbufferType = GL_NONE; + mStencilbufferHandle = 0; + } +} + +IDirect3DSurface9 *Framebuffer::getRenderTarget() +{ + Renderbuffer *colorbuffer = getColorbuffer(); + + if (colorbuffer) + { + return colorbuffer->getRenderTarget(); + } + + return NULL; +} + +IDirect3DSurface9 *Framebuffer::getDepthStencil() +{ + gl::Context *context = gl::getContext(); + Depthbuffer *depthbuffer = context->getDepthbuffer(mDepthbufferHandle); + + if (depthbuffer) + { + return depthbuffer->getDepthStencil(); + } + + return NULL; +} + +Colorbuffer *Framebuffer::getColorbuffer() +{ + gl::Context *context = gl::getContext(); + Colorbuffer *colorbuffer = NULL; + + if (mColorbufferType == GL_RENDERBUFFER) + { + colorbuffer = context->getColorbuffer(mColorbufferHandle); + } + else if (mColorbufferType == GL_TEXTURE) + { + colorbuffer = context->getTexture(mColorbufferHandle); + } + else UNREACHABLE(); + + if (colorbuffer && colorbuffer->isColorbuffer()) + { + return colorbuffer; + } + + return NULL; +} + +Depthbuffer *Framebuffer::getDepthbuffer() +{ + gl::Context *context = gl::getContext(); + Depthbuffer *depthbuffer = context->getDepthbuffer(mDepthbufferHandle); + + if (depthbuffer && depthbuffer->isDepthbuffer()) + { + return depthbuffer; + } + + return NULL; +} + +Stencilbuffer *Framebuffer::getStencilbuffer() +{ + gl::Context *context = gl::getContext(); + Stencilbuffer *stencilbuffer = context->getStencilbuffer(mStencilbufferHandle); + + if (stencilbuffer && stencilbuffer->isStencilbuffer()) + { + return stencilbuffer; + } + + return NULL; +} + +GLenum Framebuffer::completeness() +{ + gl::Context *context = gl::getContext(); + + int width = 0; + int height = 0; + + if (mColorbufferType != GL_NONE) + { + Colorbuffer *colorbuffer = getColorbuffer(); + + if (!colorbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (colorbuffer->getWidth() == 0 || colorbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + width = colorbuffer->getWidth(); + height = colorbuffer->getHeight(); + } + + if (mDepthbufferType != GL_NONE) + { + Depthbuffer *depthbuffer = context->getDepthbuffer(mDepthbufferHandle); + + if (!depthbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (depthbuffer->getWidth() == 0 || depthbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (width == 0) + { + width = depthbuffer->getWidth(); + height = depthbuffer->getHeight(); + } + else if (width != depthbuffer->getWidth() || height != depthbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + } + + if (mStencilbufferType != GL_NONE) + { + Stencilbuffer *stencilbuffer = context->getStencilbuffer(mStencilbufferHandle); + + if (!stencilbuffer) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (stencilbuffer->getWidth() == 0 || stencilbuffer->getHeight() == 0) + { + return GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT; + } + + if (width == 0) + { + width = stencilbuffer->getWidth(); + height = stencilbuffer->getHeight(); + } + else if (width != stencilbuffer->getWidth() || height != stencilbuffer->getHeight()) + { + return GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS; + } + } + + return GL_FRAMEBUFFER_COMPLETE; +} +} diff --git a/libGLESv2/Framebuffer.h b/libGLESv2/Framebuffer.h new file mode 100644 index 000000000..fd90ae1a9 --- /dev/null +++ b/libGLESv2/Framebuffer.h @@ -0,0 +1,62 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Framebuffer.h: Defines the gl::Framebuffer class. Implements GL framebuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4 page 105. + +#ifndef LIBGLESV2_FRAMEBUFFER_H_ +#define LIBGLESV2_FRAMEBUFFER_H_ + +#define GL_APICALL +#include +#include + +#include "angleutils.h" + +namespace gl +{ +class Colorbuffer; +class Depthbuffer; +class Stencilbuffer; + +class Framebuffer +{ + public: + Framebuffer(); + + ~Framebuffer(); + + void setColorbuffer(GLenum type, GLuint colorbuffer); + void setDepthbuffer(GLenum type, GLuint depthbuffer); + void setStencilbuffer(GLenum type, GLuint stencilbuffer); + + void detachTexture(GLuint texture); + void detachRenderbuffer(GLuint renderbuffer); + + IDirect3DSurface9 *getRenderTarget(); + IDirect3DSurface9 *getDepthStencil(); + + Colorbuffer *getColorbuffer(); + Depthbuffer *getDepthbuffer(); + Stencilbuffer *getStencilbuffer(); + + GLenum completeness(); + + private: + DISALLOW_COPY_AND_ASSIGN(Framebuffer); + + GLuint mColorbufferHandle; + GLenum mColorbufferType; + + GLuint mDepthbufferHandle; + GLenum mDepthbufferType; + + GLuint mStencilbufferHandle; + GLenum mStencilbufferType; +}; +} + +#endif // LIBGLESV2_FRAMEBUFFER_H_ diff --git a/libGLESv2/Program.cpp b/libGLESv2/Program.cpp new file mode 100644 index 000000000..0e73852ca --- /dev/null +++ b/libGLESv2/Program.cpp @@ -0,0 +1,942 @@ +// +// Copyright (c) 2002-2010 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. +// + +// 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 "Program.h" + +#include "main.h" +#include "Shader.h" +#include "debug.h" + +namespace gl +{ +Uniform::Uniform(UniformType type, const std::string &name, unsigned int bytes) : type(type), name(name), bytes(bytes) +{ + this->data = new unsigned char[bytes]; + memset(this->data, 0, bytes); +} + +Uniform::~Uniform() +{ + delete[] data; +} + +Program::Program() +{ + mFragmentShader = NULL; + mVertexShader = NULL; + + mPixelExecutable = NULL; + mVertexExecutable = NULL; + mConstantTablePS = NULL; + mConstantTableVS = NULL; + + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + mAttributeName[index] = NULL; + } + + unlink(); + + mDeleteStatus = false; +} + +Program::~Program() +{ + unlink(true); +} + +bool Program::attachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader) + { + return false; + } + + mVertexShader = (VertexShader*)shader; + mVertexShader->attach(); + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader) + { + return false; + } + + mFragmentShader = (FragmentShader*)shader; + mFragmentShader->attach(); + } + else UNREACHABLE(); + + return true; +} + +bool Program::detachShader(Shader *shader) +{ + if (shader->getType() == GL_VERTEX_SHADER) + { + if (mVertexShader != shader) + { + return false; + } + + mVertexShader->detach(); + mVertexShader = NULL; + } + else if (shader->getType() == GL_FRAGMENT_SHADER) + { + if (mFragmentShader != shader) + { + return false; + } + + mFragmentShader->detach(); + mFragmentShader = NULL; + } + else UNREACHABLE(); + + unlink(); + + return true; +} + +IDirect3DPixelShader9 *Program::getPixelShader() +{ + return mPixelExecutable; +} + +IDirect3DVertexShader9 *Program::getVertexShader() +{ + return mVertexExecutable; +} + +void Program::bindAttributeLocation(GLuint index, const char *name) +{ + if (index < MAX_VERTEX_ATTRIBS) + { + delete[] mAttributeName[index]; + mAttributeName[index] = new char[strlen(name) + 1]; + strcpy(mAttributeName[index], name); + } +} + +GLuint Program::getAttributeLocation(const char *name) +{ + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mAttributeName[index] && strcmp(mAttributeName[index], name) == 0) + { + return index; + } + } + + return -1; +} + +bool Program::isActiveAttribute(int attributeIndex) +{ + if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS) + { + return mInputMapping[attributeIndex] != -1; + } + + return false; +} + +int Program::getInputMapping(int attributeIndex) +{ + if (attributeIndex >= 0 && attributeIndex < MAX_VERTEX_ATTRIBS) + { + return mInputMapping[attributeIndex]; + } + + return -1; +} + +// Returns the index of the texture unit corresponding to a Direct3D 9 sampler +// index referenced in the compiled HLSL shader +GLint Program::getSamplerMapping(unsigned int samplerIndex) +{ + if (samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + return mSamplerMapping[samplerIndex]; + } + + return 0; +} + +GLint Program::getUniformLocation(const char *name) +{ + for (unsigned int location = 0; location < mUniforms.size(); location++) + { + if (mUniforms[location]->name == name) + { + return location; + } + } + + return -1; +} + +bool Program::setUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_1FV || mUniforms[location]->bytes < sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, v, sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_2FV || mUniforms[location]->bytes < 2 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, v, 2 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_3FV || mUniforms[location]->bytes < 3 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, v, 3 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_4FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, v, 4 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_MATRIX_2FV || mUniforms[location]->bytes < 4 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, value, 4 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_MATRIX_3FV || mUniforms[location]->bytes < 9 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, value, 9 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_MATRIX_4FV || mUniforms[location]->bytes < 16 * sizeof(GLfloat) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, value, 16 * sizeof(GLfloat) * count); + + return true; +} + +bool Program::setUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + if (location < 0 || location >= (int)mUniforms.size()) + { + return false; + } + + if (mUniforms[location]->type != UNIFORM_1IV || mUniforms[location]->bytes < sizeof(GLint) * count) + { + return false; + } + + memcpy(mUniforms[location]->data, v, sizeof(GLint) * count); + + return true; +} + +// Applies all the uniforms set for this program object to the Direct3D 9 device +void Program::applyUniforms() +{ + for (unsigned int location = 0; location < mUniforms.size(); location++) + { + int bytes = mUniforms[location]->bytes; + GLfloat *f = (GLfloat*)mUniforms[location]->data; + GLint *i = (GLint*)mUniforms[location]->data; + + switch (mUniforms[location]->type) + { + case UNIFORM_1FV: applyUniform1fv(location, bytes / sizeof(GLfloat), f); break; + case UNIFORM_2FV: applyUniform2fv(location, bytes / 2 / sizeof(GLfloat), f); break; + case UNIFORM_3FV: applyUniform3fv(location, bytes / 3 / sizeof(GLfloat), f); break; + case UNIFORM_4FV: applyUniform4fv(location, bytes / 4 / sizeof(GLfloat), f); break; + case UNIFORM_MATRIX_2FV: applyUniformMatrix2fv(location, bytes / 4 / sizeof(GLfloat), f); break; + case UNIFORM_MATRIX_3FV: applyUniformMatrix3fv(location, bytes / 9 / sizeof(GLfloat), f); break; + case UNIFORM_MATRIX_4FV: applyUniformMatrix4fv(location, bytes / 16 / sizeof(GLfloat), f); break; + case UNIFORM_1IV: applyUniform1iv(location, bytes / sizeof(GLint), i); break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + } + } +} + +// Compiles the HLSL code of the attached shaders into executable binaries +ID3DXBuffer *Program::compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable) +{ + if (!hlsl) + { + return NULL; + } + + ID3DXBuffer *binary = NULL; + ID3DXBuffer *errorMessage = NULL; + + HRESULT result = D3DXCompileShader(hlsl, (UINT)strlen(hlsl), NULL, 0, "main", profile, D3DXSHADER_USE_LEGACY_D3DX9_31_DLL, &binary, &errorMessage, constantTable); + + if (SUCCEEDED(result)) + { + return binary; + } + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (ID3DXBuffer*)NULL); + } + + if (errorMessage) + { + const char *message = (const char*)errorMessage->GetBufferPointer(); + trace(hlsl); + trace(message); + } + + return NULL; +} + +// Links the HLSL code of the vertex and pixel shader by matching up their varyings, +// compiling them into binaries, determining the attribute mappings, and collecting +// a list of uniforms +void Program::link() +{ + if (mLinked) + { + return; + } + + unlink(); + + if (!mFragmentShader || !mFragmentShader->isCompiled()) + { + return; + } + + if (!mVertexShader || !mVertexShader->isCompiled()) + { + return; + } + + const char *pixelHLSL = mFragmentShader->linkHLSL(); + const char *vertexHLSL = mVertexShader->linkHLSL(pixelHLSL); + ID3DXBuffer *vertexBinary = compileToBinary(vertexHLSL, "vs_2_0", &mConstantTableVS); + ID3DXBuffer *pixelBinary = compileToBinary(pixelHLSL, "ps_2_0", &mConstantTablePS); + + if (vertexBinary && pixelBinary) + { + IDirect3DDevice9 *device = getDevice(); + HRESULT vertexResult = device->CreateVertexShader((DWORD*)vertexBinary->GetBufferPointer(), &mVertexExecutable); + HRESULT pixelResult = device->CreatePixelShader((DWORD*)pixelBinary->GetBufferPointer(), &mPixelExecutable); + + if (vertexResult == D3DERR_OUTOFVIDEOMEMORY || vertexResult == E_OUTOFMEMORY || pixelResult == D3DERR_OUTOFVIDEOMEMORY || pixelResult == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY); + } + + ASSERT(SUCCEEDED(vertexResult) && SUCCEEDED(pixelResult)); + + vertexBinary->Release(); + pixelBinary->Release(); + vertexBinary = NULL; + pixelBinary = NULL; + + if (mVertexExecutable && mPixelExecutable) + { + if (!linkAttributes()) + { + return; + } + + D3DXCONSTANTTABLE_DESC constantTableDescription; + D3DXCONSTANT_DESC constantDescription; + UINT descriptionCount = 1; + + mConstantTablePS->GetDesc(&constantTableDescription); + + for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++) + { + D3DXHANDLE constantHandle = mConstantTablePS->GetConstant(0, constantIndex); + mConstantTablePS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount); + + UniformArray::iterator uniform = mUniforms.begin(); + + while (uniform != mUniforms.end()) + { + if ((*uniform)->name == constantDescription.Name) + { + UNREACHABLE(); // Redefinition; detect at compile + } + + uniform++; + } + + if (uniform == mUniforms.end()) + { + defineUniform(constantDescription); + } + } + + mConstantTableVS->GetDesc(&constantTableDescription); + + for (unsigned int constantIndex = 0; constantIndex < constantTableDescription.Constants; constantIndex++) + { + D3DXHANDLE constantHandle = mConstantTableVS->GetConstant(0, constantIndex); + mConstantTableVS->GetConstantDesc(constantHandle, &constantDescription, &descriptionCount); + + UniformArray::iterator uniform = mUniforms.begin(); + + while (uniform != mUniforms.end()) + { + if ((*uniform)->name == constantDescription.Name) + { + UNIMPLEMENTED(); // FIXME: Verify it's the same type as the fragment uniform + + if (true) + { + break; + } + else + { + return; + } + } + + uniform++; + } + + if (uniform == mUniforms.end()) + { + defineUniform(constantDescription); + } + } + + mLinked = true; + + return; + } + } +} + +// Determines the mapping between GL attributes and Direct3D 9 vertex stream usage indices +bool Program::linkAttributes() +{ + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + const char *name = mVertexShader->getAttributeName(attributeIndex); + + if (name) + { + GLuint location = getAttributeLocation(name); + + if (location == -1) // Not set by glBindAttribLocation + { + int availableIndex = 0; + + while (availableIndex < MAX_VERTEX_ATTRIBS && mAttributeName[availableIndex] && mVertexShader->isActiveAttribute(mAttributeName[availableIndex])) + { + availableIndex++; + } + + if (availableIndex == MAX_VERTEX_ATTRIBS) + { + return false; // Fail to link + } + + delete[] mAttributeName[availableIndex]; + mAttributeName[availableIndex] = new char[strlen(name) + 1]; // FIXME: Check allocation + strcpy(mAttributeName[availableIndex], name); + } + } + } + + for (int attributeIndex = 0; attributeIndex < MAX_VERTEX_ATTRIBS; attributeIndex++) + { + mInputMapping[attributeIndex] = mVertexShader->getInputMapping(mAttributeName[attributeIndex]); + } + + return true; +} + +// Adds the description of a constant found in the binary shader to the list of uniforms +void Program::defineUniform(const D3DXCONSTANT_DESC &constantDescription) +{ + if (constantDescription.Rows == 1) // Vectors and scalars + { + switch (constantDescription.Type) + { + case D3DXPT_SAMPLER2D: + case D3DXPT_SAMPLERCUBE: + case D3DXPT_BOOL: + switch (constantDescription.Columns) + { + case 1: + mUniforms.push_back(new Uniform(UNIFORM_1IV, constantDescription.Name, 1 * sizeof(GLint) * constantDescription.Elements)); + break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + } + break; + case D3DXPT_FLOAT: + switch (constantDescription.Columns) + { + case 1: + mUniforms.push_back(new Uniform(UNIFORM_1FV, constantDescription.Name, 1 * sizeof(GLfloat) * constantDescription.Elements)); + break; + case 2: + mUniforms.push_back(new Uniform(UNIFORM_2FV, constantDescription.Name, 2 * sizeof(GLfloat) * constantDescription.Elements)); + break; + case 3: + mUniforms.push_back(new Uniform(UNIFORM_3FV, constantDescription.Name, 3 * sizeof(GLfloat) * constantDescription.Elements)); + break; + case 4: + mUniforms.push_back(new Uniform(UNIFORM_4FV, constantDescription.Name, 4 * sizeof(GLfloat) * constantDescription.Elements)); + break; + default: UNREACHABLE(); + } + break; + default: + UNIMPLEMENTED(); // FIXME + UNREACHABLE(); + } + } + else if (constantDescription.Rows == constantDescription.Columns) // Square matrices + { + switch (constantDescription.Type) + { + case D3DXPT_FLOAT: + switch (constantDescription.Rows) + { + case 2: + mUniforms.push_back(new Uniform(UNIFORM_MATRIX_2FV, constantDescription.Name, 2 * 2 * sizeof(GLfloat) * constantDescription.Elements)); + break; + case 3: + mUniforms.push_back(new Uniform(UNIFORM_MATRIX_3FV, constantDescription.Name, 3 * 3 * sizeof(GLfloat) * constantDescription.Elements)); + break; + case 4: + mUniforms.push_back(new Uniform(UNIFORM_MATRIX_4FV, constantDescription.Name, 4 * 4 * sizeof(GLfloat) * constantDescription.Elements)); + break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + } + else UNREACHABLE(); +} + +bool Program::applyUniform1fv(GLint location, GLsizei count, const GLfloat *v) +{ + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetFloatArray(device, constantPS, v, count); + } + + if (constantVS) + { + mConstantTableVS->SetFloatArray(device, constantVS, v, count); + } + + return true; +} + +bool Program::applyUniform2fv(GLint location, GLsizei count, const GLfloat *v) +{ + D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + + for (int i = 0; i < count; i++) + { + vector[i] = D3DXVECTOR4(v[0], v[1], 0, 0); + + v += 2; + } + + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetVectorArray(device, constantPS, vector, count); + } + + if (constantVS) + { + mConstantTableVS->SetVectorArray(device, constantVS, vector, count); + } + + delete[] vector; + + return true; +} + +bool Program::applyUniform3fv(GLint location, GLsizei count, const GLfloat *v) +{ + D3DXVECTOR4 *vector = new D3DXVECTOR4[count]; + + for (int i = 0; i < count; i++) + { + vector[i] = D3DXVECTOR4(v[0], v[1], v[2], 0); + + v += 3; + } + + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetVectorArray(device, constantPS, vector, count); + } + + if (constantVS) + { + mConstantTableVS->SetVectorArray(device, constantVS, vector, count); + } + + delete[] vector; + + return true; +} + +bool Program::applyUniform4fv(GLint location, GLsizei count, const GLfloat *v) +{ + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetVectorArray(device, constantPS, (D3DXVECTOR4*)v, count); + } + + if (constantVS) + { + mConstantTableVS->SetVectorArray(device, constantVS, (D3DXVECTOR4*)v, count); + } + + return true; +} + +bool Program::applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value) +{ + D3DXMATRIX *matrix = new D3DXMATRIX[count]; + + for (int i = 0; i < count; i++) + { + matrix[i] = D3DXMATRIX(value[0], value[2], 0, 0, + value[1], value[3], 0, 0, + 0, 0, 1, 0, + 0, 0, 0, 1); + + value += 4; + } + + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count); + } + + if (constantVS) + { + mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count); + } + + delete[] matrix; + + return true; +} + +bool Program::applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value) +{ + D3DXMATRIX *matrix = new D3DXMATRIX[count]; + + for (int i = 0; i < count; i++) + { + matrix[i] = D3DXMATRIX(value[0], value[3], value[6], 0, + value[1], value[4], value[7], 0, + value[2], value[5], value[8], 0, + 0, 0, 0, 1); + + value += 9; + } + + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count); + } + + if (constantVS) + { + mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count); + } + + delete[] matrix; + + return true; +} + +bool Program::applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value) +{ + D3DXMATRIX *matrix = new D3DXMATRIX[count]; + + for (int i = 0; i < count; i++) + { + matrix[i] = D3DXMATRIX(value[0], value[4], value[8], value[12], + value[1], value[5], value[9], value[13], + value[2], value[6], value[10], value[14], + value[3], value[7], value[11], value[15]); + + value += 16; + } + + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + mConstantTablePS->SetMatrixArray(device, constantPS, matrix, count); + } + + if (constantVS) + { + mConstantTableVS->SetMatrixArray(device, constantVS, matrix, count); + } + + delete[] matrix; + + return true; +} + +bool Program::applyUniform1iv(GLint location, GLsizei count, const GLint *v) +{ + D3DXHANDLE constantPS = mConstantTablePS->GetConstantByName(0, mUniforms[location]->name.c_str()); + D3DXHANDLE constantVS = mConstantTableVS->GetConstantByName(0, mUniforms[location]->name.c_str()); + IDirect3DDevice9 *device = getDevice(); + + if (constantPS) + { + D3DXCONSTANT_DESC constantDescription; + UINT descriptionCount = 1; + HRESULT result = mConstantTablePS->GetConstantDesc(constantPS, &constantDescription, &descriptionCount); + + if (SUCCEEDED(result)) + { + return false; + } + + if (constantDescription.RegisterSet == D3DXRS_SAMPLER) + { + unsigned int firstIndex = mConstantTablePS->GetSamplerIndex(constantPS); + + for (unsigned int samplerIndex = firstIndex; samplerIndex < firstIndex + count; samplerIndex++) + { + GLint mappedSampler = v[0]; + + if (mappedSampler >= 0 && mappedSampler < MAX_TEXTURE_IMAGE_UNITS) + { + if (samplerIndex >= 0 && samplerIndex < MAX_TEXTURE_IMAGE_UNITS) + { + mSamplerMapping[samplerIndex] = mappedSampler; + } + } + } + + return true; + } + } + + if (constantPS) + { + mConstantTablePS->SetIntArray(device, constantPS, v, count); + } + + if (constantVS) + { + mConstantTableVS->SetIntArray(device, constantVS, v, count); + } + + return true; +} + +// Returns the program object to an unlinked state, after detaching a shader, before re-linking, or at destruction +void Program::unlink(bool destroy) +{ + if (destroy) // Object being destructed + { + if (mFragmentShader) + { + mFragmentShader->detach(); + mFragmentShader = NULL; + } + + if (mVertexShader) + { + mVertexShader->detach(); + mVertexShader = NULL; + } + + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + delete[] mAttributeName[index]; + mAttributeName[index] = NULL; + } + } + + if (mPixelExecutable) + { + mPixelExecutable->Release(); + mPixelExecutable = NULL; + } + + if (mVertexExecutable) + { + mVertexExecutable->Release(); + mVertexExecutable = NULL; + } + + if (mConstantTablePS) + { + mConstantTablePS->Release(); + mConstantTablePS = NULL; + } + + if (mConstantTableVS) + { + mConstantTableVS->Release(); + mConstantTableVS = NULL; + } + + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + mInputMapping[index] = 0; + } + + for (int index = 0; index < MAX_TEXTURE_IMAGE_UNITS; index++) + { + mSamplerMapping[index] = 0; + } + + while (!mUniforms.empty()) + { + delete mUniforms.back(); + mUniforms.pop_back(); + } + + mLinked = false; +} + +bool Program::isLinked() +{ + return mLinked; +} + +void Program::flagForDeletion() +{ + mDeleteStatus = true; +} + +bool Program::isFlaggedForDeletion() const +{ + return mDeleteStatus; +} +} diff --git a/libGLESv2/Program.h b/libGLESv2/Program.h new file mode 100644 index 000000000..20f4caa37 --- /dev/null +++ b/libGLESv2/Program.h @@ -0,0 +1,129 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Program.h: Defines the gl::Program class. Implements GL program objects +// and related functionality. [OpenGL ES 2.0.24] section 2.10.3 page 28. + +#ifndef LIBGLESV2_PROGRAM_H_ +#define LIBGLESV2_PROGRAM_H_ + +#include "Context.h" + +#include +#include +#include + +namespace gl +{ +class FragmentShader; +class VertexShader; + +enum UniformType +{ + UNIFORM_1FV, + UNIFORM_2FV, + UNIFORM_3FV, + UNIFORM_4FV, + UNIFORM_MATRIX_2FV, + UNIFORM_MATRIX_3FV, + UNIFORM_MATRIX_4FV, + UNIFORM_1IV +}; + +// Helper class representing a single shader uniform +class Uniform +{ + public: + Uniform(UniformType type, const std::string &name, unsigned int bytes); + + ~Uniform(); + + const UniformType type; + const std::string name; + const unsigned int bytes; + unsigned char *data; + + private: + DISALLOW_COPY_AND_ASSIGN(Uniform); +}; + +class Program +{ + public: + Program(); + + ~Program(); + + bool attachShader(Shader *shader); + bool detachShader(Shader *shader); + + IDirect3DPixelShader9 *getPixelShader(); + IDirect3DVertexShader9 *getVertexShader(); + + void bindAttributeLocation(GLuint index, const char *name); + GLuint getAttributeLocation(const char *name); + bool isActiveAttribute(int attributeIndex); + int getInputMapping(int attributeIndex); + + GLint getSamplerMapping(unsigned int samplerIndex); + + GLint getUniformLocation(const char *name); + bool setUniform1fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform2fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform3fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniform4fv(GLint location, GLsizei count, const GLfloat *v); + bool setUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); + bool setUniform1iv(GLint location, GLsizei count, const GLint *v); + + void applyUniforms(); + + void link(); + bool isLinked(); + + void flagForDeletion(); + bool isFlaggedForDeletion() const; + + private: + DISALLOW_COPY_AND_ASSIGN(Program); + + ID3DXBuffer *compileToBinary(const char *hlsl, const char *profile, ID3DXConstantTable **constantTable); + void unlink(bool destroy = false); + + bool linkAttributes(); + void defineUniform(const D3DXCONSTANT_DESC &constantDescription); + bool applyUniform1fv(GLint location, GLsizei count, const GLfloat *v); + bool applyUniform2fv(GLint location, GLsizei count, const GLfloat *v); + bool applyUniform3fv(GLint location, GLsizei count, const GLfloat *v); + bool applyUniform4fv(GLint location, GLsizei count, const GLfloat *v); + bool applyUniformMatrix2fv(GLint location, GLsizei count, const GLfloat *value); + bool applyUniformMatrix3fv(GLint location, GLsizei count, const GLfloat *value); + bool applyUniformMatrix4fv(GLint location, GLsizei count, const GLfloat *value); + bool applyUniform1iv(GLint location, GLsizei count, const GLint *v); + + FragmentShader *mFragmentShader; + VertexShader *mVertexShader; + + IDirect3DPixelShader9 *mPixelExecutable; + IDirect3DVertexShader9 *mVertexExecutable; + ID3DXConstantTable *mConstantTablePS; + ID3DXConstantTable *mConstantTableVS; + + char *mAttributeName[MAX_VERTEX_ATTRIBS]; + int mInputMapping[MAX_VERTEX_ATTRIBS]; + + GLint mSamplerMapping[MAX_TEXTURE_IMAGE_UNITS]; + + typedef std::vector UniformArray; + UniformArray mUniforms; + + bool mLinked; + bool mDeleteStatus; // Flag to indicate that the program can be deleted when no longer in use +}; +} + +#endif // LIBGLESV2_PROGRAM_H_ diff --git a/libGLESv2/Renderbuffer.cpp b/libGLESv2/Renderbuffer.cpp new file mode 100644 index 000000000..b44cab19c --- /dev/null +++ b/libGLESv2/Renderbuffer.cpp @@ -0,0 +1,264 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Renderbuffer.cpp: the gl::Renderbuffer class and its derived classes +// Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#include "Renderbuffer.h" + +#include "main.h" +#include "utilities.h" + +namespace gl +{ +Renderbuffer::Renderbuffer() +{ + mWidth = 0; + mHeight = 0; +} + +Renderbuffer::~Renderbuffer() +{ +} + +bool Renderbuffer::isColorbuffer() +{ + return false; +} + +bool Renderbuffer::isDepthbuffer() +{ + return false; +} + +bool Renderbuffer::isStencilbuffer() +{ + return false; +} + +IDirect3DSurface9 *Renderbuffer::getRenderTarget() +{ + return NULL; +} + +IDirect3DSurface9 *Renderbuffer::getDepthStencil() +{ + return NULL; +} + +int Renderbuffer::getWidth() +{ + return mWidth; +} + +int Renderbuffer::getHeight() +{ + return mHeight; +} + +Colorbuffer::Colorbuffer(IDirect3DSurface9 *renderTarget) : mRenderTarget(renderTarget) +{ + if (renderTarget) + { + renderTarget->AddRef(); + + D3DSURFACE_DESC description; + renderTarget->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + } +} + +Colorbuffer::~Colorbuffer() +{ + if (mRenderTarget) + { + mRenderTarget->Release(); + } +} + +bool Colorbuffer::isColorbuffer() +{ + return true; +} + +GLuint Colorbuffer::getRedSize() +{ + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + return es2dx::GetRedSize(description.Format); + } + + return 0; +} + +GLuint Colorbuffer::getGreenSize() +{ + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + return es2dx::GetGreenSize(description.Format); + } + + return 0; +} + +GLuint Colorbuffer::getBlueSize() +{ + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + return es2dx::GetBlueSize(description.Format); + } + + return 0; +} + +GLuint Colorbuffer::getAlphaSize() +{ + if (mRenderTarget) + { + D3DSURFACE_DESC description; + mRenderTarget->GetDesc(&description); + + return es2dx::GetAlphaSize(description.Format); + } + + return 0; +} + +IDirect3DSurface9 *Colorbuffer::getRenderTarget() +{ + return mRenderTarget; +} + +Depthbuffer::Depthbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil) +{ + if (depthStencil) + { + depthStencil->AddRef(); + + D3DSURFACE_DESC description; + depthStencil->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + } +} + +Depthbuffer::Depthbuffer(int width, int height) +{ + IDirect3DDevice9 *device = getDevice(); + + mDepthStencil = NULL; + HRESULT result = device->CreateDepthStencilSurface(width, height, D3DFMT_D24S8, D3DMULTISAMPLE_NONE, 0, FALSE, &mDepthStencil, 0); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY); + + return; + } + + ASSERT(SUCCEEDED(result)); + + if (mDepthStencil) + { + mWidth = width; + mHeight = height; + } + else + { + mWidth = 0; + mHeight = 0; + } +} + +Depthbuffer::~Depthbuffer() +{ + if (mDepthStencil) + { + mDepthStencil->Release(); + } +} + +bool Depthbuffer::isDepthbuffer() +{ + return true; +} + +GLuint Depthbuffer::getDepthSize() +{ + if (mDepthStencil) + { + D3DSURFACE_DESC description; + mDepthStencil->GetDesc(&description); + + es2dx::GetDepthSize(description.Format); + } + + return 0; +} + +IDirect3DSurface9 *Depthbuffer::getDepthStencil() +{ + return mDepthStencil; +} + +Stencilbuffer::Stencilbuffer(IDirect3DSurface9 *depthStencil) : mDepthStencil(depthStencil) + { + if (depthStencil) + { + depthStencil->AddRef(); + + D3DSURFACE_DESC description; + depthStencil->GetDesc(&description); + + mWidth = description.Width; + mHeight = description.Height; + } + } + +Stencilbuffer::~Stencilbuffer() +{ + if (mDepthStencil) + { + mDepthStencil->Release(); + } +} + +GLuint Stencilbuffer::getStencilSize() +{ + if (mDepthStencil) + { + D3DSURFACE_DESC description; + mDepthStencil->GetDesc(&description); + + return es2dx::GetStencilSize(description.Format); + } + + return 0; +} + +bool Stencilbuffer::isStencilbuffer() +{ + return true; +} + +IDirect3DSurface9 *Stencilbuffer::getDepthStencil() +{ + return mDepthStencil; +} +} diff --git a/libGLESv2/Renderbuffer.h b/libGLESv2/Renderbuffer.h new file mode 100644 index 000000000..c0210a624 --- /dev/null +++ b/libGLESv2/Renderbuffer.h @@ -0,0 +1,108 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Renderbuffer.h: Defines the virtual gl::Renderbuffer class and its derived +// classes Colorbuffer, Depthbuffer and Stencilbuffer. Implements GL renderbuffer +// objects and related functionality. [OpenGL ES 2.0.24] section 4.4.3 page 108. + +#ifndef LIBGLESV2_RENDERBUFFER_H_ +#define LIBGLESV2_RENDERBUFFER_H_ + +#define GL_APICALL +#include +#include + +#include "angleutils.h" + +namespace gl +{ +class Renderbuffer +{ + public: + Renderbuffer(); + + virtual ~Renderbuffer(); + + virtual bool isColorbuffer(); + virtual bool isDepthbuffer(); + virtual bool isStencilbuffer(); + + virtual IDirect3DSurface9 *getRenderTarget(); + virtual IDirect3DSurface9 *getDepthStencil(); + + int getWidth(); + int getHeight(); + + protected: + int mWidth; + int mHeight; + + private: + DISALLOW_COPY_AND_ASSIGN(Renderbuffer); +}; + +class Colorbuffer : public Renderbuffer +{ + public: + Colorbuffer(IDirect3DSurface9 *renderTarget); + + ~Colorbuffer(); + + bool isColorbuffer(); + + GLuint getRedSize(); + GLuint getGreenSize(); + GLuint getBlueSize(); + GLuint getAlphaSize(); + + IDirect3DSurface9 *getRenderTarget(); + + protected: + IDirect3DSurface9 *mRenderTarget; + + private: + DISALLOW_COPY_AND_ASSIGN(Colorbuffer); +}; + +class Depthbuffer : public Renderbuffer +{ + public: + Depthbuffer(IDirect3DSurface9 *depthStencil); + Depthbuffer(int width, int height); + + ~Depthbuffer(); + + bool isDepthbuffer(); + + GLuint getDepthSize(); + + IDirect3DSurface9 *getDepthStencil(); + + private: + DISALLOW_COPY_AND_ASSIGN(Depthbuffer); + IDirect3DSurface9 *mDepthStencil; +}; + +class Stencilbuffer : public Renderbuffer +{ + public: + Stencilbuffer(IDirect3DSurface9 *depthStencil); + + ~Stencilbuffer(); + + bool isStencilbuffer(); + + GLuint getStencilSize(); + + IDirect3DSurface9 *getDepthStencil(); + + private: + DISALLOW_COPY_AND_ASSIGN(Stencilbuffer); + IDirect3DSurface9 *mDepthStencil; +}; +} + +#endif // LIBGLESV2_RENDERBUFFER_H_ diff --git a/libGLESv2/Shader.cpp b/libGLESv2/Shader.cpp new file mode 100644 index 000000000..4ee2ce27d --- /dev/null +++ b/libGLESv2/Shader.cpp @@ -0,0 +1,337 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Shader.cpp: Implements the gl::Shader class and its derived classes +// VertexShader and FragmentShader. Implements GL shader objects and related +// functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section 3.8 page 84. + +#include "Shader.h" + +#include "main.h" +#include "Shaderlang.h" +#include "debug.h" + +namespace gl +{ +void *Shader::mFragmentCompiler = NULL; +void *Shader::mVertexCompiler = NULL; + +Shader::Shader() +{ + mSource = NULL; + mHlsl = NULL; + mErrors = NULL; + + // Perform a one-time initialization of the shader compiler (or after being destructed by releaseCompiler) + if (!mFragmentCompiler) + { + int result = ShInitialize(); + + if (result) + { + mFragmentCompiler = ShConstructCompiler(EShLangFragment, EDebugOpObjectCode); + mVertexCompiler = ShConstructCompiler(EShLangVertex, EDebugOpObjectCode); + } + } + + mAttachCount = 0; + mDeleteStatus = false; +} + +Shader::~Shader() +{ + delete[] mSource; + delete[] mHlsl; + delete[] mErrors; +} + +void Shader::setSource(GLsizei count, const char **string, const GLint *length) +{ + delete[] mSource; + int totalLength = 0; + + for (int i = 0; i < count; i++) + { + if (length && length[i] >= 0) + { + totalLength += length[i]; + } + else + { + totalLength += (int)strlen(string[i]); + } + } + + mSource = new char[totalLength + 1]; + char *code = mSource; + + for (int i = 0; i < count; i++) + { + int stringLength; + + if (length && length[i] >= 0) + { + stringLength = length[i]; + } + else + { + stringLength = (int)strlen(string[i]); + } + + strncpy(code, string[i], stringLength); + code += stringLength; + } + + mSource[totalLength] = '\0'; +} + +bool Shader::isCompiled() +{ + return mHlsl != NULL; +} + +const char *Shader::linkHLSL() +{ + return mHlsl; +} + +void Shader::attach() +{ + mAttachCount++; +} + +void Shader::detach() +{ + mAttachCount--; +} + +bool Shader::isAttached() const +{ + return mAttachCount > 0; +} + +bool Shader::isDeletable() const +{ + return mDeleteStatus == true && mAttachCount == 0; +} + +void Shader::flagForDeletion() +{ + mDeleteStatus = true; +} + +void Shader::releaseCompiler() +{ + ShDestruct(mFragmentCompiler); + ShDestruct(mVertexCompiler); + + mFragmentCompiler = NULL; + mVertexCompiler = NULL; +} + +void Shader::compileToHLSL(void *compiler) +{ + if (isCompiled() || !mSource) + { + return; + } + + trace(mSource); + + delete[] mErrors; + mErrors = NULL; + + TBuiltInResource resources; + + resources.maxVertexAttribs = MAX_VERTEX_ATTRIBS; + resources.maxVertexUniformVectors = MAX_VERTEX_UNIFORM_VECTORS; + resources.maxVaryingVectors = MAX_VARYING_VECTORS; + resources.maxVertexTextureImageUnits = MAX_VERTEX_TEXTURE_IMAGE_UNITS; + resources.maxCombinedTextureImageUnits = MAX_COMBINED_TEXTURE_IMAGE_UNITS; + resources.maxTextureImageUnits = MAX_TEXTURE_IMAGE_UNITS; + resources.maxFragmentUniformVectors = MAX_FRAGMENT_UNIFORM_VECTORS; + resources.maxDrawBuffers = MAX_DRAW_BUFFERS; + + int result = ShCompile(compiler, &mSource, 1, EShOptNone, &resources, EDebugOpObjectCode); + const char *obj = ShGetObjectCode(compiler); + const char *info = ShGetInfoLog(compiler); + + if (result) + { + mHlsl = new char[strlen(obj) + 1]; + strcpy(mHlsl, obj); + + trace(mHlsl); + } + else + { + mErrors = new char[strlen(info) + 1]; + strcpy(mErrors, info); + + trace(mErrors); + } +} + +InputMapping::InputMapping() +{ + mAttribute = NULL; + mSemanticIndex = -1; +} + +InputMapping::InputMapping(const char *attribute, int semanticIndex) +{ + mAttribute = new char[strlen(attribute) + 1]; + strcpy(mAttribute, attribute); + mSemanticIndex = semanticIndex; +} + +InputMapping &InputMapping::operator=(const InputMapping &inputMapping) +{ + delete[] mAttribute; + + mAttribute = new char[strlen(inputMapping.mAttribute) + 1]; + strcpy(mAttribute, inputMapping.mAttribute); + mSemanticIndex = inputMapping.mSemanticIndex; + + return *this; +} + +InputMapping::~InputMapping() +{ + delete[] mAttribute; +} + +VertexShader::VertexShader() +{ +} + +VertexShader::~VertexShader() +{ +} + +GLenum VertexShader::getType() +{ + return GL_VERTEX_SHADER; +} + +void VertexShader::compile() +{ + compileToHLSL(mVertexCompiler); + parseAttributes(); +} + +const char *VertexShader::linkHLSL(const char *pixelHLSL) +{ + if (mHlsl && pixelHLSL) + { + const char *input = strstr(pixelHLSL, "struct PS_INPUT"); + char *output = strstr(mHlsl, "struct VS_OUTPUT"); + + while (*input != '}' && output) + { + char varyingName[100]; + int semanticIndex; + int matches = sscanf(input, "%s : TEXCOORD%d;", varyingName, &semanticIndex); + + if (matches == 2) + { + ASSERT(semanticIndex < 10 && semanticIndex < MAX_VARYING_VECTORS); + char *varying = strstr(output, varyingName); + varying = strstr(varying, " : TEXCOORD0;"); + + if (output) + { + varying[11] = '0' + semanticIndex; + } + else + { + return NULL; + } + + input = strstr(input, ";"); + } + + input++; + } + } + + return mHlsl; +} + +const char *VertexShader::getAttributeName(unsigned int attributeIndex) +{ + if (attributeIndex < MAX_VERTEX_ATTRIBS) + { + return mInputMapping[attributeIndex].mAttribute; + } + + return 0; +} + +bool VertexShader::isActiveAttribute(const char *attributeName) +{ + return getInputMapping(attributeName) != -1; +} + +int VertexShader::getInputMapping(const char *attributeName) +{ + if (attributeName) + { + for (int index = 0; index < MAX_VERTEX_ATTRIBS; index++) + { + if (mInputMapping[index].mAttribute && strcmp(mInputMapping[index].mAttribute, attributeName) == 0) + { + return mInputMapping[index].mSemanticIndex; + } + } + } + + return -1; +} + +void VertexShader::parseAttributes() +{ + if (mHlsl) + { + const char *input = strstr(mHlsl, "struct VS_INPUT"); + + for (int attributeIndex = 0; *input != '}'; input++) + { + char attributeName[100]; + int semanticIndex; + + int matches = sscanf(input, "%s : TEXCOORD%d;", attributeName, &semanticIndex); + + if (matches == 2) + { + ASSERT(attributeIndex < MAX_VERTEX_ATTRIBS); + mInputMapping[attributeIndex] = InputMapping(attributeName, semanticIndex); + attributeIndex++; + + input = strstr(input, ";"); + } + } + } +} + +FragmentShader::FragmentShader() +{ +} + +FragmentShader::~FragmentShader() +{ +} + +GLenum FragmentShader::getType() +{ + return GL_FRAGMENT_SHADER; +} + +void FragmentShader::compile() +{ + compileToHLSL(mFragmentCompiler); +} +} diff --git a/libGLESv2/Shader.h b/libGLESv2/Shader.h new file mode 100644 index 000000000..3bac7f859 --- /dev/null +++ b/libGLESv2/Shader.h @@ -0,0 +1,114 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Shader.h: Defines the abstract gl::Shader class and its concrete derived +// classes VertexShader and FragmentShader. Implements GL shader objects and +// related functionality. [OpenGL ES 2.0.24] section 2.10 page 24 and section +// 3.8 page 84. + +#ifndef LIBGLESV2_SHADER_H_ +#define LIBGLESV2_SHADER_H_ + +#include "Context.h" + +#define GL_APICALL +#include +#include + +namespace gl +{ +class Shader +{ + public: + Shader(); + + virtual ~Shader(); + + virtual GLenum getType() = 0; + + void deleteSource(); + void setSource(GLsizei count, const char **string, const GLint *length); + + virtual void compile() = 0; + bool isCompiled(); + const char *linkHLSL(); + + void attach(); + void detach(); + bool isAttached() const; + bool isDeletable() const; + void flagForDeletion(); + + static void releaseCompiler(); + + protected: + DISALLOW_COPY_AND_ASSIGN(Shader); + + void compileToHLSL(void *compiler); + + int mAttachCount; // Number of program objects this shader is attached to + bool mDeleteStatus; // Flag to indicate that the shader can be deleted when no longer in use + + char *mSource; + char *mHlsl; + char *mErrors; + + static void *mFragmentCompiler; + static void *mVertexCompiler; +}; + +class InputMapping +{ + public: + InputMapping(); + InputMapping(const char *attribute, int semanticIndex); + + ~InputMapping(); + + InputMapping &operator=(const InputMapping &inputMapping); + + char *mAttribute; + int mSemanticIndex; // TEXCOORDi +}; + +class VertexShader : public Shader +{ + public: + VertexShader(); + + ~VertexShader(); + + GLenum getType(); + void compile(); + const char *linkHLSL(const char *pixelHLSL); + const char *getAttributeName(unsigned int attributeIndex); + bool isActiveAttribute(const char *attributeName); + int getInputMapping(const char *attributeName); + + private: + DISALLOW_COPY_AND_ASSIGN(VertexShader); + + void parseAttributes(); + + InputMapping mInputMapping[MAX_VERTEX_ATTRIBS]; +}; + +class FragmentShader : public Shader +{ + public: + FragmentShader(); + + ~FragmentShader(); + + GLenum getType(); + void compile(); + + private: + DISALLOW_COPY_AND_ASSIGN(FragmentShader); +}; +} + +#endif // LIBGLESV2_SHADER_H_ diff --git a/libGLESv2/Texture.cpp b/libGLESv2/Texture.cpp new file mode 100644 index 000000000..72e9282d2 --- /dev/null +++ b/libGLESv2/Texture.cpp @@ -0,0 +1,671 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Texture.cpp: Implements the gl::Texture class and its derived classes +// Texture2D and TextureCubeMap. Implements GL texture objects and related +// functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#include "Texture.h" + +#include "main.h" +#include "mathutil.h" +#include "debug.h" + +namespace gl +{ +Texture::Texture() : Colorbuffer(0) +{ + mMinFilter = GL_NEAREST_MIPMAP_LINEAR; + mMagFilter = GL_LINEAR; + mWrapS = GL_REPEAT; + mWrapT = GL_REPEAT; +} + +Texture::~Texture() +{ +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMinFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mMinFilter = filter; + return true; + default: + return false; + } +} + +// Returns true on successful filter state update (valid enum parameter) +bool Texture::setMagFilter(GLenum filter) +{ + switch (filter) + { + case GL_NEAREST: + case GL_LINEAR: + mMagFilter = filter; + return true; + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapS(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + mWrapS = wrap; + return true; + default: + return false; + } +} + +// Returns true on successful wrap state update (valid enum parameter) +bool Texture::setWrapT(GLenum wrap) +{ + switch (wrap) + { + case GL_REPEAT: + case GL_CLAMP_TO_EDGE: + case GL_MIRRORED_REPEAT: + mWrapT = wrap; + return true; + default: + return false; + } +} + +GLenum Texture::getMinFilter() +{ + return mMinFilter; +} + +GLenum Texture::getMagFilter() +{ + return mMagFilter; +} + +GLenum Texture::getWrapS() +{ + return mWrapS; +} + +GLenum Texture::getWrapT() +{ + return mWrapT; +} + +// Copies an Image into an already locked Direct3D 9 surface, performing format conversions as necessary +void Texture::copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image) +{ + if (lock.pBits && image.pixels) + { + for (int y = 0; y < image.height; y++) + { + unsigned char *source = (unsigned char*)image.pixels + y * image.width * pixelSize(image); + unsigned short *source16 = (unsigned short*)source; + unsigned char *dest = (unsigned char*)lock.pBits + y * lock.Pitch; + + for (int x = 0; x < image.width; x++) + { + unsigned char r; + unsigned char g; + unsigned char b; + unsigned char a; + + switch (image.format) + { + case GL_ALPHA: + UNIMPLEMENTED(); + break; + case GL_LUMINANCE: + UNIMPLEMENTED(); + break; + case GL_LUMINANCE_ALPHA: + UNIMPLEMENTED(); + break; + case GL_RGB: + switch (image.type) + { + case GL_UNSIGNED_BYTE: UNIMPLEMENTED(); break; + case GL_UNSIGNED_SHORT_5_6_5: + { + unsigned short rgba = source16[x]; + + a = 0xFF; + b = ((rgba & 0x001F) << 3) | ((rgba & 0x001F) >> 2); + g = ((rgba & 0x07E0) >> 3) | ((rgba & 0x07E0) >> 9); + r = ((rgba & 0xF800) >> 8) | ((rgba & 0xF800) >> 13); + } + break; + default: UNREACHABLE(); + } + break; + case GL_RGBA: + switch (image.type) + { + case GL_UNSIGNED_BYTE: + r = source[x * 4 + 0]; + g = source[x * 4 + 1]; + b = source[x * 4 + 2]; + a = source[x * 4 + 3]; + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + { + unsigned short rgba = source16[x]; + + a = ((rgba & 0x000F) << 4) | ((rgba & 0x000F) >> 0); + b = ((rgba & 0x00F0) << 0) | ((rgba & 0x00F0) >> 4); + g = ((rgba & 0x0F00) >> 4) | ((rgba & 0x0F00) >> 8); + r = ((rgba & 0xF000) >> 8) | ((rgba & 0xF000) >> 12); + } + break; + case GL_UNSIGNED_SHORT_5_5_5_1: UNIMPLEMENTED(); break; + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + + switch (format) + { + case D3DFMT_A8R8G8B8: + dest[4 * x + 0] = b; + dest[4 * x + 1] = g; + dest[4 * x + 2] = r; + dest[4 * x + 3] = a; + break; + default: UNREACHABLE(); + } + } + } + } +} + +// Selects an internal Direct3D 9 format for storing an Image +D3DFORMAT Texture::selectFormat(const Image &image) +{ + switch (image.format) + { + case GL_ALPHA: + UNIMPLEMENTED(); + break; + case GL_LUMINANCE: + UNIMPLEMENTED(); + break; + case GL_LUMINANCE_ALPHA: + UNIMPLEMENTED(); + break; + case GL_RGB: + switch (image.type) + { + case GL_UNSIGNED_BYTE: UNIMPLEMENTED(); + case GL_UNSIGNED_SHORT_5_6_5: return D3DFMT_A8R8G8B8; + default: UNREACHABLE(); + } + break; + case GL_RGBA: + switch (image.type) + { + case GL_UNSIGNED_BYTE: return D3DFMT_A8R8G8B8; + case GL_UNSIGNED_SHORT_4_4_4_4: return D3DFMT_A8R8G8B8; + case GL_UNSIGNED_SHORT_5_5_5_1: UNIMPLEMENTED(); + default: UNREACHABLE(); + } + break; + default: UNREACHABLE(); + } + + return D3DFMT_UNKNOWN; +} + +// Returns the size, in bytes, of a single texel in an Image +int Texture::pixelSize(const Image &image) +{ + switch (image.type) + { + case GL_UNSIGNED_BYTE: + switch (image.format) + { + case GL_ALPHA: return sizeof(unsigned char); + case GL_LUMINANCE: return sizeof(unsigned char); + case GL_LUMINANCE_ALPHA: return sizeof(unsigned char) * 2; + case GL_RGB: return sizeof(unsigned char) * 3; + case GL_RGBA: return sizeof(unsigned char) * 4; + default: UNREACHABLE(); + } + break; + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + case GL_UNSIGNED_SHORT_5_6_5: + return sizeof(unsigned short); + default: UNREACHABLE(); + } + + return 0; +} + +Texture2D::Texture2D() +{ + for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) + { + mImageArray[level].pixels = NULL; + } + + mTexture = NULL; +} + +Texture2D::~Texture2D() +{ + for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) + { + delete[] mImageArray[level].pixels; + } + + if (mTexture) + { + mTexture->Release(); + mTexture = NULL; + } +} + +GLenum Texture2D::getTarget() const +{ + return GL_TEXTURE_2D; +} + +void Texture2D::setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) + { + return; + } + + mImageArray[level].internalFormat = internalFormat; + mImageArray[level].width = width; + mImageArray[level].height = height; + mImageArray[level].format = format; + mImageArray[level].type = type; + + delete[] mImageArray[level].pixels; + mImageArray[level].pixels = NULL; + + int imageSize = pixelSize(mImageArray[level]) * width * height; + mImageArray[level].pixels = new unsigned char[imageSize]; + + if(pixels) + { + memcpy(mImageArray[level].pixels, pixels, imageSize); + } + + if (level == 0) + { + mWidth = width; + mHeight = height; + } +} + +// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool Texture2D::isComplete() +{ + if (mWidth <= 0 || mHeight <= 0) + { + return false; + } + + bool mipmapping; + + switch (mMagFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: UNREACHABLE(); + } + + if (mipmapping) + { + int q = log2(max(mWidth, mHeight)); + + for (int level = 1; level <= q; level++) + { + if (mImageArray[level].format != mImageArray[0].format) + { + return false; + } + + if (mImageArray[level].internalFormat != mImageArray[0].internalFormat) + { + return false; + } + + if (mImageArray[level].type != mImageArray[0].type) + { + return false; + } + + if (mImageArray[level].width != (mImageArray[level - 1].width + 1) / 2) + { + return false; + } + + if (mImageArray[level].height != (mImageArray[level - 1].height + 1) / 2) + { + return false; + } + } + } + + return true; +} + +// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one +IDirect3DBaseTexture9 *Texture2D::getTexture() +{ + if (!isComplete()) + { + return NULL; + } + + if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget) + { + IDirect3DDevice9 *device = getDevice(); + D3DFORMAT format = selectFormat(mImageArray[0]); + + HRESULT result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY, 0); + } + + ASSERT(SUCCEEDED(result)); + + IDirect3DTexture9 *lockableTexture; + result = device->CreateTexture(mWidth, mHeight, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY,(IDirect3DBaseTexture9*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + if (mTexture) // FIXME: Handle failure + { + int levelCount = mTexture->GetLevelCount(); + + for (int level = 0; level < levelCount; level++) + { + D3DLOCKED_RECT lock = {0}; + lockableTexture->LockRect(level, &lock, NULL, 0); + + copyImage(lock, format, mImageArray[level]); + + lockableTexture->UnlockRect(level); + } + + device->UpdateTexture(lockableTexture, mTexture); + lockableTexture->Release(); + } + } + + return mTexture; +} + +// Returns the top-level texture surface as a render target +IDirect3DSurface9 *Texture2D::getRenderTarget() +{ + if (!mRenderTarget && getTexture()) + { + mTexture->GetSurfaceLevel(0, &mRenderTarget); + } + + return mRenderTarget; +} + +TextureCubeMap::TextureCubeMap() +{ + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) + { + mImageArray[face][level].pixels = NULL; + } + } + + mTexture = NULL; +} + +TextureCubeMap::~TextureCubeMap() +{ + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) + { + delete[] mImageArray[face][level].pixels; + } + } + + if (mTexture) + { + mTexture->Release(); + mTexture = NULL; + } +} + +GLenum TextureCubeMap::getTarget() const +{ + return GL_TEXTURE_CUBE_MAP; +} + +void TextureCubeMap::setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(0, level, internalFormat, width, height, format, type, pixels); +} + +void TextureCubeMap::setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(1, level, internalFormat, width, height, format, type, pixels); +} + +void TextureCubeMap::setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(2, level, internalFormat, width, height, format, type, pixels); +} + +void TextureCubeMap::setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(3, level, internalFormat, width, height, format, type, pixels); +} + +void TextureCubeMap::setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(4, level, internalFormat, width, height, format, type, pixels); +} + +void TextureCubeMap::setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + setImage(5, level, internalFormat, width, height, format, type, pixels); +} + +// Tests for GL texture object completeness. [OpenGL ES 2.0.24] section 3.7.10 page 81. +bool TextureCubeMap::isComplete() +{ + if (mWidth <= 0 || mHeight <= 0 || mWidth != mHeight) + { + return false; + } + + bool mipmapping; + + switch (mMagFilter) + { + case GL_NEAREST: + case GL_LINEAR: + mipmapping = false; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + mipmapping = true; + break; + default: UNREACHABLE(); + } + + for (int face = 0; face < 6; face++) + { + if (mImageArray[face][0].width != mWidth || mImageArray[face][0].height != mHeight) + { + return false; + } + } + + if (mipmapping) + { + int q = log2(mWidth); + + for (int face = 0; face < 6; face++) + { + for (int level = 1; level <= q; level++) + { + if (mImageArray[face][level].format != mImageArray[0][0].format) + { + return false; + } + + if (mImageArray[face][level].internalFormat != mImageArray[0][0].internalFormat) + { + return false; + } + + if (mImageArray[face][level].type != mImageArray[0][0].type) + { + return false; + } + + if (mImageArray[face][level].width != (mImageArray[0][level - 1].width + 1) / 2) + { + return false; + } + + if (mImageArray[face][level].height != (mImageArray[0][level - 1].height + 1) / 2) + { + return false; + } + } + } + } + + return true; +} + +// Constructs a Direct3D 9 texture resource from the texture images, or returns an existing one +IDirect3DBaseTexture9 *TextureCubeMap::getTexture() +{ + if (!isComplete()) + { + return NULL; + } + + if (!mTexture) // FIXME: Recreate when changed (same for getRenderTarget) + { + IDirect3DDevice9 *device = getDevice(); + D3DFORMAT format = selectFormat(mImageArray[0][0]); + + HRESULT result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_RENDERTARGET, format, D3DPOOL_DEFAULT, &mTexture, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + IDirect3DCubeTexture9 *lockableTexture; + result = device->CreateCubeTexture(mWidth, 0, D3DUSAGE_DYNAMIC, format, D3DPOOL_SYSTEMMEM, &lockableTexture, NULL); + + if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY) + { + return error(GL_OUT_OF_MEMORY, (IDirect3DBaseTexture9*)NULL); + } + + ASSERT(SUCCEEDED(result)); + + if (mTexture) + { + for (int face = 0; face < 6; face++) + { + for (int level = 0; level < MAX_TEXTURE_LEVELS; level++) + { + D3DLOCKED_RECT lock = {0}; + lockableTexture->LockRect((D3DCUBEMAP_FACES)face, level, &lock, NULL, 0); + + copyImage(lock, format, mImageArray[face][level]); + + lockableTexture->UnlockRect((D3DCUBEMAP_FACES)face, level); + } + } + + device->UpdateTexture(lockableTexture, mTexture); + lockableTexture->Release(); + } + } + + return mTexture; +} + +void TextureCubeMap::setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels) +{ + if (level < 0 || level >= MAX_TEXTURE_LEVELS) + { + return; + } + + mImageArray[face][level].internalFormat = internalFormat; + mImageArray[face][level].width = width; + mImageArray[face][level].height = height; + mImageArray[face][level].format = format; + mImageArray[face][level].type = type; + + delete[] mImageArray[face][level].pixels; + mImageArray[face][level].pixels = NULL; + + int imageSize = pixelSize(mImageArray[face][level]) * width * height; + mImageArray[face][level].pixels = new unsigned char[imageSize]; + + if (pixels) + { + memcpy(mImageArray[face][level].pixels, pixels, imageSize); + } + + if (face == 0 && level == 0) + { + mWidth = width; + mHeight = height; + } +} +} diff --git a/libGLESv2/Texture.h b/libGLESv2/Texture.h new file mode 100644 index 000000000..fc3a30b67 --- /dev/null +++ b/libGLESv2/Texture.h @@ -0,0 +1,141 @@ +// +// Copyright (c) 2002-2010 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. +// + +// Texture.h: Defines the abstract gl::Texture class and its concrete derived +// classes Texture2D and TextureCubeMap. Implements GL texture objects and +// related functionality. [OpenGL ES 2.0.24] section 3.7 page 63. + +#ifndef LIBGLESV2_TEXTURE_H_ +#define LIBGLESV2_TEXTURE_H_ + +#include "Renderbuffer.h" + +#define GL_APICALL +#include +#include + +namespace gl +{ +enum +{ + MAX_TEXTURE_SIZE = 2048, + MAX_CUBE_MAP_TEXTURE_SIZE = 2048, + + MAX_TEXTURE_LEVELS = 11 // log2 of MAX_TEXTURE_SIZE +}; + +// Helper structure representing a single image layer +struct Image +{ + GLenum internalFormat; + GLsizei width; + GLsizei height; + GLenum format; + GLenum type; + void *pixels; +}; + +class Texture : public Colorbuffer +{ + public: + Texture(); + + ~Texture(); + + virtual GLenum getTarget() const = 0; + + bool setMinFilter(GLenum filter); + bool setMagFilter(GLenum filter); + bool setWrapS(GLenum wrap); + bool setWrapT(GLenum wrap); + + GLenum getMinFilter(); + GLenum getMagFilter(); + GLenum getWrapS(); + GLenum getWrapT(); + + virtual bool isComplete() = 0; + virtual IDirect3DBaseTexture9 *getTexture() = 0; + + protected: + void copyImage(D3DLOCKED_RECT &lock, D3DFORMAT format, Image &image); + + static D3DFORMAT selectFormat(const Image &image); + static int pixelSize(const Image &image); + + GLenum mMinFilter; + GLenum mMagFilter; + GLenum mWrapS; + GLenum mWrapT; + + private: + DISALLOW_COPY_AND_ASSIGN(Texture); +}; + +class Texture2D : public Texture +{ + public: + Texture2D(); + + ~Texture2D(); + + GLenum getTarget() const; + + void setImage(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + + bool setMinFilter(GLenum filter); + bool setMagFilter(GLenum filter); + bool setWrapS(GLenum wrap); + bool setWrapT(GLenum wrap); + + GLenum getMinFilter(); + GLenum getMagFilter(); + GLenum getWrapS(); + GLenum getWrapT(); + + bool isComplete(); + IDirect3DBaseTexture9 *getTexture(); + IDirect3DSurface9 *getRenderTarget(); + + private: + DISALLOW_COPY_AND_ASSIGN(Texture2D); + + Image mImageArray[MAX_TEXTURE_LEVELS]; + + IDirect3DTexture9 *mTexture; +}; + +class TextureCubeMap : public Texture +{ + public: + TextureCubeMap(); + + ~TextureCubeMap(); + + GLenum getTarget() const; + + void setImagePosX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void setImageNegX(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void setImagePosY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void setImageNegY(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void setImagePosZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + void setImageNegZ(GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + + bool isComplete(); + IDirect3DBaseTexture9 *getTexture(); + + private: + DISALLOW_COPY_AND_ASSIGN(TextureCubeMap); + + void setImage(int face, GLint level, GLenum internalFormat, GLsizei width, GLsizei height, GLenum format, GLenum type, const void *pixels); + + Image mImageArray[6][MAX_TEXTURE_LEVELS]; + + IDirect3DCubeTexture9 *mTexture; +}; +} + +#endif // LIBGLESV2_TEXTURE_H_ diff --git a/libGLESv2/libGLESv2.cpp b/libGLESv2/libGLESv2.cpp new file mode 100644 index 000000000..21c41b274 --- /dev/null +++ b/libGLESv2/libGLESv2.cpp @@ -0,0 +1,3836 @@ +// +// Copyright (c) 2002-2010 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. +// + +// libGLESv2.cpp: Implements the exported OpenGL ES 2.0 functions. + +#define GL_APICALL +#include +#include + +#include "Context.h" +#include "main.h" +#include "Program.h" +#include "Shader.h" +#include "Buffer.h" +#include "Texture.h" +#include "Renderbuffer.h" +#include "Framebuffer.h" +#include "mathutil.h" +#include "debug.h" + +#include + +extern "C" +{ + +void __stdcall glActiveTexture(GLenum texture) +{ + TRACE("GLenum texture = 0x%X", texture); + + try + { + if (texture < GL_TEXTURE0 || texture > GL_TEXTURE0 + gl::MAX_TEXTURE_IMAGE_UNITS - 1) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->activeSampler = texture - GL_TEXTURE0; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glAttachShader(GLuint program, GLuint shader) +{ + TRACE("GLuint program = %d, GLuint shader = %d", program, shader); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if(!programObject || !shaderObject) + { + return error(GL_INVALID_VALUE); + } + + if (!programObject->attachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindAttribLocation(GLuint program, GLuint index, const char* name) +{ + TRACE("GLuint program = %d, GLuint index = %d, const char* name = 0x%0.8p", program, index, name); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + programObject->bindAttributeLocation(index, name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindBuffer(GLenum target, GLuint buffer) +{ + TRACE("GLenum target = 0x%X, GLuint buffer = %d", target, buffer); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (target) + { + case GL_ARRAY_BUFFER: + context->bindArrayBuffer(buffer); + return; + case GL_ELEMENT_ARRAY_BUFFER: + context->bindElementArrayBuffer(buffer); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindFramebuffer(GLenum target, GLuint framebuffer) +{ + TRACE("GLenum target = 0x%X, GLuint framebuffer = %d", target, framebuffer); + + try + { + if (target != GL_FRAMEBUFFER) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->bindFramebuffer(framebuffer); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindRenderbuffer(GLenum target, GLuint renderbuffer) +{ + TRACE("GLenum target = 0x%X, GLuint renderbuffer = %d", target, renderbuffer); + + try + { + if (target != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->bindRenderbuffer(renderbuffer); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBindTexture(GLenum target, GLuint texture) +{ + TRACE("GLenum target = 0x%X, GLuint texture = %d", target, texture); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject && textureObject->getTarget() != target && texture != 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_2D: + context->bindTexture2D(texture); + return; + case GL_TEXTURE_CUBE_MAP: + context->bindTextureCubeMap(texture); + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + TRACE("GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f", red, green, blue, alpha); + + try + { + gl::Context* context = gl::getContext(); + + if (context) + { + context->blendColor.red = gl::clamp01(red); + context->blendColor.blue = gl::clamp01(blue); + context->blendColor.green = gl::clamp01(green); + context->blendColor.alpha = gl::clamp01(alpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendEquation(GLenum mode) +{ + glBlendEquationSeparate(mode, mode); +} + +void __stdcall glBlendEquationSeparate(GLenum modeRGB, GLenum modeAlpha) +{ + TRACE("GLenum modeRGB = 0x%X, GLenum modeAlpha = 0x%X", modeRGB, modeAlpha); + + try + { + switch (modeRGB) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (modeAlpha) + { + case GL_FUNC_ADD: + case GL_FUNC_SUBTRACT: + case GL_FUNC_REVERSE_SUBTRACT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->blendEquationRGB = modeRGB; + context->blendEquationAlpha = modeAlpha; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBlendFunc(GLenum sfactor, GLenum dfactor) +{ + glBlendFuncSeparate(sfactor, dfactor, sfactor, dfactor); +} + +void __stdcall glBlendFuncSeparate(GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha) +{ + TRACE("GLenum srcRGB = 0x%X, GLenum dstRGB = 0x%X, GLenum srcAlpha = 0x%X, GLenum dstAlpha = 0x%X", srcRGB, dstRGB, srcAlpha, dstAlpha); + + try + { + switch (srcRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstRGB) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (srcAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + case GL_SRC_ALPHA_SATURATE: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (dstAlpha) + { + case GL_ZERO: + case GL_ONE: + case GL_SRC_COLOR: + case GL_ONE_MINUS_SRC_COLOR: + case GL_DST_COLOR: + case GL_ONE_MINUS_DST_COLOR: + case GL_SRC_ALPHA: + case GL_ONE_MINUS_SRC_ALPHA: + case GL_DST_ALPHA: + case GL_ONE_MINUS_DST_ALPHA: + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + break; + default: + return error(GL_INVALID_ENUM); + } + + if ((srcRGB == GL_CONSTANT_COLOR && dstRGB == GL_CONSTANT_ALPHA) || + (srcRGB == GL_CONSTANT_ALPHA && dstRGB == GL_CONSTANT_COLOR)) + { + UNIMPLEMENTED(); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->sourceBlendRGB = srcRGB; + context->sourceBlendAlpha = srcAlpha; + context->destBlendRGB = dstRGB; + context->destBlendAlpha = dstAlpha; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferData(GLenum target, GLsizeiptr size, const void* data, GLenum usage) +{ + TRACE("GLenum target = 0x%X, GLsizeiptr size = %d, const void* data = 0x%0.8p, GLenum usage = %d", target, size, data, usage); + + try + { + if (size < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (usage) + { + case GL_STREAM_DRAW: + case GL_STATIC_DRAW: + case GL_DYNAMIC_DRAW: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Buffer *buffer; + + switch (target) + { + case GL_ARRAY_BUFFER: + buffer = context->getArrayBuffer(); + break; + case GL_ELEMENT_ARRAY_BUFFER: + buffer = context->getElementArrayBuffer(); + break; + default: + return error(GL_INVALID_ENUM); + } + + if (!buffer) + { + return error(GL_INVALID_OPERATION); + } + + buffer->storeData(size, data); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void* data) +{ + TRACE("GLenum target = 0x%X, GLintptr offset = %d, GLsizeiptr size = %d, const void* data = 0x%0.8p", target, offset, size, data); + + try + { + if (size < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glCheckFramebufferStatus(GLenum target) +{ + TRACE("GLenum target = 0x%X", target); + + try + { + if (target != GL_FRAMEBUFFER) + { + return error(GL_INVALID_ENUM, 0); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Framebuffer *framebuffer = context->getFramebuffer(); + + return framebuffer->completeness(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glClear(GLbitfield mask) +{ + TRACE("GLbitfield mask = %X", mask); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->clear(mask); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) +{ + TRACE("GLclampf red = %f, GLclampf green = %f, GLclampf blue = %f, GLclampf alpha = %f", red, green, blue, alpha); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->setClearColor(red, green, blue, alpha); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearDepthf(GLclampf depth) +{ + TRACE("GLclampf depth = %f", depth); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->setClearDepth(depth); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glClearStencil(GLint s) +{ + TRACE("GLint s = %d", s); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->setClearStencil(s); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glColorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) +{ + TRACE("GLboolean red = %d, GLboolean green = %d, GLboolean blue = %d, GLboolean alpha = %d", red, green, blue, alpha); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->colorMaskRed = red != GL_FALSE; + context->colorMaskGreen = green != GL_FALSE; + context->colorMaskBlue = blue != GL_FALSE; + context->colorMaskAlpha = alpha != GL_FALSE; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompileShader(GLuint shader) +{ + TRACE("GLuint shader = %d", shader); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + shaderObject->compile(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, GLsizei imageSize, const void* data) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLint border = %d, GLsizei imageSize = %d, const void* data = 0x%0.8p", + target, level, internalformat, width, height, border, imageSize, data); + + try + { + if (width < 0 || height < 0 || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCompressedTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLsizei imageSize, const void* data) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLsizei imageSize = %d, const void* data = 0x%0.8p", + target, level, xoffset, yoffset, width, height, format, imageSize, data); + + try + { + if (width < 0 || height < 0 || imageSize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexImage2D(GLenum target, GLint level, GLenum internalformat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d", + target, level, internalformat, x, y, width, height, border); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glCopyTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d", + target, level, xoffset, yoffset, x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLuint __stdcall glCreateProgram(void) +{ + TRACE(""); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + return context->createProgram(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +GLuint __stdcall glCreateShader(GLenum type) +{ + TRACE("GLenum type = 0x%X", type); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (type) + { + case GL_FRAGMENT_SHADER: + case GL_VERTEX_SHADER: + return context->createShader(type); + default: + return error(GL_INVALID_ENUM, 0); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, 0); + } + + return 0; +} + +void __stdcall glCullFace(GLenum mode) +{ + TRACE("GLenum mode = 0x%X", mode); + + try + { + switch (mode) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->cullMode = mode; + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteBuffers(GLsizei n, const GLuint* buffers) +{ + TRACE("GLsizei n = %d, const GLuint* buffers = 0x%0.8p", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + context->deleteBuffer(buffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteFramebuffers(GLsizei n, const GLuint* framebuffers) +{ + TRACE("GLsizei n = %d, const GLuint* framebuffers = 0x%0.8p", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (framebuffers[i] != 0) + { + context->deleteFramebuffer(framebuffers[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteProgram(GLuint program) +{ + TRACE("GLuint program = %d", program); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->deleteProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteRenderbuffers(GLsizei n, const GLuint* renderbuffers) +{ + TRACE("GLsizei n = %d, const GLuint* renderbuffers = 0x%0.8p", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for(int i = 0; i < n; i++) + { + context->deleteRenderbuffer(renderbuffers[i]); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteShader(GLuint shader) +{ + TRACE("GLuint shader = %d", shader); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->deleteShader(shader); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDeleteTextures(GLsizei n, const GLuint* textures) +{ + TRACE("GLsizei n = %d, const GLuint* textures = 0x%0.8p", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + if (textures[i] != 0) + { + context->deleteTexture(textures[i]); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthFunc(GLenum func) +{ + TRACE("GLenum func = 0x%X", func); + + try + { + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GREATER: + case GL_GEQUAL: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->depthFunc = func; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthMask(GLboolean flag) +{ + TRACE("GLboolean flag = %d", flag); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->depthMask = flag != GL_FALSE; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDepthRangef(GLclampf zNear, GLclampf zFar) +{ + TRACE("GLclampf zNear = %f, GLclampf zFar = %f", zNear, zFar); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->zNear = zNear; + context->zFar = zFar; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDetachShader(GLuint program, GLuint shader) +{ + TRACE("GLuint program = %d, GLuint shader = %d", program, shader); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + gl::Shader *shaderObject = context->getShader(shader); + + if (!programObject || !shaderObject) + { + return error(GL_INVALID_VALUE); + } + + if (!programObject->detachShader(shaderObject)) + { + return error(GL_INVALID_OPERATION); + } + + if (shaderObject->isDeletable()) + { + context->deleteShader(shader); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisable(GLenum cap) +{ + TRACE("GLenum cap = 0x%X", cap); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->cullFace = false; break; + case GL_POLYGON_OFFSET_FILL: context->polygonOffsetFill = false; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->sampleAlphaToCoverage = false; break; + case GL_SAMPLE_COVERAGE: context->sampleCoverage = false; break; + case GL_SCISSOR_TEST: context->scissorTest = false; break; + case GL_STENCIL_TEST: context->stencilTest = false; break; + case GL_DEPTH_TEST: context->depthTest = false; break; + case GL_BLEND: context->blend = false; break; + case GL_DITHER: context->dither = false; break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDisableVertexAttribArray(GLuint index) +{ + TRACE("GLuint index = %d", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->vertexAttribute[index].enabled = false; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawArrays(GLenum mode, GLint first, GLsizei count) +{ + TRACE("GLenum mode = 0x%X, GLint first = %d, GLsizei count = %d", mode, first, count); + + try + { + if (count < 0 || first < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->drawArrays(mode, first, count); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glDrawElements(GLenum mode, GLsizei count, GLenum type, const void* indices) +{ + TRACE("GLenum mode = 0x%X, GLsizei count = %d, GLenum type = 0x%X, const void* indices = 0x%0.8p", mode, count, type, indices); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (type) + { + case GL_UNSIGNED_BYTE: + UNIMPLEMENTED(); // FIXME + case GL_UNSIGNED_SHORT: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->drawElements(mode, count, type, indices); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnable(GLenum cap) +{ + TRACE("GLenum cap = 0x%X", cap); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: context->cullFace = true; break; + case GL_POLYGON_OFFSET_FILL: context->polygonOffsetFill = true; break; + case GL_SAMPLE_ALPHA_TO_COVERAGE: context->sampleAlphaToCoverage = true; break; + case GL_SAMPLE_COVERAGE: context->sampleCoverage = true; break; + case GL_SCISSOR_TEST: context->scissorTest = true; break; + case GL_STENCIL_TEST: context->stencilTest = true; break; + case GL_DEPTH_TEST: context->depthTest = true; break; + case GL_BLEND: context->blend = true; break; + case GL_DITHER: context->dither = true; break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glEnableVertexAttribArray(GLuint index) +{ + TRACE("GLuint index = %d", index); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->vertexAttribute[index].enabled = true; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFinish(void) +{ + TRACE(""); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->finish(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFlush(void) +{ + TRACE(""); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->flush(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferRenderbuffer(GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer) +{ + TRACE("GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum renderbuffertarget = 0x%X, GLuint renderbuffer = %d", target, attachment, renderbuffertarget, renderbuffer); + + try + { + if (target != GL_FRAMEBUFFER || renderbuffertarget != GL_RENDERBUFFER) + { + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Framebuffer *framebuffer = context->getFramebuffer(); + + if (context->framebuffer == 0 || !framebuffer) + { + return error(GL_INVALID_OPERATION); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + framebuffer->setColorbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_DEPTH_ATTACHMENT: + framebuffer->setDepthbuffer(GL_RENDERBUFFER, renderbuffer); + break; + case GL_STENCIL_ATTACHMENT: + framebuffer->setStencilbuffer(GL_RENDERBUFFER, renderbuffer); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFramebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level) +{ + TRACE("GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum textarget = 0x%X, GLuint texture = %d, GLint level = %d", target, attachment, textarget, texture, level); + + try + { + if (target != GL_FRAMEBUFFER) + { + return error(GL_INVALID_ENUM); + } + + switch (attachment) + { + case GL_COLOR_ATTACHMENT0: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (texture) + { + switch (textarget) + { + case GL_TEXTURE_2D: + if (!context->getTexture2D()) + { + return error(GL_INVALID_OPERATION); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + UNIMPLEMENTED(); // FIXME + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + UNIMPLEMENTED(); // FIXME + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + UNIMPLEMENTED(); // FIXME + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + UNIMPLEMENTED(); // FIXME + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + UNIMPLEMENTED(); // FIXME + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + UNIMPLEMENTED(); // FIXME + break; + default: + return error(GL_INVALID_ENUM); + } + + if (level != 0) + { + return error(GL_INVALID_VALUE); + } + } + + gl::Framebuffer *framebuffer = context->getFramebuffer(); + + if (context->framebuffer == 0 || !framebuffer) + { + return error(GL_INVALID_OPERATION); + } + + framebuffer->setColorbuffer(GL_TEXTURE, texture); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glFrontFace(GLenum mode) +{ + TRACE("GLenum mode = 0x%X", mode); + + try + { + switch (mode) + { + case GL_CW: + case GL_CCW: + { + gl::Context *context = gl::getContext(); + + if (context) + { + context->frontFace = mode; + } + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenBuffers(GLsizei n, GLuint* buffers) +{ + TRACE("GLsizei n = %d, GLuint* buffers = 0x%0.8p", n, buffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + buffers[i] = context->createBuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenerateMipmap(GLenum target) +{ + TRACE("GLenum target = 0x%X", target); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenFramebuffers(GLsizei n, GLuint* framebuffers) +{ + TRACE("GLsizei n = %d, GLuint* framebuffers = 0x%0.8p", n, framebuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + framebuffers[i] = context->createFramebuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenRenderbuffers(GLsizei n, GLuint* renderbuffers) +{ + TRACE("GLsizei n = %d, GLuint* renderbuffers = 0x%0.8p", n, renderbuffers); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + renderbuffers[i] = context->createRenderbuffer(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGenTextures(GLsizei n, GLuint* textures) +{ + TRACE("GLsizei n = %d, GLuint* textures = 0x%0.8p", n, textures); + + try + { + if (n < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + for (int i = 0; i < n; i++) + { + textures[i] = context->createTexture(); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveAttrib(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ + TRACE("GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = %0.8p, char* name = %0.8p", + program, index, bufsize, length, size, type, name); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetActiveUniform(GLuint program, GLuint index, GLsizei bufsize, GLsizei* length, GLint* size, GLenum* type, char* name) +{ + TRACE("GLuint program = %d, GLuint index = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, GLint* size = 0x%0.8p, GLenum* type = 0x%0.8p, char* name = 0x%0.8p", + program, index, bufsize, length, size, type, name); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetAttachedShaders(GLuint program, GLsizei maxcount, GLsizei* count, GLuint* shaders) +{ + TRACE("GLuint program = %d, GLsizei maxcount = %d, GLsizei* count = 0x%0.8p, GLuint* shaders = 0x%0.8p", program, maxcount, count, shaders); + + try + { + if (maxcount < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetAttribLocation(GLuint program, const char* name) +{ + TRACE("GLuint program = %d, const char* name = %s", program, name); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE, -1); + } + + return programObject->getAttributeLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetBooleanv(GLenum pname, GLboolean* params) +{ + TRACE("GLenum pname = 0x%X, GLboolean* params = 0x%0.8p", pname, params); + + try + { + switch (pname) + { + case GL_SHADER_COMPILER: *params = GL_TRUE; break; + default: + UNIMPLEMENTED(); // FIXME + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetBufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p", target, pname, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLenum __stdcall glGetError(void) +{ + TRACE(""); + + gl::Context *context = gl::getContext(); + + if (context) + { + return context->getError(); + } + + return GL_NO_ERROR; +} + +void __stdcall glGetFloatv(GLenum pname, GLfloat* params) +{ + TRACE("GLenum pname = 0x%X, GLfloat* params = 0x%0.8p", pname, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetFramebufferAttachmentParameteriv(GLenum target, GLenum attachment, GLenum pname, GLint* params) +{ + TRACE("GLenum target = 0x%X, GLenum attachment = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p", target, attachment, pname, params); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + if (context->framebuffer == 0) + { + return error(GL_INVALID_OPERATION); + } + + UNIMPLEMENTED(); // FIXME + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetIntegerv(GLenum pname, GLint* params) +{ + TRACE("GLenum pname = 0x%X, GLint* params = 0x%0.8p", pname, params); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (pname) + { + case GL_MAX_VERTEX_ATTRIBS: *params = gl::MAX_VERTEX_ATTRIBS; break; + case GL_MAX_VERTEX_UNIFORM_VECTORS: *params = gl::MAX_VERTEX_UNIFORM_VECTORS; break; + case GL_MAX_VARYING_VECTORS: *params = gl::MAX_VARYING_VECTORS; break; + case GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS: *params = gl::MAX_COMBINED_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_VERTEX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_TEXTURE_IMAGE_UNITS: *params = gl::MAX_TEXTURE_IMAGE_UNITS; break; + case GL_MAX_FRAGMENT_UNIFORM_VECTORS: *params = gl::MAX_FRAGMENT_UNIFORM_VECTORS; break; + case GL_MAX_RENDERBUFFER_SIZE: *params = gl::MAX_RENDERBUFFER_SIZE; break; + case GL_NUM_SHADER_BINARY_FORMATS: *params = 0; break; + case GL_ARRAY_BUFFER_BINDING: *params = context->arrayBuffer; break; + case GL_FRAMEBUFFER_BINDING: *params = context->framebuffer; break; + case GL_RENDERBUFFER_BINDING: *params = context->renderbuffer; break; + case GL_CURRENT_PROGRAM: *params = context->currentProgram; break; + case GL_RED_BITS: + case GL_GREEN_BITS: + case GL_BLUE_BITS: + case GL_ALPHA_BITS: + { + gl::Framebuffer *framebuffer = context->getFramebuffer(); + gl::Colorbuffer *colorbuffer = framebuffer->getColorbuffer(); + + if (colorbuffer) + { + switch (pname) + { + case GL_RED_BITS: *params = colorbuffer->getRedSize(); break; + case GL_GREEN_BITS: *params = colorbuffer->getGreenSize(); break; + case GL_BLUE_BITS: *params = colorbuffer->getBlueSize(); break; + case GL_ALPHA_BITS: *params = colorbuffer->getAlphaSize(); break; + } + } + else + { + *params = 0; + } + } + break; + case GL_DEPTH_BITS: + { + gl::Framebuffer *framebuffer = context->getFramebuffer(); + gl::Depthbuffer *depthbuffer = framebuffer->getDepthbuffer(); + + if (depthbuffer) + { + *params = depthbuffer->getDepthSize(); + } + else + { + *params = 0; + } + } + break; + case GL_STENCIL_BITS: + { + gl::Framebuffer *framebuffer = context->getFramebuffer(); + gl::Stencilbuffer *stencilbuffer = framebuffer->getStencilbuffer(); + + if (stencilbuffer) + { + *params = stencilbuffer->getStencilSize(); + } + else + { + *params = 0; + } + } + break; + default: + UNIMPLEMENTED(); // FIXME + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramiv(GLuint program, GLenum pname, GLint* params) +{ + TRACE("GLuint program = %d, GLenum pname = %d, GLint* params = 0x%0.8p", program, pname, params); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_DELETE_STATUS: + UNIMPLEMENTED(); // FIXME + *params = GL_FALSE; + return; + case GL_LINK_STATUS: + *params = programObject->isLinked(); + return; + case GL_VALIDATE_STATUS: + UNIMPLEMENTED(); // FIXME + *params = GL_TRUE; + return; + case GL_INFO_LOG_LENGTH: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + case GL_ATTACHED_SHADERS: + UNIMPLEMENTED(); // FIXME + *params = 2; + return; + case GL_ACTIVE_ATTRIBUTES: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + case GL_ACTIVE_ATTRIBUTE_MAX_LENGTH: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + case GL_ACTIVE_UNIFORMS: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + case GL_ACTIVE_UNIFORM_MAX_LENGTH: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, char* infolog) +{ + TRACE("GLuint program = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, char* infolog = 0x%0.8p", program, bufsize, length, infolog); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetRenderbufferParameteriv(GLenum target, GLenum pname, GLint* params) +{ + TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p", target, pname, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + TRACE("GLuint shader = %d, GLenum pname = %d, GLint* params = 0x%0.8p", shader, pname, params); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + switch (pname) + { + case GL_SHADER_TYPE: + *params = shaderObject->getType(); + return; + case GL_DELETE_STATUS: + UNIMPLEMENTED(); // FIXME + *params = GL_FALSE; + return; + case GL_COMPILE_STATUS: + *params = shaderObject->isCompiled() ? GL_TRUE : GL_FALSE; + return; + case GL_INFO_LOG_LENGTH: + UNIMPLEMENTED(); // FIXME + *params = 0; + return; + case GL_SHADER_SOURCE_LENGTH: + UNIMPLEMENTED(); // FIXME + *params = 1; + return; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, char* infolog) +{ + TRACE("GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, char* infolog = 0x%0.8p", shader, bufsize, length, infolog); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderPrecisionFormat(GLenum shadertype, GLenum precisiontype, GLint* range, GLint* precision) +{ + TRACE("GLenum shadertype = 0x%X, GLenum precisiontype = 0x%X, GLint* range = 0x%0.8p, GLint* precision = 0x%0.8p", shadertype, precisiontype, range, precision); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetShaderSource(GLuint shader, GLsizei bufsize, GLsizei* length, char* source) +{ + TRACE("GLuint shader = %d, GLsizei bufsize = %d, GLsizei* length = 0x%0.8p, char* source = 0x%0.8p", shader, bufsize, length, source); + + try + { + if (bufsize < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +const GLubyte* __stdcall glGetString(GLenum name) +{ + TRACE("GLenum name = 0x%X", name); + + try + { + switch (name) + { + case GL_VENDOR: + return (GLubyte*)"TransGaming Inc."; + case GL_RENDERER: + return (GLubyte*)"ANGLE"; + case GL_VERSION: + return (GLubyte*)"OpenGL ES 2.0 (git-devel "__DATE__ " " __TIME__")"; + case GL_SHADING_LANGUAGE_VERSION: + return (GLubyte*)"OpenGL ES GLSL ES 1.00 (git-devel "__DATE__ " " __TIME__")"; + case GL_EXTENSIONS: + return (GLubyte*)""; + default: + return error(GL_INVALID_ENUM, (GLubyte*)NULL); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, (GLubyte*)NULL); + } + + return NULL; +} + +void __stdcall glGetTexParameterfv(GLenum target, GLenum pname, GLfloat* params) +{ + TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p", target, pname, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetTexParameteriv(GLenum target, GLenum pname, GLint* params) +{ + TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLint* params = 0x%0.8p", target, pname, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformfv(GLuint program, GLint location, GLfloat* params) +{ + TRACE("GLuint program = %d, GLint location = %d, GLfloat* params = 0x%0.8p", program, location, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetUniformiv(GLuint program, GLint location, GLint* params) +{ + TRACE("GLuint program = %d, GLint location = %d, GLint* params = 0x%0.8p", program, location, params); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +int __stdcall glGetUniformLocation(GLuint program, const char* name) +{ + TRACE("GLuint program = %d, const char* name = 0x%0.8p", program, name); + + try + { + gl::Context *context = gl::getContext(); + + if (strstr(name, "gl_") == name) + { + return -1; + } + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE, -1); + } + + if (!programObject->isLinked()) + { + return error(GL_INVALID_OPERATION, -1); + } + + return programObject->getUniformLocation(name); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, -1); + } + + return -1; +} + +void __stdcall glGetVertexAttribfv(GLuint index, GLenum pname, GLfloat* params) +{ + TRACE("GLuint index = %d, GLenum pname = 0x%X, GLfloat* params = 0x%0.8p", index, pname, params); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribiv(GLuint index, GLenum pname, GLint* params) +{ + TRACE("GLuint index = %d, GLenum pname = 0x%X, GLint* params = 0x%0.8p", index, pname, params); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glGetVertexAttribPointerv(GLuint index, GLenum pname, void** pointer) +{ + TRACE("GLuint index = %d, GLenum pname = 0x%X, void** pointer = 0x%0.8p", index, pname, pointer); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glHint(GLenum target, GLenum mode) +{ + TRACE("GLenum target = 0x%X, GLenum mode = 0x%X", target, mode); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +GLboolean __stdcall glIsBuffer(GLuint buffer) +{ + TRACE("GLuint buffer = %d", buffer); + + try + { + gl::Context *context = gl::getContext(); + + if (context && buffer) + { + gl::Buffer *bufferObject = context->getBuffer(buffer); + + if (bufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsEnabled(GLenum cap) +{ + TRACE("GLenum cap = 0x%X", cap); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + switch (cap) + { + case GL_CULL_FACE: return context->cullFace; + case GL_POLYGON_OFFSET_FILL: return context->polygonOffsetFill; + case GL_SAMPLE_ALPHA_TO_COVERAGE: return context->sampleAlphaToCoverage; + case GL_SAMPLE_COVERAGE: return context->sampleCoverage; + case GL_SCISSOR_TEST: return context->scissorTest; + case GL_STENCIL_TEST: return context->stencilTest; + case GL_DEPTH_TEST: return context->depthTest; + case GL_BLEND: return context->blend; + case GL_DITHER: return context->dither; + default: + return error(GL_INVALID_ENUM, false); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, false); + } + + return false; +} + +GLboolean __stdcall glIsFramebuffer(GLuint framebuffer) +{ + TRACE("GLuint framebuffer = %d", framebuffer); + + try + { + gl::Context *context = gl::getContext(); + + if (context && framebuffer) + { + gl::Framebuffer *framebufferObject = context->getFramebuffer(framebuffer); + + if (framebufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsProgram(GLuint program) +{ + TRACE("GLuint program = %d", program); + + try + { + gl::Context *context = gl::getContext(); + + if (context && program) + { + gl::Program *programObject = context->getProgram(program); + + if (programObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsRenderbuffer(GLuint renderbuffer) +{ + TRACE("GLuint renderbuffer = %d", renderbuffer); + + try + { + gl::Context *context = gl::getContext(); + + if (context && renderbuffer) + { + gl::Renderbuffer *renderbufferObject = context->getRenderbuffer(renderbuffer); + + if (renderbufferObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsShader(GLuint shader) +{ + TRACE("GLuint shader = %d", shader); + + try + { + gl::Context *context = gl::getContext(); + + if (context && shader) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (shaderObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +GLboolean __stdcall glIsTexture(GLuint texture) +{ + TRACE("GLuint texture = %d", texture); + + try + { + gl::Context *context = gl::getContext(); + + if (context && texture) + { + gl::Texture *textureObject = context->getTexture(texture); + + if (textureObject) + { + return GL_TRUE; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY, GL_FALSE); + } + + return GL_FALSE; +} + +void __stdcall glLineWidth(GLfloat width) +{ + TRACE("GLfloat width = %f", width); + + try + { + if (width <= 0.0f) + { + return error(GL_INVALID_VALUE); + } + + if (width != 1.0f) + { + UNIMPLEMENTED(); // FIXME + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glLinkProgram(GLuint program) +{ + TRACE("GLuint program = %d", program); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (!programObject) + { + return error(GL_INVALID_VALUE); + } + + programObject->link(); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPixelStorei(GLenum pname, GLint param) +{ + TRACE("GLenum pname = 0x%X, GLint param = %d", pname, param); + + try + { + switch (pname) + { + case GL_UNPACK_ALIGNMENT: + // UNIMPLEMENTED(); // FIXME + break; + case GL_PACK_ALIGNMENT: + // UNIMPLEMENTED(); // FIXME + break; + default: + return error(GL_INVALID_ENUM); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glPolygonOffset(GLfloat factor, GLfloat units) +{ + TRACE("GLfloat factor = %f, GLfloat units = %f", factor, units); + + try + { + if (factor != 0.0f || units != 0.0f) + { + UNIMPLEMENTED(); // FIXME + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReadPixels(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void* pixels) +{ + TRACE("GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, void* pixels = 0x%0.8p", x, y, width, height, format, type, pixels); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + switch (format) + { + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + case gl::IMPLEMENTATION_COLOR_READ_FORMAT: + switch (type) + { + case gl::IMPLEMENTATION_COLOR_READ_TYPE: + break; + default: + return error(GL_INVALID_OPERATION); + } + break; + default: + return error(GL_INVALID_OPERATION); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->readPixels(x, y, width, height, format, type, pixels); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glReleaseShaderCompiler(void) +{ + TRACE(""); + + try + { + gl::Shader::releaseCompiler(); + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glRenderbufferStorage(GLenum target, GLenum internalformat, GLsizei width, GLsizei height) +{ + TRACE("GLenum target = 0x%X, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d", target, internalformat, width, height); + + try + { + switch (target) + { + case GL_RENDERBUFFER: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + case GL_STENCIL_INDEX8: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (width < 0 || height < 0 || width > gl::MAX_RENDERBUFFER_SIZE || height > gl::MAX_RENDERBUFFER_SIZE) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (context->framebuffer == 0 || context->renderbuffer == 0) + { + return error(GL_INVALID_OPERATION); + } + + switch (internalformat) + { + case GL_DEPTH_COMPONENT16: + context->setRenderbuffer(new gl::Depthbuffer(width, height)); + break; + case GL_RGBA4: + case GL_RGB5_A1: + case GL_RGB565: + UNIMPLEMENTED(); // FIXME + // context->setRenderbuffer(new Colorbuffer(renderTarget)); + break; + case GL_STENCIL_INDEX8: + UNIMPLEMENTED(); // FIXME + // context->setRenderbuffer(new Stencilbuffer(depthStencil)); + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glSampleCoverage(GLclampf value, GLboolean invert) +{ + TRACE("GLclampf value = %f, GLboolean invert = %d", value, invert); + + try + { + gl::Context* context = gl::getContext(); + + if (context) + { + context->sampleCoverageValue = gl::clamp01(value); + context->sampleCoverageInvert = invert; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glScissor(GLint x, GLint y, GLsizei width, GLsizei height) +{ + TRACE("GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context* context = gl::getContext(); + + if (context) + { + context->scissorX = x; + context->scissorY = y; + context->scissorWidth = width; + context->scissorHeight = height; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderBinary(GLsizei n, const GLuint* shaders, GLenum binaryformat, const void* binary, GLsizei length) +{ + TRACE("GLsizei n = %d, const GLuint* shaders = 0x%0.8p, GLenum binaryformat = 0x%X, const void* binary = 0x%0.8p, GLsizei length = %d", + n, shaders, binaryformat, binary, length); + + try + { + if (n < 0 || length < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glShaderSource(GLuint shader, GLsizei count, const char** string, const GLint* length) +{ + TRACE("GLuint shader = %d, GLsizei count = %d, const char** string = 0x%0.8p, const GLint* length = 0x%0.8p", shader, count, string, length); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Shader *shaderObject = context->getShader(shader); + + if (!shaderObject) + { + return error(GL_INVALID_VALUE); + } + + shaderObject->setSource(count, string, length); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilFunc(GLenum func, GLint ref, GLuint mask) +{ + glStencilFuncSeparate(GL_FRONT_AND_BACK, func, ref, mask); +} + +void __stdcall glStencilFuncSeparate(GLenum face, GLenum func, GLint ref, GLuint mask) +{ + TRACE("GLenum face = 0x%X, GLenum func = 0x%X, GLint ref = %d, GLuint mask = %d", face, func, ref, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (func) + { + case GL_NEVER: + case GL_ALWAYS: + case GL_LESS: + case GL_LEQUAL: + case GL_EQUAL: + case GL_GEQUAL: + case GL_GREATER: + case GL_NOTEQUAL: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->stencilFunc = func; + context->stencilRef = ref; + context->stencilMask = mask; + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->stencilBackFunc = func; + context->stencilBackRef = ref; + context->stencilBackMask = mask; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilMask(GLuint mask) +{ + glStencilMaskSeparate(GL_FRONT_AND_BACK, mask); +} + +void __stdcall glStencilMaskSeparate(GLenum face, GLuint mask) +{ + TRACE("GLenum face = 0x%X, GLuint mask = %d", face, mask); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->stencilWritemask = mask; + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->stencilBackWritemask = mask; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glStencilOp(GLenum fail, GLenum zfail, GLenum zpass) +{ + glStencilOpSeparate(GL_FRONT_AND_BACK, fail, zfail, zpass); +} + +void __stdcall glStencilOpSeparate(GLenum face, GLenum fail, GLenum zfail, GLenum zpass) +{ + TRACE("GLenum face = 0x%X, GLenum fail = 0x%X, GLenum zfail = 0x%X, GLenum zpas = 0x%Xs", face, fail, zfail, zpass); + + try + { + switch (face) + { + case GL_FRONT: + case GL_BACK: + case GL_FRONT_AND_BACK: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (fail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zfail) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (zpass) + { + case GL_ZERO: + case GL_KEEP: + case GL_REPLACE: + case GL_INCR: + case GL_DECR: + case GL_INVERT: + case GL_INCR_WRAP: + case GL_DECR_WRAP: + break; + default: + return error(GL_INVALID_ENUM); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (face == GL_FRONT || face == GL_FRONT_AND_BACK) + { + context->stencilFail = fail; + context->stencilPassDepthFail = zfail; + context->stencilPassDepthPass = zpass; + } + + if (face == GL_BACK || face == GL_FRONT_AND_BACK) + { + context->stencilBackFail = fail; + context->stencilBackPassDepthFail = zfail; + context->stencilBackPassDepthPass = zpass; + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void* pixels) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLint internalformat = %d, GLsizei width = %d, GLsizei height = %d, GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%X, const void* pixels = 0x%0.8p", target, level, internalformat, width, height, border, format, type, pixels); + + try + { + if (level < 0 || width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + if (level > 0 && (!gl::isPow2(width) || !gl::isPow2(height))) + { + return error(GL_INVALID_VALUE); + } + + switch (target) + { + case GL_TEXTURE_2D: + if (width > (gl::MAX_TEXTURE_SIZE >> level) || height > (gl::MAX_TEXTURE_SIZE >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + if (!gl::isPow2(width) || !gl::isPow2(height)) + { + return error(GL_INVALID_VALUE); + } + + if (width > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level) || height > (gl::MAX_CUBE_MAP_TEXTURE_SIZE >> level)) + { + return error(GL_INVALID_VALUE); + } + break; + default: + return error(GL_INVALID_ENUM); + } + + if (internalformat != format) + { + return error(GL_INVALID_OPERATION); + } + + switch (internalformat) + { + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + switch (type) + { + case GL_UNSIGNED_BYTE: + break; + default: + return error(GL_INVALID_ENUM); + } + break; + case GL_RGB: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_5_6_5: + break; + default: + return error(GL_INVALID_ENUM); + } + break; + case GL_RGBA: + switch (type) + { + case GL_UNSIGNED_BYTE: + case GL_UNSIGNED_SHORT_4_4_4_4: + case GL_UNSIGNED_SHORT_5_5_5_1: + break; + default: + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_VALUE); + } + + if (border != 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + if (target == GL_TEXTURE_2D) + { + gl::Texture2D *texture = context->getTexture2D(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + texture->setImage(level, internalformat, width, height, format, type, pixels); + } + else + { + gl::TextureCubeMap *texture = context->getTextureCubeMap(); + + if (!texture) + { + return error(GL_INVALID_OPERATION); + } + + switch (target) + { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + texture->setImagePosX(level, internalformat, width, height, format, type, pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + texture->setImageNegX(level, internalformat, width, height, format, type, pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + texture->setImagePosY(level, internalformat, width, height, format, type, pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + texture->setImageNegY(level, internalformat, width, height, format, type, pixels); + break; + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + texture->setImagePosZ(level, internalformat, width, height, format, type, pixels); + break; + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + texture->setImageNegZ(level, internalformat, width, height, format, type, pixels); + break; + default: UNREACHABLE(); + } + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameterf(GLenum target, GLenum pname, GLfloat param) +{ + glTexParameteri(target, pname, (GLint)param); +} + +void __stdcall glTexParameterfv(GLenum target, GLenum pname, const GLfloat* params) +{ + glTexParameteri(target, pname, (GLint)*params); +} + +void __stdcall glTexParameteri(GLenum target, GLenum pname, GLint param) +{ + TRACE("GLenum target = 0x%X, GLenum pname = 0x%X, GLfloat param = %f", target, pname, param); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Texture *texture; + + switch (target) + { + case GL_TEXTURE_2D: + texture = context->getTexture2D(); + break; + case GL_TEXTURE_CUBE_MAP: + texture = context->getTextureCubeMap(); + break; + default: + return error(GL_INVALID_ENUM); + } + + switch (pname) + { + case GL_TEXTURE_WRAP_S: + if (!texture->setWrapS((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_WRAP_T: + if (!texture->setWrapT((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MIN_FILTER: + if (!texture->setMinFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + case GL_TEXTURE_MAG_FILTER: + if (!texture->setMagFilter((GLenum)param)) + { + return error(GL_INVALID_ENUM); + } + break; + default: + return error(GL_INVALID_ENUM); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexParameteriv(GLenum target, GLenum pname, const GLint* params) +{ + glTexParameteri(target, pname, *params); +} + +void __stdcall glTexSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const void* pixels) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLint xoffset = %d, GLint yoffset = %d, GLsizei width = %d, GLsizei height = %d, GLenum format = 0x%X, GLenum type = 0x%X, const void* pixels = 0x%0.8p", + target, level, xoffset, yoffset, width, height, format, type, pixels); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1f(GLint location, GLfloat x) +{ + glUniform1fv(location, 1, &x); +} + +void __stdcall glUniform1fv(GLint location, GLsizei count, const GLfloat* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p", location, count, v); + + try + { + if (location == -1) + { + return; + } + + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniform1fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform1i(GLint location, GLint x) +{ + glUniform1iv(location, 1, &x); +} + +void __stdcall glUniform1iv(GLint location, GLsizei count, const GLint* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniform1iv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2f(GLint location, GLfloat x, GLfloat y) +{ + GLfloat xy[2] = {x, y}; + + glUniform2fv(location, 1, (GLfloat*)&xy); +} + +void __stdcall glUniform2fv(GLint location, GLsizei count, const GLfloat* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p", location, count, v); + + try + { + if (location == -1) + { + return; + } + + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniform2fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform2i(GLint location, GLint x, GLint y) +{ + GLint xy[4] = {x, y}; + + glUniform2iv(location, 1, (GLint*)&xy); +} + +void __stdcall glUniform2iv(GLint location, GLsizei count, const GLint* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3f(GLint location, GLfloat x, GLfloat y, GLfloat z) +{ + GLfloat xyz[3] = {x, y, z}; + + glUniform3fv(location, 1, (GLfloat*)&xyz); +} + +void __stdcall glUniform3fv(GLint location, GLsizei count, const GLfloat* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniform3fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform3i(GLint location, GLint x, GLint y, GLint z) +{ + GLint xyz[3] = {x, y, z}; + + glUniform3iv(location, 1, (GLint*)&xyz); +} + +void __stdcall glUniform3iv(GLint location, GLsizei count, const GLint* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4f(GLint location, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GLfloat xyzw[4] = {x, y, z, w}; + + glUniform4fv(location, 1, (GLfloat*)&xyzw); +} + +void __stdcall glUniform4fv(GLint location, GLsizei count, const GLfloat* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLfloat* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniform4fv(location, count, v)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniform4i(GLint location, GLint x, GLint y, GLint z, GLint w) +{ + GLint xyzw[4] = {x, y, z, w}; + + glUniform4iv(location, 1, (GLint*)&xyzw); +} + +void __stdcall glUniform4iv(GLint location, GLsizei count, const GLint* v) +{ + TRACE("GLint location = %d, GLsizei count = %d, const GLint* v = 0x%0.8p", location, count, v); + + try + { + if (count < 0) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + TRACE("GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p", location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniformMatrix2fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + TRACE("GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p", location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniformMatrix3fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat* value) +{ + TRACE("GLint location = %d, GLsizei count = %d, GLboolean transpose = %d, const GLfloat* value = 0x%0.8p", location, count, transpose, value); + + try + { + if (count < 0 || transpose != GL_FALSE) + { + return error(GL_INVALID_VALUE); + } + + if (location == -1) + { + return; + } + + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *program = context->getCurrentProgram(); + + if (!program) + { + return error(GL_INVALID_OPERATION); + } + + if (!program->setUniformMatrix4fv(location, count, value)) + { + return error(GL_INVALID_OPERATION); + } + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glUseProgram(GLuint program) +{ + TRACE("GLuint program = %d", program); + + try + { + gl::Context *context = gl::getContext(); + + if (context) + { + gl::Program *programObject = context->getProgram(program); + + if (programObject && !programObject->isLinked()) + { + return error(GL_INVALID_OPERATION); + } + + context->useProgram(program); + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glValidateProgram(GLuint program) +{ + TRACE("GLuint program = %d", program); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1f(GLuint index, GLfloat x) +{ + TRACE("GLuint index = %d, GLfloat x = %f", index, x); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib1fv(GLuint index, const GLfloat* values) +{ + TRACE("GLuint index = %d, const GLfloat* values = 0x%0.8p", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2f(GLuint index, GLfloat x, GLfloat y) +{ + TRACE("GLuint index = %d, GLfloat x = %f, GLfloat y = %f", index, x, y); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib2fv(GLuint index, const GLfloat* values) +{ + TRACE("GLuint index = %d, const GLfloat* values = 0x%0.8p", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3f(GLuint index, GLfloat x, GLfloat y, GLfloat z) +{ + TRACE("GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f", index, x, y, z); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib3fv(GLuint index, const GLfloat* values) +{ + TRACE("GLuint index = %d, const GLfloat* values = 0x%0.8p", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4f(GLuint index, GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + TRACE("GLuint index = %d, GLfloat x = %f, GLfloat y = %f, GLfloat z = %f, GLfloat w = %f", index, x, y, z, w); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttrib4fv(GLuint index, const GLfloat* values) +{ + TRACE("GLuint index = %d, const GLfloat* values = 0x%0.8p", index, values); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glVertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* ptr) +{ + TRACE("GLuint index = %d, GLint size = %d, GLenum type = 0x%X, GLboolean normalized = %d, GLsizei stride = %d, const void* ptr = 0x%0.8p", index, size, type, normalized, stride, ptr); + + try + { + if (index >= gl::MAX_VERTEX_ATTRIBS) + { + return error(GL_INVALID_VALUE); + } + + if (size < 1 || size > 4) + { + return error(GL_INVALID_VALUE); + } + + switch (type) + { + case GL_BYTE: + case GL_UNSIGNED_BYTE: + case GL_SHORT: + case GL_UNSIGNED_SHORT: + case GL_FIXED: + case GL_FLOAT: + break; + default: + return error(GL_INVALID_ENUM); + } + + if (stride < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->vertexAttribute[index].boundBuffer = context->arrayBuffer; + context->vertexAttribute[index].size = size; + context->vertexAttribute[index].type = type; + context->vertexAttribute[index].normalized = normalized; + context->vertexAttribute[index].stride = stride; + context->vertexAttribute[index].pointer = ptr; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glViewport(GLint x, GLint y, GLsizei width, GLsizei height) +{ + TRACE("GLint x = %d, GLint y = %d, GLsizei width = %d, GLsizei height = %d", x, y, width, height); + + try + { + if (width < 0 || height < 0) + { + return error(GL_INVALID_VALUE); + } + + gl::Context *context = gl::getContext(); + + if (context) + { + context->viewportX = x; + context->viewportY = y; + context->viewportWidth = width; + context->viewportHeight = height; + } + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} + +void __stdcall glTexImage3DOES(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLenum format, GLenum type, const void* pixels) +{ + TRACE("GLenum target = 0x%X, GLint level = %d, GLenum internalformat = 0x%X, GLsizei width = %d, GLsizei height = %d, GLsizei depth = %d, GLint border = %d, GLenum format = 0x%X, GLenum type = 0x%x, const void* pixels = 0x%0.8p", + target, level, internalformat, width, height, depth, border, format, type, pixels); + + try + { + UNIMPLEMENTED(); // FIXME + } + catch(std::bad_alloc&) + { + return error(GL_OUT_OF_MEMORY); + } +} +} diff --git a/libGLESv2/libGLESv2.def b/libGLESv2/libGLESv2.def new file mode 100644 index 000000000..2ae969f3c --- /dev/null +++ b/libGLESv2/libGLESv2.def @@ -0,0 +1,153 @@ +LIBRARY libGLESv2 +EXPORTS + glActiveTexture @1 + glAttachShader @2 + glBindAttribLocation @3 + glBindBuffer @4 + glBindFramebuffer @5 + glBindRenderbuffer @6 + glBindTexture @7 + glBlendColor @8 + glBlendEquation @9 + glBlendEquationSeparate @10 + glBlendFunc @11 + glBlendFuncSeparate @12 + glBufferData @13 + glBufferSubData @14 + glCheckFramebufferStatus @15 + glClear @16 + glClearColor @17 + glClearDepthf @18 + glClearStencil @19 + glColorMask @20 + glCompileShader @21 + glCompressedTexImage2D @22 + glCompressedTexSubImage2D @23 + glCopyTexImage2D @24 + glCopyTexSubImage2D @25 + glCreateProgram @26 + glCreateShader @27 + glCullFace @28 + glDeleteBuffers @29 + glDeleteFramebuffers @30 + glDeleteProgram @32 + glDeleteRenderbuffers @33 + glDeleteShader @34 + glDeleteTextures @31 + glDepthFunc @36 + glDepthMask @37 + glDepthRangef @38 + glDetachShader @35 + glDisable @39 + glDisableVertexAttribArray @40 + glDrawArrays @41 + glDrawElements @42 + glEnable @43 + glEnableVertexAttribArray @44 + glFinish @45 + glFlush @46 + glFramebufferRenderbuffer @47 + glFramebufferTexture2D @48 + glFrontFace @49 + glGenBuffers @50 + glGenFramebuffers @52 + glGenRenderbuffers @53 + glGenTextures @54 + glGenerateMipmap @51 + glGetActiveAttrib @55 + glGetActiveUniform @56 + glGetAttachedShaders @57 + glGetAttribLocation @58 + glGetBooleanv @59 + glGetBufferParameteriv @60 + glGetError @61 + glGetFloatv @62 + glGetFramebufferAttachmentParameteriv @63 + glGetIntegerv @64 + glGetProgramInfoLog @66 + glGetProgramiv @65 + glGetRenderbufferParameteriv @67 + glGetShaderInfoLog @69 + glGetShaderPrecisionFormat @70 + glGetShaderSource @71 + glGetShaderiv @68 + glGetString @72 + glGetTexParameterfv @73 + glGetTexParameteriv @74 + glGetUniformLocation @77 + glGetUniformfv @75 + glGetUniformiv @76 + glGetVertexAttribPointerv @80 + glGetVertexAttribfv @78 + glGetVertexAttribiv @79 + glHint @81 + glIsBuffer @82 + glIsEnabled @83 + glIsFramebuffer @84 + glIsProgram @85 + glIsRenderbuffer @86 + glIsShader @87 + glIsTexture @88 + glLineWidth @89 + glLinkProgram @90 + glPixelStorei @91 + glPolygonOffset @92 + glReadPixels @93 + glReleaseShaderCompiler @94 + glRenderbufferStorage @95 + glSampleCoverage @96 + glScissor @97 + glShaderBinary @98 + glShaderSource @99 + glStencilFunc @100 + glStencilFuncSeparate @101 + glStencilMask @102 + glStencilMaskSeparate @103 + glStencilOp @104 + glStencilOpSeparate @105 + glTexImage2D @106 + glTexParameterf @107 + glTexParameterfv @108 + glTexParameteri @109 + glTexParameteriv @110 + glTexSubImage2D @111 + glUniform1f @112 + glUniform1fv @113 + glUniform1i @114 + glUniform1iv @115 + glUniform2f @116 + glUniform2fv @117 + glUniform2i @118 + glUniform2iv @119 + glUniform3f @120 + glUniform3fv @121 + glUniform3i @122 + glUniform3iv @123 + glUniform4f @124 + glUniform4fv @125 + glUniform4i @126 + glUniform4iv @127 + glUniformMatrix2fv @128 + glUniformMatrix3fv @129 + glUniformMatrix4fv @130 + glUseProgram @131 + glValidateProgram @132 + glVertexAttrib1f @133 + glVertexAttrib1fv @134 + glVertexAttrib2f @135 + glVertexAttrib2fv @136 + glVertexAttrib3f @137 + glVertexAttrib3fv @138 + glVertexAttrib4f @139 + glVertexAttrib4fv @140 + glVertexAttribPointer @141 + glViewport @142 + + ; Extensions + glTexImage3DOES @143 + + ; EGL dependencies + glCreateContext @144 NONAME + glDestroyContext @145 NONAME + glMakeCurrent @146 NONAME + glGetCurrentContext @147 NONAME \ No newline at end of file diff --git a/libGLESv2/libGLESv2.vcproj b/libGLESv2/libGLESv2.vcproj new file mode 100644 index 000000000..9752c42df --- /dev/null +++ b/libGLESv2/libGLESv2.vcproj @@ -0,0 +1,331 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/libGLESv2/main.cpp b/libGLESv2/main.cpp new file mode 100644 index 000000000..d7290382f --- /dev/null +++ b/libGLESv2/main.cpp @@ -0,0 +1,136 @@ +// +// Copyright (c) 2002-2010 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. +// + +// main.cpp: DLL entry point and management of thread-local data. + +#include "main.h" + +#include "Framebuffer.h" +#include "Surface.h" +#include "debug.h" + +static DWORD currentTLS = TLS_OUT_OF_INDEXES; + +BOOL WINAPI DllMain(HINSTANCE instance, DWORD reason, LPVOID reserved) +{ + switch (reason) + { + case DLL_PROCESS_ATTACH: + { + currentTLS = TlsAlloc(); + + if (currentTLS == TLS_OUT_OF_INDEXES) + { + return FALSE; + } + } + // Fall throught to initialize index + case DLL_THREAD_ATTACH: + { + gl::Current *current = (gl::Current*)LocalAlloc(LPTR, sizeof(gl::Current)); + + if (current) + { + TlsSetValue(currentTLS, current); + + current->context = NULL; + current->display = NULL; + } + } + break; + case DLL_THREAD_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + } + break; + case DLL_PROCESS_DETACH: + { + void *current = TlsGetValue(currentTLS); + + if (current) + { + LocalFree((HLOCAL)current); + } + + TlsFree(currentTLS); + } + break; + default: + break; + } + + return TRUE; +} + +namespace gl +{ +void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface) +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + current->context = context; + current->display = display; + + if (context && display && surface) + { + context->makeCurrent(display, surface); + } +} + +Context *getContext() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + + return current->context; +} + +IDirect3DDevice9 *getDevice() +{ + Current *current = (Current*)TlsGetValue(currentTLS); + egl::Display *display = current->display; + + return display->getDevice(); +} +} + +// Records an error code +void error(GLenum errorCode) +{ + gl::Context *context = glGetCurrentContext(); + + if (context) + { + switch (errorCode) + { + case GL_INVALID_ENUM: + context->recordInvalidEnum(); + gl::trace("\t! Error generated: invalid enum\n"); + break; + case GL_INVALID_VALUE: + context->recordInvalidValue(); + gl::trace("\t! Error generated: invalid value\n"); + break; + case GL_INVALID_OPERATION: + context->recordInvalidOperation(); + gl::trace("\t! Error generated: invalid operation\n"); + break; + case GL_OUT_OF_MEMORY: + context->recordOutOfMemory(); + gl::trace("\t! Error generated: out of memory\n"); + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + context->recordInvalidFramebufferOperation(); + gl::trace("\t! Error generated: invalid framebuffer operation\n"); + break; + default: UNREACHABLE(); + } + } +} diff --git a/libGLESv2/main.h b/libGLESv2/main.h new file mode 100644 index 000000000..d8cc5c237 --- /dev/null +++ b/libGLESv2/main.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2002-2010 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. +// + +// main.h: Management of thread-local data. + +#ifndef LIBGLESV2_MAIN_H_ +#define LIBGLESV2_MAIN_H_ + +#define GL_APICALL +#include + +#include "Context.h" +#include "Display.h" +#include "debug.h" + +namespace gl +{ +struct Current +{ + Context *context; + egl::Display *display; +}; + +void makeCurrent(Context *context, egl::Display *display, egl::Surface *surface); + +Context *getContext(); +egl::Display *getDisplay(); + +IDirect3DDevice9 *getDevice(); +} + +void error(GLenum errorCode); + +template +const T &error(GLenum errorCode, const T &returnValue) +{ + error(errorCode); + + return returnValue; +} + +#endif // LIBGLESV2_MAIN_H_ diff --git a/libGLESv2/mathutil.h b/libGLESv2/mathutil.h new file mode 100644 index 000000000..93c9945c9 --- /dev/null +++ b/libGLESv2/mathutil.h @@ -0,0 +1,53 @@ +// +// Copyright (c) 2002-2010 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. +// + +// mathutil.h: Math and bit manipulation functions. + +#ifndef LIBGLESV2_MATHUTIL_H_ +#define LIBGLESV2_MATHUTIL_H_ + +#include + +namespace gl +{ +inline bool isPow2(int x) +{ + return (x & (x - 1)) == 0 && (x != 0); +} + +inline int log2(int x) +{ + int r = 0; + while((x >> r) > 1) r++; + return r; +} + +inline float clamp01(float x) +{ + return x < 0 ? 0 : (x > 1 ? 1 : x); +} + +template +inline unsigned int unorm(float x) +{ + const unsigned int max = 0xFFFFFFFF >> (32 - n); + + if(x > 1) + { + return max; + } + else if(x < 0) + { + return 0; + } + else + { + return (unsigned int)(max * x + 0.5f); + } +} +} + +#endif // LIBGLESV2_MATHUTIL_H_ diff --git a/libGLESv2/utilities.cpp b/libGLESv2/utilities.cpp new file mode 100644 index 000000000..4c604f944 --- /dev/null +++ b/libGLESv2/utilities.cpp @@ -0,0 +1,358 @@ +// +// Copyright (c) 2002-2010 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. +// + +// utilities.cpp: Conversion functions and other utility routines. + +#include "utilities.h" + +#include "debug.h" +#include "mathutil.h" +#include "Context.h" + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison) +{ + D3DCMPFUNC d3dComp = D3DCMP_ALWAYS; + switch (comparison) + { + case GL_NEVER: d3dComp = D3DCMP_NEVER; break; + case GL_ALWAYS: d3dComp = D3DCMP_ALWAYS; break; + case GL_LESS: d3dComp = D3DCMP_LESS; break; + case GL_LEQUAL: d3dComp = D3DCMP_LESSEQUAL; break; + case GL_EQUAL: d3dComp = D3DCMP_EQUAL; break; + case GL_GREATER: d3dComp = D3DCMP_GREATER; break; + case GL_GEQUAL: d3dComp = D3DCMP_GREATEREQUAL; break; + case GL_NOTEQUAL: d3dComp = D3DCMP_NOTEQUAL; break; + default: UNREACHABLE(); + } + + return d3dComp; +} + +D3DCOLOR ConvertColor(gl::Color color) +{ + return D3DCOLOR_RGBA(gl::unorm<8>(color.red), + gl::unorm<8>(color.blue), + gl::unorm<8>(color.green), + gl::unorm<8>(color.alpha)); +} + +D3DBLEND ConvertBlendFunc(GLenum blend) +{ + D3DBLEND d3dBlend = D3DBLEND_ZERO; + + switch (blend) + { + case GL_ZERO: d3dBlend = D3DBLEND_ZERO; break; + case GL_ONE: d3dBlend = D3DBLEND_ONE; break; + case GL_SRC_COLOR: d3dBlend = D3DBLEND_SRCCOLOR; break; + case GL_ONE_MINUS_SRC_COLOR: d3dBlend = D3DBLEND_INVSRCCOLOR; break; + case GL_DST_COLOR: d3dBlend = D3DBLEND_DESTCOLOR; break; + case GL_ONE_MINUS_DST_COLOR: d3dBlend = D3DBLEND_INVDESTCOLOR; break; + case GL_SRC_ALPHA: d3dBlend = D3DBLEND_SRCALPHA; break; + case GL_ONE_MINUS_SRC_ALPHA: d3dBlend = D3DBLEND_INVSRCALPHA; break; + case GL_DST_ALPHA: d3dBlend = D3DBLEND_DESTALPHA; break; + case GL_ONE_MINUS_DST_ALPHA: d3dBlend = D3DBLEND_INVDESTALPHA; break; + case GL_CONSTANT_COLOR: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_COLOR: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_CONSTANT_ALPHA: d3dBlend = D3DBLEND_BLENDFACTOR; break; + case GL_ONE_MINUS_CONSTANT_ALPHA: d3dBlend = D3DBLEND_INVBLENDFACTOR; break; + case GL_SRC_ALPHA_SATURATE: d3dBlend = D3DBLEND_SRCALPHASAT; break; + default: UNREACHABLE(); + } + + return d3dBlend; +} + +D3DBLENDOP ConvertBlendOp(GLenum blendOp) +{ + D3DBLENDOP d3dBlendOp = D3DBLENDOP_ADD; + + switch (blendOp) + { + case GL_FUNC_ADD: d3dBlendOp = D3DBLENDOP_ADD; break; + case GL_FUNC_SUBTRACT: d3dBlendOp = D3DBLENDOP_SUBTRACT; break; + case GL_FUNC_REVERSE_SUBTRACT: d3dBlendOp = D3DBLENDOP_REVSUBTRACT; break; + default: UNREACHABLE(); + } + + return d3dBlendOp; +} + +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp) +{ + D3DSTENCILOP d3dStencilOp = D3DSTENCILOP_KEEP; + + switch (stencilOp) + { + case GL_ZERO: d3dStencilOp = D3DSTENCILOP_ZERO; break; + case GL_KEEP: d3dStencilOp = D3DSTENCILOP_KEEP; break; + case GL_REPLACE: d3dStencilOp = D3DSTENCILOP_REPLACE; break; + case GL_INCR: d3dStencilOp = D3DSTENCILOP_INCRSAT; break; + case GL_DECR: d3dStencilOp = D3DSTENCILOP_DECRSAT; break; + case GL_INVERT: d3dStencilOp = D3DSTENCILOP_INVERT; break; + case GL_INCR_WRAP: d3dStencilOp = D3DSTENCILOP_INCR; break; + case GL_DECR_WRAP: d3dStencilOp = D3DSTENCILOP_DECR; break; + default: UNREACHABLE(); + } + + return d3dStencilOp; +} + +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap) +{ + D3DTEXTUREADDRESS d3dWrap = D3DTADDRESS_WRAP; + + switch (wrap) + { + case GL_REPEAT: d3dWrap = D3DTADDRESS_WRAP; break; + case GL_CLAMP_TO_EDGE: d3dWrap = D3DTADDRESS_CLAMP; break; + case GL_MIRRORED_REPEAT: d3dWrap = D3DTADDRESS_MIRROR; break; + default: UNREACHABLE(); + } + + return d3dWrap; +} + +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace) +{ + D3DCULL cull = D3DCULL_CCW; + switch (cullFace) + { + case GL_FRONT: + cull = (frontFace == GL_CCW ? D3DCULL_CW : D3DCULL_CCW); + break; + case GL_BACK: + cull = (frontFace == GL_CCW ? D3DCULL_CCW : D3DCULL_CW); + break; + case GL_FRONT_AND_BACK: + UNIMPLEMENTED(); // FIXME + break; + default: UNREACHABLE(); + } + + return cull; +} + +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha) +{ + return (red ? D3DCOLORWRITEENABLE_RED : 0) | + (green ? D3DCOLORWRITEENABLE_GREEN : 0) | + (blue ? D3DCOLORWRITEENABLE_BLUE : 0) | + (alpha ? D3DCOLORWRITEENABLE_ALPHA : 0); +} + +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter) +{ + D3DTEXTUREFILTERTYPE d3dMagFilter = D3DTEXF_POINT; + switch (magFilter) + { + case GL_NEAREST: d3dMagFilter = D3DTEXF_POINT; break; + case GL_LINEAR: d3dMagFilter = D3DTEXF_LINEAR; break; + default: UNREACHABLE(); + } + + return d3dMagFilter; +} + +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter) +{ + switch (minFilter) + { + case GL_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_LINEAR_MIPMAP_NEAREST: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_POINT; + break; + case GL_NEAREST_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + *d3dMinFilter = D3DTEXF_LINEAR; + *d3dMipFilter = D3DTEXF_LINEAR; + break; + default: + *d3dMinFilter = D3DTEXF_POINT; + *d3dMipFilter = D3DTEXF_NONE; + UNREACHABLE(); + } +} + +unsigned int GetStencilSize(D3DFORMAT stencilFormat) +{ + switch(stencilFormat) + { + case D3DFMT_D24FS8: + case D3DFMT_D24S8: + return 8; + case D3DFMT_D24X4S4: + return 4; + case D3DFMT_D15S1: + return 1; + case D3DFMT_D16_LOCKABLE: + case D3DFMT_D32: + case D3DFMT_D24X8: + case D3DFMT_D32F_LOCKABLE: + case D3DFMT_D16: + return 0; +// case D3DFMT_D32_LOCKABLE: return 0; // DirectX 9Ex only +// case D3DFMT_S8_LOCKABLE: return 8; // DirectX 9Ex only + default: UNREACHABLE(); + } + return 0; +} + +unsigned int GetAlphaSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A2R10G10B10: + return 2; + case D3DFMT_A8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + return 1; + case D3DFMT_X8R8G8B8: + case D3DFMT_X1R5G5B5: + case D3DFMT_R5G6B5: + return 0; + default: UNREACHABLE(); + } + return 0; +} + +unsigned int GetRedSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + return 5; + default: UNREACHABLE(); + } + return 0; +} + +unsigned int GetGreenSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_X1R5G5B5: + return 5; + case D3DFMT_R5G6B5: + return 6; + default: UNREACHABLE(); + } + return 0; +} + +unsigned int GetBlueSize(D3DFORMAT colorFormat) +{ + switch (colorFormat) + { + case D3DFMT_A2R10G10B10: + return 10; + case D3DFMT_A8R8G8B8: + case D3DFMT_X8R8G8B8: + return 8; + case D3DFMT_A1R5G5B5: + case D3DFMT_R5G6B5: + case D3DFMT_X1R5G5B5: + return 5; + default: UNREACHABLE(); + } + return 0; +} + +unsigned int GetDepthSize(D3DFORMAT depthFormat) +{ + switch (depthFormat) + { + case D3DFMT_D16_LOCKABLE: return 16; + case D3DFMT_D32: return 32; + case D3DFMT_D15S1: return 15; + case D3DFMT_D24S8: return 24; + case D3DFMT_D24X8: return 24; + case D3DFMT_D24X4S4: return 24; + case D3DFMT_D16: return 16; + case D3DFMT_D32F_LOCKABLE: return 32; + case D3DFMT_D24FS8: return 24; +// case D3DFMT_D32_LOCKABLE: return 32; // D3D9Ex only +// case D3DFMT_S8_LOCKABLE: return 0; // D3D9Ex only + default: + UNREACHABLE(); + } + return 0; +} + +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount) +{ + switch (primitiveType) + { + case GL_POINTS: + *d3dPrimitiveType = D3DPT_POINTLIST; + *d3dPrimitiveCount = primitiveCount; + break; + case GL_LINES: + *d3dPrimitiveType = D3DPT_LINELIST; + *d3dPrimitiveCount = primitiveCount / 2; + break; + case GL_LINE_LOOP: + UNIMPLEMENTED(); // FIXME: Emulate using an index buffer + *d3dPrimitiveType = D3DPT_LINELIST; + *d3dPrimitiveCount = primitiveCount; + break; + case GL_LINE_STRIP: + *d3dPrimitiveType = D3DPT_LINESTRIP; + *d3dPrimitiveCount = primitiveCount - 1; + break; + case GL_TRIANGLES: + *d3dPrimitiveType = D3DPT_TRIANGLELIST; + *d3dPrimitiveCount = primitiveCount / 3; + break; + case GL_TRIANGLE_STRIP: + *d3dPrimitiveType = D3DPT_TRIANGLESTRIP; + *d3dPrimitiveCount = primitiveCount - 2; + break; + case GL_TRIANGLE_FAN: + *d3dPrimitiveType = D3DPT_TRIANGLEFAN; + *d3dPrimitiveCount = primitiveCount - 2; + break; + default: + return false; + } + + return true; +} + +} diff --git a/libGLESv2/utilities.h b/libGLESv2/utilities.h new file mode 100644 index 000000000..2222f5b11 --- /dev/null +++ b/libGLESv2/utilities.h @@ -0,0 +1,45 @@ +// +// Copyright (c) 2002-2010 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. +// + +// utilities.h: Conversion functions and other utility routines. + +#ifndef LIBGLESV2_UTILITIES_H +#define LIBGLESV2_UTILITIES_H + +#define GL_APICALL +#include +#include + +namespace gl +{ +struct Color; +} + +namespace es2dx +{ + +D3DCMPFUNC ConvertComparison(GLenum comparison); +D3DCOLOR ConvertColor(gl::Color color); +D3DBLEND ConvertBlendFunc(GLenum blend); +D3DBLENDOP ConvertBlendOp(GLenum blendOp); +D3DSTENCILOP ConvertStencilOp(GLenum stencilOp); +D3DTEXTUREADDRESS ConvertTextureWrap(GLenum wrap); +D3DCULL ConvertCullMode(GLenum cullFace, GLenum frontFace); +DWORD ConvertColorMask(bool red, bool green, bool blue, bool alpha); +D3DTEXTUREFILTERTYPE ConvertMagFilter(GLenum magFilter); +void ConvertMinFilter(GLenum minFilter, D3DTEXTUREFILTERTYPE *d3dMinFilter, D3DTEXTUREFILTERTYPE *d3dMipFilter); +unsigned int GetAlphaSize(D3DFORMAT colorFormat); +unsigned int GetRedSize(D3DFORMAT colorFormat); +unsigned int GetGreenSize(D3DFORMAT colorFormat); +unsigned int GetBlueSize(D3DFORMAT colorFormat); +unsigned int GetDepthSize(D3DFORMAT depthFormat); +unsigned int GetStencilSize(D3DFORMAT stencilFormat); +bool ConvertPrimitiveType(GLenum primitiveType, GLsizei primitiveCount, + D3DPRIMITIVETYPE *d3dPrimitiveType, int *d3dPrimitiveCount); + +} + +#endif // LIBGLESV2_UTILITIES_H