Commit f561ca40 by Vladimir Vukicevic Committed by Shannon Woods

Implement EXT_shader_texture_lod

BUG=angle:551 Change-Id: Iecfa6e265939610fd8d8a54aef022f5d344d1be5 Reviewed-on: https://chromium-review.googlesource.com/185693Reviewed-by: 's avatarShannon Woods <shannonwoods@chromium.org> Tested-by: 's avatarShannon Woods <shannonwoods@chromium.org>
parent 5fdb492e
Name
EXT_shader_texture_lod
Name Strings
GL_EXT_shader_texture_lod
Contributors
Benj Lipchak
Ben Bowman
and contributors to the ARB_shader_texture_lod spec,
which provided the basis for this spec.
Contact
Benj Lipchak, Apple (lipchak 'at' apple.com)
IP Status
No known IP issues.
Status
Draft
Version
Last Modified Date: February 24, 2011
Revision: 3
Number
OpenGL ES Extension #77
Dependencies
This extension is written against the OpenGL ES 2.0 Specification.
This extension is written against The OpenGL ES Shading Language,
Language Version 1.00, Document Revision 17.
This extension interacts with EXT_texture_filter_anisotropic.
Overview
This extension adds additional texture functions to the
OpenGL ES Shading Language which provide the shader writer
with explicit control of LOD.
Mipmap texture fetches and anisotropic texture fetches
require implicit derivatives to calculate rho, lambda
and/or the line of anisotropy. These implicit derivatives
will be undefined for texture fetches occurring inside
non-uniform control flow or for vertex shader texture
fetches, resulting in undefined texels.
The additional texture functions introduced with
this extension provide explicit control of LOD
(isotropic texture functions) or provide explicit
derivatives (anisotropic texture functions).
Anisotropic texture functions return defined texels
for mipmap texture fetches or anisotropic texture fetches,
even inside non-uniform control flow. Isotropic texture
functions return defined texels for mipmap texture fetches,
even inside non-uniform control flow. However, isotropic
texture functions return undefined texels for anisotropic
texture fetches.
The existing isotropic vertex texture functions:
vec4 texture2DLodEXT(sampler2D sampler,
vec2 coord,
float lod);
vec4 texture2DProjLodEXT(sampler2D sampler,
vec3 coord,
float lod);
vec4 texture2DProjLodEXT(sampler2D sampler,
vec4 coord,
float lod);
vec4 textureCubeLodEXT(samplerCube sampler,
vec3 coord,
float lod);
are added to the built-in functions for fragment shaders
with "EXT" suffix appended.
New anisotropic texture functions, providing explicit
derivatives:
vec4 texture2DGradEXT(sampler2D sampler,
vec2 P,
vec2 dPdx,
vec2 dPdy);
vec4 texture2DProjGradEXT(sampler2D sampler,
vec3 P,
vec2 dPdx,
vec2 dPdy);
vec4 texture2DProjGradEXT(sampler2D sampler,
vec4 P,
vec2 dPdx,
vec2 dPdy);
vec4 textureCubeGradEXT(samplerCube sampler,
vec3 P,
vec3 dPdx,
vec3 dPdy);
are added to the built-in functions for vertex shaders
and fragment shaders.
New Procedures and Functions
None
New Tokens
None
Additions to Chapter 2 of the OpenGL ES 2.0 Specification (OpenGL Operation)
None
Additions to Chapter 3 of the OpenGL ES 2.0 Specification (Rasterization)
In Section 3.7.7, replace the final paragraph on p. 76 with:
"Let s(x, y) be the function that associates an s texture coordinate
with each set of window coordinates (x, y) that lie within a
primitive; define t(x, y) analogously. Let u(x, y) = wt * s(x, y) and
v(x, y) = ht * t(x, y), where wt and ht are equal to the width and height
of the level zero array.
Let
dUdx = wt*dSdx; dUdy = wt*dSdy;
dVdx = ht*dTdx; dVdy = ht*dTdy; (3.12a)
where dSdx indicates the derivative of s with respect to window x,
and similarly for dTdx.
For a polygon, rho is given at a fragment with window coordinates
(x, y) by
rho = max (
sqrt(dUdx*dUdx + dVdx*dVdx),
sqrt(dUdy*dUdy + dVdy*dVdy)
); (3.12b)"
Additions to Chapter 4 of the OpenGL ES 2.0 Specification (Per-Fragment Operations and the Frame Buffer)
None
Additions to Chapter 5 of the OpenGL ES 2.0 Specification (Special Functions)
None
Additions to Chapter 6 of the OpenGL ES 2.0 Specification (State and State
Requests)
None
Additions to Appendix A of the OpenGL ES 2.0 Specification (Invariance)
None
Additions to version 1.00.17 of the OpenGL ES Shading Language Specification
"A new preprocessor #define is added to the OpenGL Shading Language:
#define GL_EXT_shader_texture_lod 1
Including the following line in a shader can be used to control the
language features described in this extension:
#extension GL_EXT_shader_texture_lod : <behavior>
Where <behavior> is as specified in section 3.3."
Additions to Chapter 8 of version 1.00.17 of the OpenGL ES Shading Language
Specification
8.7 Texture Lookup Functions
Delete the last paragraph, and replace with:
"For the "Lod" functions, lod specifies lambda_base (see equation 3.11 in
The OpenGL ES 2.0 Specification) and specifies dSdx, dTdx = 0 and
dSdy, dTdy = 0 (see equation 3.12a in The OpenGL ES 2.0 Specification).
The "Lod" functions are allowed in a vertex shader. If enabled by the
preprocessor directive #extension, the "Lod" functions are also allowed in
a fragment shader.
For the "Grad" functions, dPdx is the explicit derivative of P with respect
to window x, and similarly dPdy with respect to window y. For the "ProjGrad"
functions, dPdx is the explicit derivative of the projected P with respect
to window x, and similarly for dPdy with respect to window y. For a two-
dimensional texture, dPdx and dPdy are vec2. For a cube map texture,
dPdx and dPdy are vec3.
Let
dSdx = dPdx.s;
dSdy = dPdy.s;
dTdx = dPdx.t;
dTdy = dPdy.t;
and
/ 0.0; for two-dimensional texture
dRdx = (
\ dPdx.p; for cube map texture
/ 0.0; for two-dimensional texture
dRdy = (
\ dPdy.p; for cube map texture
(See equation 3.12a in The OpenGL ES 2.0 Specification.)
If enabled by the preprocessor directive #extension, the "Grad" functions
are allowed in vertex and fragment shaders.
All other texture functions may require implicit derivatives. Implicit
derivatives are undefined within non-uniform control flow or for vertex
shader texture fetches."
Add the following entries to the texture function table:
vec4 texture2DGradEXT(sampler2D sampler,
vec2 P,
vec2 dPdx,
vec2 dPdy);
vec4 texture2DProjGradEXT(sampler2D sampler,
vec3 P,
vec2 dPdx,
vec2 dPdy);
vec4 texture2DProjGradEXT(sampler2D sampler,
vec4 P,
vec2 dPdx,
vec2 dPdy);
vec4 textureCubeGradEXT(samplerCube sampler,
vec3 P,
vec3 dPdx,
vec3 dPdy);
Interactions with EXT_texture_anisotropic
The Lod functions set the derivatives ds/dx, dt/dx, dr/dx,
dx/dy, dt/dy, and dr/dy = 0. Therefore Rhox and Rhoy = 0
0, Rhomax and Rhomin = 0.
Revision History:
3 - 2011-02-24
* Assign extension number
2 - 2010-01-20
* Naming updates
1 - 2010-01-19
* Initial ES version
......@@ -256,6 +256,7 @@ typedef struct
int ARB_texture_rectangle;
int EXT_draw_buffers;
int EXT_frag_depth;
int EXT_shader_texture_lod;
// Set to 1 if highp precision is supported in the fragment language.
// Default is 0.
......
......@@ -126,6 +126,7 @@ int main(int argc, char* argv[])
case 'i': resources.OES_EGL_image_external = 1; break;
case 'd': resources.OES_standard_derivatives = 1; break;
case 'r': resources.ARB_texture_rectangle = 1; break;
case 'l': resources.EXT_shader_texture_lod = 1; break;
default: failCode = EFailUsage;
}
} else {
......@@ -231,7 +232,8 @@ void usage()
" -b=h11 : output HLSL11 code\n"
" -x=i : enable GL_OES_EGL_image_external\n"
" -x=d : enable GL_OES_EGL_standard_derivatives\n"
" -x=r : enable ARB_texture_rectangle\n");
" -x=r : enable ARB_texture_rectangle\n"
" -x=l : enable EXT_shader_texture_lod\n");
}
//
......
......@@ -350,6 +350,22 @@ void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltI
symbolTable.insertBuiltIn(float4, "texture2DRectProj", sampler2DRect, float4);
}
if (resources.EXT_shader_texture_lod)
{
/* The *Grad* variants are new to both vertex and fragment shaders; the fragment
* shader specific pieces are added separately belyw
* added separately below.
*/
symbolTable.insertBuiltIn(float4, "texture2DGradEXT", sampler2D, float2, float2, float2);
symbolTable.insertBuiltIn(float4, "texture2DProjGradEXT", sampler2D, float3, float2, float2);
symbolTable.insertBuiltIn(float4, "texture2DProjGradEXT", sampler2D, float4, float2, float2);
symbolTable.insertBuiltIn(float4, "textureCubeGradEXT", samplerCube, float3, float3, float3);
symbolTable.relateToExtension("texture2DGradEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension("texture2DProjGradEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension("textureCubeGradEXT", "GL_EXT_shader_texture_lod");
}
if (type == SH_FRAGMENT_SHADER)
{
symbolTable.insertBuiltIn(float4, "texture2D", sampler2D, float2, float1);
......@@ -374,9 +390,21 @@ void InsertBuiltInFunctions(ShShaderType type, ShShaderSpec spec, const ShBuiltI
symbolTable.insertBuiltIn(float3, "fwidth", float3);
symbolTable.insertBuiltIn(float4, "fwidth", float4);
}
if (resources.EXT_shader_texture_lod)
{
symbolTable.insertBuiltIn(float4, "texture2DLodEXT", sampler2D, float2, float1);
symbolTable.insertBuiltIn(float4, "texture2DProjLodEXT", sampler2D, float3, float1);
symbolTable.insertBuiltIn(float4, "texture2DProjLodEXT", sampler2D, float4, float1);
symbolTable.insertBuiltIn(float4, "textureCubeLodEXT", samplerCube, float3, float1);
symbolTable.relateToExtension("texture2DLodEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension("texture2DProjLodEXT", "GL_EXT_shader_texture_lod");
symbolTable.relateToExtension("textureCubeLodEXT", "GL_EXT_shader_texture_lod");
}
}
if(type == SH_VERTEX_SHADER)
if (type == SH_VERTEX_SHADER)
{
symbolTable.insertBuiltIn(float4, "texture2DLod", sampler2D, float2, float1);
symbolTable.insertBuiltIn(float4, "texture2DProjLod", sampler2D, float3, float1);
......@@ -561,4 +589,6 @@ void InitExtensionBehavior(const ShBuiltInResources& resources,
extBehavior["GL_EXT_draw_buffers"] = EBhUndefined;
if (resources.EXT_frag_depth)
extBehavior["GL_EXT_frag_depth"] = EBhUndefined;
if (resources.EXT_shader_texture_lod)
extBehavior["GL_EXT_shader_texture_lod"] = EBhUndefined;
}
......@@ -33,3 +33,24 @@ void TOutputGLSL::visitSymbol(TIntermSymbol* node)
TOutputGLSLBase::visitSymbol(node);
}
}
TString TOutputGLSL::translateTextureFunction(TString& name)
{
static const char *simpleRename[] = {
"texture2DLodEXT", "texture2DLod",
"texture2DProjLodEXT", "texture2DProjLod",
"textureCubeLodEXT", "textureCubeLod",
"texture2DGradEXT", "texture2DGradARB",
"texture2DProjGradEXT", "texture2DProjGradARB",
"textureCubeGradEXT", "textureCubeGradARB",
NULL, NULL
};
for (int i = 0; simpleRename[i] != NULL; i += 2) {
if (name == simpleRename[i]) {
return simpleRename[i+1];
}
}
return name;
}
......@@ -21,6 +21,7 @@ public:
protected:
virtual bool writeVariablePrecision(TPrecision);
virtual void visitSymbol(TIntermSymbol* node);
virtual TString translateTextureFunction(TString& name);
};
#endif // CROSSCOMPILERGLSL_OUTPUTGLSL_H_
......@@ -798,8 +798,9 @@ TString TOutputGLSLBase::hashVariableName(const TString& name)
TString TOutputGLSLBase::hashFunctionName(const TString& mangled_name)
{
TString name = TFunction::unmangleName(mangled_name);
if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main")
return name;
if (mSymbolTable.findBuiltIn(mangled_name) != NULL || name == "main") {
return translateTextureFunction(name);
}
return hashName(name);
}
......
......@@ -50,6 +50,8 @@ protected:
TString hashVariableName(const TString& name);
// Same as hashName(), but without hashing built-in functions.
TString hashFunctionName(const TString& mangled_name);
// Used to translate function names for differences between ESSL and GLSL
virtual TString translateTextureFunction(TString& name) { return name; }
private:
bool structDeclared(const TStructure* structure) const;
......
......@@ -93,9 +93,12 @@ class OutputHLSL : public TIntermTraverser
bool mUsesTexture2DProj;
bool mUsesTexture2DProj_bias;
bool mUsesTexture2DProjLod;
bool mUsesTexture2DGrad;
bool mUsesTexture2DProjGrad;
bool mUsesTextureCube;
bool mUsesTextureCube_bias;
bool mUsesTextureCubeLod;
bool mUsesTextureCubeGrad;
bool mUsesTexture2DLod0;
bool mUsesTexture2DLod0_bias;
bool mUsesTexture2DProjLod0;
......
......@@ -89,6 +89,7 @@ void ShInitBuiltInResources(ShBuiltInResources* resources)
resources->ARB_texture_rectangle = 0;
resources->EXT_draw_buffers = 0;
resources->EXT_frag_depth = 0;
resources->EXT_shader_texture_lod = 0;
// Disable highp precision in fragment shader by default.
resources->FragmentPrecisionHigh = 0;
......
......@@ -280,7 +280,7 @@ public:
return insert(*constant);
}
bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0)
bool insertBuiltIn(TType *rvalue, const char *name, TType *ptype1, TType *ptype2 = 0, TType *ptype3 = 0, TType *ptype4 = 0)
{
TFunction *function = new TFunction(NewPoolTString(name), *rvalue);
......@@ -299,6 +299,12 @@ public:
function->addParameter(param3);
}
if(ptype4)
{
TParameter param4 = {NULL, ptype4};
function->addParameter(param4);
}
return insert(*function);
}
......
......@@ -31,6 +31,9 @@ void TranslatorGLSL::translate(TIntermNode* root) {
// Write GLSL version.
writeVersion(getShaderType(), root, sink);
// Write extension behaviour as needed
writeExtensionBehavior();
// Write emulated built-in functions if needed.
getBuiltInFunctionEmulator().OutputEmulatedFunctionDefinition(
sink, false);
......@@ -42,3 +45,20 @@ void TranslatorGLSL::translate(TIntermNode* root) {
TOutputGLSL outputGLSL(sink, getArrayIndexClampingStrategy(), getHashFunction(), getNameMap(), getSymbolTable());
root->traverse(&outputGLSL);
}
void TranslatorGLSL::writeExtensionBehavior() {
TInfoSinkBase& sink = getInfoSink().obj;
const TExtensionBehavior& extensionBehavior = getExtensionBehavior();
for (TExtensionBehavior::const_iterator iter = extensionBehavior.begin();
iter != extensionBehavior.end(); ++iter) {
if (iter->second == EBhUndefined)
continue;
// For GLSL output, we don't need to emit most extensions explicitly,
// but some we need to translate.
if (iter->first == "GL_EXT_shader_texture_lod") {
sink << "#extension GL_ARB_shader_texture_lod : "
<< getBehaviorString(iter->second) << "\n";
}
}
}
......@@ -15,6 +15,9 @@ public:
protected:
virtual void translate(TIntermNode* root);
private:
void writeExtensionBehavior();
};
#endif // COMPILER_TRANSLATORGLSL_H_
......@@ -2568,6 +2568,7 @@ void Context::initExtensionString()
extensionString += "GL_EXT_read_format_bgra ";
extensionString += "GL_EXT_robustness ";
extensionString += "GL_EXT_shader_texture_lod ";
if (supportsDXT1Textures())
{
......
......@@ -245,6 +245,7 @@ void Shader::initializeCompiler()
resources.MaxDrawBuffers = mRenderer->getMaxRenderTargets();
resources.OES_standard_derivatives = mRenderer->getDerivativeInstructionSupport();
resources.EXT_draw_buffers = mRenderer->getMaxRenderTargets() > 1;
resources.EXT_shader_texture_lod = 1;
// resources.OES_EGL_image_external = mRenderer->getShareHandleSupport() ? 1 : 0; // TODO: commented out until the extension is actually supported.
resources.FragmentPrecisionHigh = 1; // Shader Model 2+ always supports FP24 (s16e7) which corresponds to highp
resources.EXT_frag_depth = 1; // Shader Model 2+ always supports explicit depth output
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment