Turned on SkSL->GLSL compiler
GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2288033003 Committed: https://skia.googlesource.com/skia/+/9b0fe3d125f237d9884732a48414fa85fc71b4e3 Committed: https://skia.googlesource.com/skia/+/b12b3c6908c62c908b3680be01e3b5bfd30de310 Committed: https://skia.googlesource.com/skia/+/f008b0a59f45c0d4bea3e66faf3b01805009ec89 Committed: https://skia.googlesource.com/skia/+/08b2ccf398e2b81bc05d2c105837e5419899469b Committed: https://skia.googlesource.com/skia/+/dcfe6dba4a335e50e86ff68e3252065d4197432c Review-Url: https://codereview.chromium.org/2288033003
This commit is contained in:
parent
568c98606f
commit
ccb1dd8f26
@ -11,7 +11,10 @@
|
||||
#include "GrGpu.h"
|
||||
#include "GrTest.h"
|
||||
#include "gl/GrGLContext.h"
|
||||
#include "gl/builders/GrGLShaderStringBuilder.h"
|
||||
#include "SkSLCompiler.h"
|
||||
#include <stdio.h>
|
||||
#include <string>
|
||||
|
||||
const GrGLContext* GLBench::getGLContext(SkCanvas* canvas) {
|
||||
// This bench exclusively tests GL calls directly
|
||||
@ -61,13 +64,26 @@ void GLBench::onDraw(int loops, SkCanvas* canvas) {
|
||||
canvas->getGrContext()->resetContext();
|
||||
}
|
||||
|
||||
GrGLuint GLBench::CompileShader(const GrGLInterface* gl, const char* shaderSrc, GrGLenum type) {
|
||||
GrGLuint GLBench::CompileShader(const GrGLContext* context, const char* sksl, GrGLenum type) {
|
||||
const GrGLInterface* gl = context->interface();
|
||||
std::string glsl;
|
||||
bool result = context->compiler()->toGLSL(type == GR_GL_VERTEX_SHADER
|
||||
? SkSL::Program::kVertex_Kind
|
||||
: SkSL::Program::kFragment_Kind,
|
||||
std::string(sksl),
|
||||
GrGLSkSLCapsForContext(*context),
|
||||
&glsl);
|
||||
if (!result) {
|
||||
SkDebugf("SkSL compilation failed:\n%s\n%s\n", sksl,
|
||||
context->compiler()->errorText().c_str());
|
||||
}
|
||||
GrGLuint shader;
|
||||
// Create the shader object
|
||||
GR_GL_CALL_RET(gl, shader, CreateShader(type));
|
||||
|
||||
// Load the shader source
|
||||
GR_GL_CALL(gl, ShaderSource(shader, 1, &shaderSrc, nullptr));
|
||||
const char* glslPtr = glsl.c_str();
|
||||
GR_GL_CALL(gl, ShaderSource(shader, 1, (const char**) &glslPtr, nullptr));
|
||||
|
||||
// Compile the shader
|
||||
GR_GL_CALL(gl, CompileShader(shader));
|
||||
@ -84,10 +100,11 @@ GrGLuint GLBench::CompileShader(const GrGLInterface* gl, const char* shaderSrc,
|
||||
return shader;
|
||||
}
|
||||
|
||||
GrGLuint GLBench::CreateProgram(const GrGLInterface* gl, const char* vshader, const char* fshader) {
|
||||
|
||||
GrGLuint vertexShader = CompileShader(gl, vshader, GR_GL_VERTEX_SHADER);
|
||||
GrGLuint fragmentShader = CompileShader(gl, fshader, GR_GL_FRAGMENT_SHADER);
|
||||
GrGLuint GLBench::CreateProgram(const GrGLContext* context, const char* vshader,
|
||||
const char* fshader) {
|
||||
const GrGLInterface* gl = context->interface();
|
||||
GrGLuint vertexShader = CompileShader(context, vshader, GR_GL_VERTEX_SHADER);
|
||||
GrGLuint fragmentShader = CompileShader(context, fshader, GR_GL_FRAGMENT_SHADER);
|
||||
|
||||
GrGLuint shaderProgram;
|
||||
GR_GL_CALL_RET(gl, shaderProgram, CreateProgram());
|
||||
|
@ -35,8 +35,8 @@ protected:
|
||||
virtual void teardown(const GrGLInterface*)=0;
|
||||
void onDraw(int loops, SkCanvas*) override;
|
||||
virtual void glDraw(int loops, const GrGLContext*)=0;
|
||||
static GrGLuint CompileShader(const GrGLInterface*, const char* shaderSrc, GrGLenum type);
|
||||
static GrGLuint CreateProgram(const GrGLInterface*, const char* vshader, const char* fshader);
|
||||
static GrGLuint CompileShader(const GrGLContext*, const char* shaderSrc, GrGLenum type);
|
||||
static GrGLuint CreateProgram(const GrGLContext*, const char* vshader, const char* fshader);
|
||||
static GrGLuint SetupFramebuffer(const GrGLInterface*, int screenWidth, int screenHeight);
|
||||
static void DumpImage(const GrGLInterface* gl, uint32_t screenWidth, uint32_t screenHeight,
|
||||
const char* filename);
|
||||
|
@ -130,8 +130,6 @@ GrGLuint GLCpuPosInstancedArraysBench::setupShader(const GrGLContext* ctx) {
|
||||
"o_color = a_color;\n"
|
||||
"}\n");
|
||||
|
||||
const GrGLInterface* gl = ctx->interface();
|
||||
|
||||
// setup fragment shader
|
||||
GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
|
||||
SkString fshaderTxt(version);
|
||||
@ -155,7 +153,7 @@ GrGLuint GLCpuPosInstancedArraysBench::setupShader(const GrGLContext* ctx) {
|
||||
"%s = vec4(o_color, 1.0);\n"
|
||||
"}\n", fsOutName);
|
||||
|
||||
return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
return CreateProgram(ctx, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
|
@ -124,8 +124,6 @@ GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) {
|
||||
" o_color = a_color;\n"
|
||||
"}\n");
|
||||
|
||||
const GrGLInterface* gl = ctx->interface();
|
||||
|
||||
// set up fragment shader; this fragment shader will have fNumStages coverage stages plus an
|
||||
// XP stage at the end. Each coverage stage computes the pixel's distance from some hard-
|
||||
// coded center and compare that to some hard-coded circle radius to compute a coverage.
|
||||
@ -186,7 +184,7 @@ GrGLuint GLVec4ScalarBench::setupShader(const GrGLContext* ctx) {
|
||||
"}\n",
|
||||
fsOutName);
|
||||
|
||||
return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
return CreateProgram(ctx, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
}
|
||||
|
||||
template<typename Func>
|
||||
|
@ -114,8 +114,6 @@ GrGLuint GLVertexAttributesBench::setupShader(const GrGLContext* ctx, uint32_t a
|
||||
|
||||
vshaderTxt.append("}\n");
|
||||
|
||||
const GrGLInterface* gl = ctx->interface();
|
||||
|
||||
// setup fragment shader
|
||||
GrGLSLShaderVar oFragColor("o_FragColor", kVec4f_GrSLType, GrShaderVar::kOut_TypeModifier);
|
||||
SkString fshaderTxt(version);
|
||||
@ -127,7 +125,7 @@ GrGLuint GLVertexAttributesBench::setupShader(const GrGLContext* ctx, uint32_t a
|
||||
fshaderTxt.append(";\n");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
fsOutName = "sk_FragColor";
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < maxAttribs; i++) {
|
||||
@ -149,7 +147,7 @@ GrGLuint GLVertexAttributesBench::setupShader(const GrGLContext* ctx, uint32_t a
|
||||
fshaderTxt.append(";\n"
|
||||
"}\n");
|
||||
|
||||
return CreateProgram(gl, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
return CreateProgram(ctx, vshaderTxt.c_str(), fshaderTxt.c_str());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -18,7 +18,7 @@
|
||||
],
|
||||
'all_dependent_settings': {
|
||||
'include_dirs': [
|
||||
'../src/sksl',
|
||||
'<(skia_src_path)/sksl',
|
||||
],
|
||||
},
|
||||
},
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "GrGLContext.h"
|
||||
#include "GrGLGLSL.h"
|
||||
#include "SkSLCompiler.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@ -63,6 +64,17 @@ GrGLContext* GrGLContext::Create(const GrGLInterface* interface, const GrContext
|
||||
return new GrGLContext(args);
|
||||
}
|
||||
|
||||
GrGLContext::~GrGLContext() {
|
||||
delete fCompiler;
|
||||
}
|
||||
|
||||
SkSL::Compiler* GrGLContext::compiler() const {
|
||||
if (!fCompiler) {
|
||||
fCompiler = new SkSL::Compiler();
|
||||
}
|
||||
return fCompiler;
|
||||
}
|
||||
|
||||
GrGLContextInfo::GrGLContextInfo(const ConstructorArgs& args) {
|
||||
fInterface.reset(SkRef(args.fInterface));
|
||||
fGLVersion = args.fGLVersion;
|
||||
|
@ -15,6 +15,9 @@
|
||||
#include "GrGLUtil.h"
|
||||
|
||||
struct GrContextOptions;
|
||||
namespace SkSL {
|
||||
class Compiler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates information about an OpenGL context including the OpenGL
|
||||
@ -39,6 +42,8 @@ public:
|
||||
|
||||
const GrGLExtensions& extensions() const { return fInterface->fExtensions; }
|
||||
|
||||
virtual ~GrGLContextInfo() {}
|
||||
|
||||
protected:
|
||||
struct ConstructorArgs {
|
||||
const GrGLInterface* fInterface;
|
||||
@ -64,7 +69,7 @@ protected:
|
||||
};
|
||||
|
||||
/**
|
||||
* Extension of GrGLContextInfo that also provides access to GrGLInterface.
|
||||
* Extension of GrGLContextInfo that also provides access to GrGLInterface and SkSL::Compiler.
|
||||
*/
|
||||
class GrGLContext : public GrGLContextInfo {
|
||||
public:
|
||||
@ -76,8 +81,16 @@ public:
|
||||
|
||||
const GrGLInterface* interface() const { return fInterface; }
|
||||
|
||||
SkSL::Compiler* compiler() const;
|
||||
|
||||
~GrGLContext() override;
|
||||
|
||||
private:
|
||||
GrGLContext(const ConstructorArgs& args) : INHERITED(args) {}
|
||||
GrGLContext(const ConstructorArgs& args)
|
||||
: INHERITED(args)
|
||||
, fCompiler(nullptr) {}
|
||||
|
||||
mutable SkSL::Compiler* fCompiler;
|
||||
|
||||
typedef GrGLContextInfo INHERITED;
|
||||
};
|
||||
|
@ -3790,20 +3790,11 @@ bool GrGLGpu::createCopyProgram(int progIdx) {
|
||||
fshaderTxt.append(";");
|
||||
uTexture.appendDecl(glslCaps, &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
const char* fsOutName;
|
||||
if (glslCaps->mustDeclareFragmentShaderOutput()) {
|
||||
oFragColor.appendDecl(glslCaps, &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
}
|
||||
fshaderTxt.appendf(
|
||||
"// Copy Program FS\n"
|
||||
"void main() {"
|
||||
" %s = %s(u_texture, v_texCoord);"
|
||||
" sk_FragColor = %s(u_texture, v_texCoord);"
|
||||
"}",
|
||||
fsOutName,
|
||||
GrGLSLTexture2DFunctionName(kVec2f_GrSLType, kSamplerTypes[progIdx], this->glslGeneration())
|
||||
);
|
||||
|
||||
@ -3936,14 +3927,6 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
|
||||
}
|
||||
uTexture.appendDecl(glslCaps, &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
const char* fsOutName;
|
||||
if (glslCaps->mustDeclareFragmentShaderOutput()) {
|
||||
oFragColor.appendDecl(glslCaps, &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
}
|
||||
const char* sampleFunction = GrGLSLTexture2DFunctionName(kVec2f_GrSLType,
|
||||
kTexture2DSampler_GrSLType,
|
||||
this->glslGeneration());
|
||||
@ -3954,19 +3937,19 @@ bool GrGLGpu::createMipmapProgram(int progIdx) {
|
||||
|
||||
if (oddWidth && oddHeight) {
|
||||
fshaderTxt.appendf(
|
||||
" %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1) + "
|
||||
" %s(u_texture, v_texCoord2) + %s(u_texture, v_texCoord3)) * 0.25;",
|
||||
fsOutName, sampleFunction, sampleFunction, sampleFunction, sampleFunction
|
||||
" sk_FragColor = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1) + "
|
||||
" %s(u_texture, v_texCoord2) + %s(u_texture, v_texCoord3)) * 0.25;",
|
||||
sampleFunction, sampleFunction, sampleFunction, sampleFunction
|
||||
);
|
||||
} else if (oddWidth || oddHeight) {
|
||||
fshaderTxt.appendf(
|
||||
" %s = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1)) * 0.5;",
|
||||
fsOutName, sampleFunction, sampleFunction
|
||||
" sk_FragColor = (%s(u_texture, v_texCoord0) + %s(u_texture, v_texCoord1)) * 0.5;",
|
||||
sampleFunction, sampleFunction
|
||||
);
|
||||
} else {
|
||||
fshaderTxt.appendf(
|
||||
" %s = %s(u_texture, v_texCoord0);",
|
||||
fsOutName, sampleFunction
|
||||
" sk_FragColor = %s(u_texture, v_texCoord0);",
|
||||
sampleFunction
|
||||
);
|
||||
}
|
||||
|
||||
@ -4053,20 +4036,11 @@ bool GrGLGpu::createWireRectProgram() {
|
||||
&fshaderTxt);
|
||||
uColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
const char* fsOutName;
|
||||
if (this->glCaps().glslCaps()->mustDeclareFragmentShaderOutput()) {
|
||||
oFragColor.appendDecl(this->glCaps().glslCaps(), &fshaderTxt);
|
||||
fshaderTxt.append(";");
|
||||
fsOutName = oFragColor.c_str();
|
||||
} else {
|
||||
fsOutName = "gl_FragColor";
|
||||
}
|
||||
fshaderTxt.appendf(
|
||||
"// Write Rect Program FS\n"
|
||||
"void main() {"
|
||||
" %s = %s;"
|
||||
" sk_FragColor = %s;"
|
||||
"}",
|
||||
fsOutName,
|
||||
uColor.c_str()
|
||||
);
|
||||
|
||||
|
@ -9,6 +9,9 @@
|
||||
#include "gl/GrGLGpu.h"
|
||||
#include "gl/GrGLSLPrettyPrint.h"
|
||||
#include "SkTraceEvent.h"
|
||||
#include "SkSLCompiler.h"
|
||||
#include "SkSLGLSLCodeGenerator.h"
|
||||
#include "ir/SkSLProgram.h"
|
||||
|
||||
#define GL_CALL(X) GR_GL_CALL(gpu->glInterface(), X)
|
||||
#define GL_CALL_RET(R, X) GR_GL_CALL_RET(gpu->glInterface(), R, X)
|
||||
@ -18,6 +21,90 @@ static const bool c_PrintShaders{false};
|
||||
|
||||
static void print_shader_source(const char** strings, int* lengths, int count);
|
||||
|
||||
SkSL::GLCaps GrGLSkSLCapsForContext(const GrGLContext& context) {
|
||||
GrGLStandard standard = context.standard();
|
||||
const GrGLCaps* caps = context.caps();
|
||||
const GrGLSLCaps* glslCaps = caps->glslCaps();
|
||||
SkSL::GLCaps result;
|
||||
switch (standard) {
|
||||
case kGL_GrGLStandard:
|
||||
result.fStandard = SkSL::GLCaps::kGL_Standard;
|
||||
break;
|
||||
case kGLES_GrGLStandard:
|
||||
result.fStandard = SkSL::GLCaps::kGLES_Standard;
|
||||
break;
|
||||
default:
|
||||
SkASSERT(false);
|
||||
result.fStandard = SkSL::GLCaps::kGL_Standard;
|
||||
}
|
||||
|
||||
switch (glslCaps->generation()) {
|
||||
case k110_GrGLSLGeneration:
|
||||
if (kGLES_GrGLStandard == standard) {
|
||||
// ES2's shader language is based on GLSL 1.20 but is version 1.00 of the ES
|
||||
// language
|
||||
result.fVersion = 100;
|
||||
} else {
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 110;
|
||||
}
|
||||
break;
|
||||
case k130_GrGLSLGeneration:
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 130;
|
||||
break;
|
||||
case k140_GrGLSLGeneration:
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 140;
|
||||
break;
|
||||
case k150_GrGLSLGeneration:
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 150;
|
||||
break;
|
||||
case k330_GrGLSLGeneration:
|
||||
if (kGLES_GrGLStandard == standard) {
|
||||
result.fVersion = 300;
|
||||
} else {
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 330;
|
||||
}
|
||||
break;
|
||||
case k400_GrGLSLGeneration:
|
||||
SkASSERT(kGL_GrGLStandard == standard);
|
||||
result.fVersion = 400;
|
||||
break;
|
||||
case k310es_GrGLSLGeneration:
|
||||
SkASSERT(kGLES_GrGLStandard == standard);
|
||||
result.fVersion = 310;
|
||||
break;
|
||||
case k320es_GrGLSLGeneration:
|
||||
SkASSERT(kGLES_GrGLStandard == standard);
|
||||
result.fVersion = 320;
|
||||
break;
|
||||
}
|
||||
result.fIsCoreProfile = caps->isCoreProfile();
|
||||
result.fUsesPrecisionModifiers = glslCaps->usesPrecisionModifiers();
|
||||
result.fMustDeclareFragmentShaderOutput = glslCaps->mustDeclareFragmentShaderOutput();
|
||||
result.fCanUseMinAndAbsTogether = glslCaps->canUseMinAndAbsTogether();
|
||||
return result;
|
||||
}
|
||||
|
||||
static void dump_string(std::string s) {
|
||||
// on Android, SkDebugf only displays the first 1K characters of output, which results in
|
||||
// incomplete shader source code. Print each line individually to avoid this problem.
|
||||
size_t index = 0;
|
||||
for (;;) {
|
||||
size_t next = s.find("\n", index);
|
||||
if (next == std::string::npos) {
|
||||
SkDebugf("%s", s.substr(index).c_str());
|
||||
break;
|
||||
} else {
|
||||
SkDebugf("%s", s.substr(index, next - index + 1).c_str());
|
||||
index = next + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
@ -33,15 +120,40 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string sksl;
|
||||
#ifdef SK_DEBUG
|
||||
SkString prettySource = GrGLSLPrettyPrint::PrettyPrintGLSL(strings, lengths, count, false);
|
||||
const GrGLchar* sourceStr = prettySource.c_str();
|
||||
GrGLint sourceLength = static_cast<GrGLint>(prettySource.size());
|
||||
GR_GL_CALL(gli, ShaderSource(shaderId, 1, &sourceStr, &sourceLength));
|
||||
sksl = std::string(prettySource.c_str());
|
||||
#else
|
||||
GR_GL_CALL(gli, ShaderSource(shaderId, count, strings, lengths));
|
||||
for (int i = 0; i < count; i++) {
|
||||
sksl.append(strings[i], lengths[i]);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::string glsl;
|
||||
SkSL::Compiler& compiler = *glCtx.compiler();
|
||||
SkSL::GLCaps caps = GrGLSkSLCapsForContext(glCtx);
|
||||
SkASSERT(type == GR_GL_VERTEX_SHADER || type == GR_GL_FRAGMENT_SHADER);
|
||||
SkDEBUGCODE(bool result = )compiler.toGLSL(type == GR_GL_VERTEX_SHADER
|
||||
? SkSL::Program::kVertex_Kind
|
||||
: SkSL::Program::kFragment_Kind,
|
||||
std::string(sksl.c_str()),
|
||||
caps,
|
||||
&glsl);
|
||||
#ifdef SK_DEBUG
|
||||
if (!result) {
|
||||
SkDebugf("SKSL compilation error\n----------------------\n");
|
||||
SkDebugf("SKSL:\n");
|
||||
dump_string(sksl);
|
||||
SkDebugf("\nErrors:\n%s\n", compiler.errorText().c_str());
|
||||
SkDEBUGFAIL("SKSL compilation failed!\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
const char* glslChars = glsl.c_str();
|
||||
GrGLint glslLength = (GrGLint) glsl.length();
|
||||
GR_GL_CALL(gli, ShaderSource(shaderId, 1, &glslChars, &glslLength));
|
||||
|
||||
// If tracing is enabled in chrome then we pretty print
|
||||
bool traceShader;
|
||||
TRACE_EVENT_CATEGORY_GROUP_ENABLED(TRACE_DISABLED_BY_DEFAULT("skia.gpu"), &traceShader);
|
||||
@ -72,10 +184,14 @@ GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
// buffer param validation.
|
||||
GrGLsizei length = GR_GL_INIT_ZERO;
|
||||
GR_GL_CALL(gli, GetShaderInfoLog(shaderId, infoLen+1, &length, (char*)log.get()));
|
||||
print_shader_source(strings, lengths, count);
|
||||
SkDebugf("\n%s", (const char*)log.get());
|
||||
SkDebugf("GLSL compilation error\n----------------------\n");
|
||||
SkDebugf("SKSL:\n");
|
||||
dump_string(sksl);
|
||||
SkDebugf("GLSL:\n");
|
||||
dump_string(glsl);
|
||||
SkDebugf("Errors:\n%s\n", (const char*) log.get());
|
||||
}
|
||||
SkDEBUGFAIL("Shader compilation failed!");
|
||||
SkDEBUGFAIL("GLSL compilation failed!");
|
||||
GR_GL_CALL(gli, DeleteShader(shaderId));
|
||||
return 0;
|
||||
}
|
||||
|
@ -11,8 +11,11 @@
|
||||
#include "GrAllocator.h"
|
||||
#include "GrGpu.h"
|
||||
#include "gl/GrGLContext.h"
|
||||
#include "SkSLGLSLCodeGenerator.h"
|
||||
#include "SkTypes.h"
|
||||
|
||||
SkSL::GLCaps GrGLSkSLCapsForContext(const GrGLContext& context);
|
||||
|
||||
GrGLuint GrGLCompileAndAttachShader(const GrGLContext& glCtx,
|
||||
GrGLuint programId,
|
||||
GrGLenum type,
|
||||
|
@ -291,10 +291,10 @@ void GrGLSLFragmentShaderBuilder::enableCustomOutput() {
|
||||
if (!fHasCustomColorOutput) {
|
||||
fHasCustomColorOutput = true;
|
||||
fCustomColorOutputIndex = fOutputs.count();
|
||||
fOutputs.push_back().set(kVec4f_GrSLType,
|
||||
GrGLSLShaderVar::kOut_TypeModifier,
|
||||
DeclaredColorOutputName());
|
||||
fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back());
|
||||
fOutputs.push_back().set(kVec4f_GrSLType,
|
||||
GrGLSLShaderVar::kOut_TypeModifier,
|
||||
DeclaredColorOutputName());
|
||||
fProgramBuilder->finalizeFragmentOutputColor(fOutputs.back());
|
||||
}
|
||||
}
|
||||
|
||||
@ -318,7 +318,7 @@ void GrGLSLFragmentShaderBuilder::enableSecondaryOutput() {
|
||||
}
|
||||
|
||||
const char* GrGLSLFragmentShaderBuilder::getPrimaryColorOutputName() const {
|
||||
return fHasCustomColorOutput ? DeclaredColorOutputName() : "gl_FragColor";
|
||||
return fHasCustomColorOutput ? DeclaredColorOutputName() : "sk_FragColor";
|
||||
}
|
||||
|
||||
void GrGLSLFragmentBuilder::declAppendf(const char* fmt, ...) {
|
||||
|
@ -203,7 +203,7 @@ private:
|
||||
}
|
||||
#endif
|
||||
|
||||
static const char* DeclaredColorOutputName() { return "fsColorOut"; }
|
||||
static const char* DeclaredColorOutputName() { return "sk_FragColor"; }
|
||||
static const char* DeclaredSecondaryColorOutputName() { return "fsSecondaryColorOut"; }
|
||||
|
||||
GrSurfaceOrigin getSurfaceOrigin() const;
|
||||
|
@ -72,23 +72,27 @@ public:
|
||||
void appendTexelFetch(SamplerHandle, const char* coordExpr);
|
||||
|
||||
/**
|
||||
* Adds a #define directive to the top of the shader.
|
||||
* Adds a constant declaration to the top of the shader.
|
||||
*/
|
||||
void define(const char* macro, const char* replacement) {
|
||||
this->definitions().appendf("#define %s %s\n", macro, replacement);
|
||||
void defineConstant(const char* type, const char* name, const char* value) {
|
||||
this->definitions().appendf("const %s %s = %s;\n", type, name, value);
|
||||
}
|
||||
|
||||
void define(const char* macro, int replacement) {
|
||||
this->definitions().appendf("#define %s %i\n", macro, replacement);
|
||||
void defineConstant(const char* name, int value) {
|
||||
this->definitions().appendf("const int %s = %i;\n", name, value);
|
||||
}
|
||||
|
||||
void definef(const char* macro, const char* replacement, ...) {
|
||||
this->definitions().appendf("#define %s ", macro);
|
||||
void defineConstant(const char* name, float value) {
|
||||
this->definitions().appendf("const float %s = %f;\n", name, value);
|
||||
}
|
||||
|
||||
void defineConstantf(const char* type, const char* name, const char* fmt, ...) {
|
||||
this->definitions().appendf("const %s %s = ", type, name);
|
||||
va_list args;
|
||||
va_start(args, replacement);
|
||||
this->definitions().appendVAList(replacement, args);
|
||||
va_start(args, fmt);
|
||||
this->definitions().appendVAList(fmt, args);
|
||||
va_end(args);
|
||||
this->definitions().append("\n");
|
||||
this->definitions().append(";\n");
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -213,24 +213,20 @@ public:
|
||||
|
||||
private:
|
||||
static const char* TypeModifierString(const GrGLSLCaps* glslCaps, TypeModifier t) {
|
||||
GrGLSLGeneration gen = glslCaps->generation();
|
||||
switch (t) {
|
||||
case kNone_TypeModifier:
|
||||
return "";
|
||||
case kAttribute_TypeModifier: // fall through
|
||||
case kVaryingIn_TypeModifier: // fall through
|
||||
case kIn_TypeModifier:
|
||||
return "in";
|
||||
case kInOut_TypeModifier:
|
||||
return "inout";
|
||||
case kVaryingOut_TypeModifier: // fall through
|
||||
case kOut_TypeModifier:
|
||||
return "out";
|
||||
case kUniform_TypeModifier:
|
||||
return "uniform";
|
||||
case kAttribute_TypeModifier:
|
||||
return k110_GrGLSLGeneration == gen ? "attribute" : "in";
|
||||
case kVaryingIn_TypeModifier:
|
||||
return k110_GrGLSLGeneration == gen ? "varying" : "in";
|
||||
case kVaryingOut_TypeModifier:
|
||||
return k110_GrGLSLGeneration == gen ? "varying" : "out";
|
||||
default:
|
||||
SkFAIL("Unknown shader variable type modifier.");
|
||||
return ""; // suppress warning
|
||||
|
@ -107,10 +107,10 @@ public:
|
||||
|
||||
void initParams(const SamplerHandle paramsBuffer) {
|
||||
fParamsBuffer = paramsBuffer;
|
||||
fVertexBuilder->definef("PARAMS_IDX_MASK", "0x%xu", kParamsIdx_InfoMask);
|
||||
fVertexBuilder->appendPrecisionModifier(kHigh_GrSLPrecision);
|
||||
fVertexBuilder->codeAppendf("int paramsIdx = int(%s & PARAMS_IDX_MASK);",
|
||||
this->attr(Attrib::kInstanceInfo));
|
||||
fVertexBuilder->codeAppendf("int paramsIdx = int(%s & 0x%x);",
|
||||
this->attr(Attrib::kInstanceInfo),
|
||||
kParamsIdx_InfoMask);
|
||||
}
|
||||
|
||||
const char* attr(Attrib attr) const { return fInstProc.getAttrib((int)attr).fName; }
|
||||
@ -224,10 +224,10 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
|
||||
v->codeAppendf("mat2x3 shapeMatrix = mat2x3(%s, %s);",
|
||||
inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY));
|
||||
} else {
|
||||
v->definef("PERSPECTIVE_FLAG", "0x%xu", kPerspective_InfoFlag);
|
||||
v->defineConstantf("int", "PERSPECTIVE_FLAG", "0x%x", kPerspective_InfoFlag);
|
||||
v->codeAppendf("mat3 shapeMatrix = mat3(%s, %s, vec3(0, 0, 1));",
|
||||
inputs.attr(Attrib::kShapeMatrixX), inputs.attr(Attrib::kShapeMatrixY));
|
||||
v->codeAppendf("if (0u != (%s & PERSPECTIVE_FLAG)) {",
|
||||
v->codeAppendf("if (0 != (%s & PERSPECTIVE_FLAG)) {",
|
||||
inputs.attr(Attrib::kInstanceInfo));
|
||||
v->codeAppend ( "shapeMatrix[2] = ");
|
||||
inputs.fetchNextParam(kVec3f_GrSLType);
|
||||
@ -237,7 +237,7 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
|
||||
|
||||
bool hasSingleShapeType = SkIsPow2(ip.batchInfo().fShapeTypes);
|
||||
if (!hasSingleShapeType) {
|
||||
v->define("SHAPE_TYPE_BIT", kShapeType_InfoBit);
|
||||
v->defineConstant("SHAPE_TYPE_BIT", kShapeType_InfoBit);
|
||||
v->codeAppendf("uint shapeType = %s >> SHAPE_TYPE_BIT;",
|
||||
inputs.attr(Attrib::kInstanceInfo));
|
||||
}
|
||||
@ -285,8 +285,8 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
|
||||
if (ip.batchInfo().fInnerShapeTypes) {
|
||||
bool hasSingleInnerShapeType = SkIsPow2(ip.batchInfo().fInnerShapeTypes);
|
||||
if (!hasSingleInnerShapeType) {
|
||||
v->definef("INNER_SHAPE_TYPE_MASK", "0x%xu", kInnerShapeType_InfoMask);
|
||||
v->define("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit);
|
||||
v->defineConstantf("int", "INNER_SHAPE_TYPE_MASK", "0x%x", kInnerShapeType_InfoMask);
|
||||
v->defineConstant("INNER_SHAPE_TYPE_BIT", kInnerShapeType_InfoBit);
|
||||
v->codeAppendf("uint innerShapeType = ((%s & INNER_SHAPE_TYPE_MASK) >> "
|
||||
"INNER_SHAPE_TYPE_BIT);",
|
||||
inputs.attr(Attrib::kInstanceInfo));
|
||||
@ -346,13 +346,13 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
|
||||
}
|
||||
|
||||
if (usedShapeDefinitions & kOval_ShapeFlag) {
|
||||
v->definef("OVAL_SHAPE_TYPE", "%du", (int)ShapeType::kOval);
|
||||
v->defineConstant("OVAL_SHAPE_TYPE", (int)ShapeType::kOval);
|
||||
}
|
||||
if (usedShapeDefinitions & kSimpleRRect_ShapeFlag) {
|
||||
v->definef("SIMPLE_R_RECT_SHAPE_TYPE", "%du", (int)ShapeType::kSimpleRRect);
|
||||
v->defineConstant("SIMPLE_R_RECT_SHAPE_TYPE", (int)ShapeType::kSimpleRRect);
|
||||
}
|
||||
if (usedShapeDefinitions & kNinePatch_ShapeFlag) {
|
||||
v->definef("NINE_PATCH_SHAPE_TYPE", "%du", (int)ShapeType::kNinePatch);
|
||||
v->defineConstant("NINE_PATCH_SHAPE_TYPE", (int)ShapeType::kNinePatch);
|
||||
}
|
||||
SkASSERT(!(usedShapeDefinitions & (kRect_ShapeFlag | kComplexRRect_ShapeFlag)));
|
||||
|
||||
@ -367,8 +367,8 @@ void GLSLInstanceProcessor::onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) {
|
||||
inputs.attr(Attrib::kLocalRect), inputs.attr(Attrib::kLocalRect));
|
||||
}
|
||||
if (ip.batchInfo().fHasLocalMatrix && ip.batchInfo().fHasParams) {
|
||||
v->definef("LOCAL_MATRIX_FLAG", "0x%xu", kLocalMatrix_InfoFlag);
|
||||
v->codeAppendf("if (0u != (%s & LOCAL_MATRIX_FLAG)) {",
|
||||
v->defineConstantf("int", "LOCAL_MATRIX_FLAG", "0x%x", kLocalMatrix_InfoFlag);
|
||||
v->codeAppendf("if (0 != (%s & LOCAL_MATRIX_FLAG)) {",
|
||||
inputs.attr(Attrib::kInstanceInfo));
|
||||
if (!ip.batchInfo().fUsesLocalCoords) {
|
||||
inputs.skipParams(2);
|
||||
@ -1179,7 +1179,7 @@ void GLSLInstanceProcessor::BackendMultisample::onInit(GrGLSLVaryingHandler* var
|
||||
}
|
||||
}
|
||||
if (kRect_ShapeFlag != fBatchInfo.fShapeTypes) {
|
||||
v->definef("SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
|
||||
v->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
|
||||
varyingHandler->addFlatVarying("earlyAccept", &fEarlyAccept, kHigh_GrSLPrecision);
|
||||
}
|
||||
}
|
||||
@ -1360,10 +1360,10 @@ void GLSLInstanceProcessor::BackendMultisample::onSetupInnerSimpleRRect(GrGLSLVe
|
||||
void GLSLInstanceProcessor::BackendMultisample::onEmitCode(GrGLSLVertexBuilder*,
|
||||
GrGLSLPPFragmentBuilder* f,
|
||||
const char*, const char*) {
|
||||
f->define("SAMPLE_COUNT", fEffectiveSampleCnt);
|
||||
f->defineConstant("SAMPLE_COUNT", fEffectiveSampleCnt);
|
||||
if (this->isMixedSampled()) {
|
||||
f->definef("SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
|
||||
f->definef("SAMPLE_MASK_MSB", "0x%x", 1 << (fEffectiveSampleCnt - 1));
|
||||
f->defineConstantf("int", "SAMPLE_MASK_ALL", "0x%x", (1 << fEffectiveSampleCnt) - 1);
|
||||
f->defineConstantf("int", "SAMPLE_MASK_MSB", "0x%x", 1 << (fEffectiveSampleCnt - 1));
|
||||
}
|
||||
|
||||
if (kRect_ShapeFlag != (fBatchInfo.fShapeTypes | fBatchInfo.fInnerShapeTypes)) {
|
||||
|
35
src/sksl/README
Normal file
35
src/sksl/README
Normal file
@ -0,0 +1,35 @@
|
||||
Overview
|
||||
========
|
||||
|
||||
SkSL ("Skia Shading Language") is a variant of GLSL which is used as Skia's
|
||||
internal shading language. SkSL is, at its heart, a single standardized version
|
||||
of GLSL which avoids all of the various version and dialect differences found
|
||||
in GLSL "in the wild", but it does bring a few of its own changes to the table.
|
||||
|
||||
Skia uses the SkSL compiler to convert SkSL code to GLSL, GLSL ES, or SPIR-V
|
||||
before handing it over to the graphics driver.
|
||||
|
||||
Differences from GLSL
|
||||
=====================
|
||||
|
||||
SkSL is based on GLSL 4.5. For the most part, write SkSL exactly as you would
|
||||
desktop GLSL, and the SkSL compiler will take care of version and dialect
|
||||
differences (for instance, you always use "in" and "out", and skslc will handle
|
||||
translating them to "varying" and "attribute" as appropriate). Be aware of the
|
||||
following differences between SkSL and GLSL:
|
||||
|
||||
* no #version or "precision" statement is required, and they will be ignored if
|
||||
present
|
||||
* the output color is sk_FragColor (do not declare it)
|
||||
* lowp, mediump, and highp are always permitted (but will only be respected if
|
||||
you run on a GLES device)
|
||||
* you do not need to include ".0" to make a number a float (meaning that
|
||||
"vec2(x, y) * 4" is perfectly legal in SkSL, unlike GLSL where it would often
|
||||
have to be expressed "vec2(x, y) * 4.0". There is no performance penalty for
|
||||
this, as the number is converted to a float at compile time)
|
||||
* type suffixes on numbers (1.0f, 0xFFu) are both unnecessary and unsupported
|
||||
* some built-in functions and one or two rarely-used language features are not
|
||||
yet supported (sorry!)
|
||||
|
||||
SkSL is still under development, and is expected to diverge further from GLSL
|
||||
over time.
|
@ -10,7 +10,7 @@
|
||||
|
||||
#include "ir/SkSLProgram.h"
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <ostream>
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
|
@ -10,11 +10,13 @@
|
||||
#include <fstream>
|
||||
#include <streambuf>
|
||||
|
||||
#include "ast/SkSLASTPrecision.h"
|
||||
#include "SkSLIRGenerator.h"
|
||||
#include "SkSLParser.h"
|
||||
#include "SkSLSPIRVCodeGenerator.h"
|
||||
#include "ir/SkSLExpression.h"
|
||||
#include "ir/SkSLIntLiteral.h"
|
||||
#include "ir/SkSLModifiersDeclaration.h"
|
||||
#include "ir/SkSLSymbolTable.h"
|
||||
#include "ir/SkSLVarDeclaration.h"
|
||||
#include "SkMutex.h"
|
||||
@ -23,15 +25,15 @@
|
||||
|
||||
// include the built-in shader symbols as static strings
|
||||
|
||||
static std::string SKSL_INCLUDE =
|
||||
static const char* SKSL_INCLUDE =
|
||||
#include "sksl.include"
|
||||
;
|
||||
|
||||
static std::string SKSL_VERT_INCLUDE =
|
||||
static const char* SKSL_VERT_INCLUDE =
|
||||
#include "sksl_vert.include"
|
||||
;
|
||||
|
||||
static std::string SKSL_FRAG_INCLUDE =
|
||||
static const char* SKSL_FRAG_INCLUDE =
|
||||
#include "sksl_frag.include"
|
||||
;
|
||||
|
||||
@ -97,6 +99,7 @@ Compiler::Compiler()
|
||||
ADD_TYPE(Sampler1D);
|
||||
ADD_TYPE(Sampler2D);
|
||||
ADD_TYPE(Sampler3D);
|
||||
ADD_TYPE(SamplerExternalOES);
|
||||
ADD_TYPE(SamplerCube);
|
||||
ADD_TYPE(Sampler2DRect);
|
||||
ADD_TYPE(Sampler1DArray);
|
||||
@ -128,8 +131,9 @@ Compiler::Compiler()
|
||||
ADD_TYPE(GSampler2DArrayShadow);
|
||||
ADD_TYPE(GSamplerCubeArrayShadow);
|
||||
|
||||
std::vector<std::unique_ptr<ProgramElement>> ignored;
|
||||
this->internalConvertProgram(SKSL_INCLUDE, &ignored);
|
||||
Modifiers::Flag ignored1;
|
||||
std::vector<std::unique_ptr<ProgramElement>> ignored2;
|
||||
this->internalConvertProgram(SKSL_INCLUDE, &ignored1, &ignored2);
|
||||
ASSERT(!fErrorCount);
|
||||
}
|
||||
|
||||
@ -138,12 +142,14 @@ Compiler::~Compiler() {
|
||||
}
|
||||
|
||||
void Compiler::internalConvertProgram(std::string text,
|
||||
Modifiers::Flag* defaultPrecision,
|
||||
std::vector<std::unique_ptr<ProgramElement>>* result) {
|
||||
Parser parser(text, *fTypes, *this);
|
||||
std::vector<std::unique_ptr<ASTDeclaration>> parsed = parser.file();
|
||||
if (fErrorCount) {
|
||||
return;
|
||||
}
|
||||
*defaultPrecision = Modifiers::kHighp_Flag;
|
||||
for (size_t i = 0; i < parsed.size(); i++) {
|
||||
ASTDeclaration& decl = *parsed[i];
|
||||
switch (decl.fKind) {
|
||||
@ -164,6 +170,14 @@ void Compiler::internalConvertProgram(std::string text,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ASTDeclaration::kModifiers_Kind: {
|
||||
std::unique_ptr<ModifiersDeclaration> f = fIRGenerator->convertModifiersDeclaration(
|
||||
(ASTModifiersDeclaration&) decl);
|
||||
if (f) {
|
||||
result->push_back(std::move(f));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ASTDeclaration::kInterfaceBlock_Kind: {
|
||||
std::unique_ptr<InterfaceBlock> i = fIRGenerator->convertInterfaceBlock(
|
||||
(ASTInterfaceBlock&) decl);
|
||||
@ -179,6 +193,10 @@ void Compiler::internalConvertProgram(std::string text,
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ASTDeclaration::kPrecision_Kind: {
|
||||
*defaultPrecision = ((ASTPrecision&) decl).fPrecision;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
ABORT("unsupported declaration: %s\n", decl.description().c_str());
|
||||
}
|
||||
@ -190,16 +208,18 @@ std::unique_ptr<Program> Compiler::convertProgram(Program::Kind kind, std::strin
|
||||
fErrorCount = 0;
|
||||
fIRGenerator->pushSymbolTable();
|
||||
std::vector<std::unique_ptr<ProgramElement>> elements;
|
||||
Modifiers::Flag ignored;
|
||||
switch (kind) {
|
||||
case Program::kVertex_Kind:
|
||||
this->internalConvertProgram(SKSL_VERT_INCLUDE, &elements);
|
||||
this->internalConvertProgram(SKSL_VERT_INCLUDE, &ignored, &elements);
|
||||
break;
|
||||
case Program::kFragment_Kind:
|
||||
this->internalConvertProgram(SKSL_FRAG_INCLUDE, &elements);
|
||||
this->internalConvertProgram(SKSL_FRAG_INCLUDE, &ignored, &elements);
|
||||
break;
|
||||
}
|
||||
this->internalConvertProgram(text, &elements);
|
||||
auto result = std::unique_ptr<Program>(new Program(kind, std::move(elements),
|
||||
Modifiers::Flag defaultPrecision;
|
||||
this->internalConvertProgram(text, &defaultPrecision, &elements);
|
||||
auto result = std::unique_ptr<Program>(new Program(kind, defaultPrecision, std::move(elements),
|
||||
fIRGenerator->fSymbolTable));;
|
||||
fIRGenerator->popSymbolTable();
|
||||
this->writeErrorCount();
|
||||
|
@ -15,6 +15,8 @@
|
||||
#include "SkSLErrorReporter.h"
|
||||
#include "SkSLGLSLCodeGenerator.h"
|
||||
|
||||
#define SK_FRAGCOLOR_BUILTIN 10001
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
class IRGenerator;
|
||||
@ -24,6 +26,8 @@ class IRGenerator;
|
||||
* file into an abstract syntax tree (a tree of ASTNodes), then performs semantic analysis to
|
||||
* produce a Program (a tree of IRNodes), then feeds the Program into a CodeGenerator to produce
|
||||
* compiled output.
|
||||
*
|
||||
* See the README for information about SkSL.
|
||||
*/
|
||||
class Compiler : public ErrorReporter {
|
||||
public:
|
||||
@ -50,6 +54,7 @@ public:
|
||||
private:
|
||||
|
||||
void internalConvertProgram(std::string text,
|
||||
Modifiers::Flag* defaultPrecision,
|
||||
std::vector<std::unique_ptr<ProgramElement>>* result);
|
||||
|
||||
std::shared_ptr<SymbolTable> fTypes;
|
||||
|
@ -60,6 +60,7 @@ public:
|
||||
, fSampler1D_Type(new Type("sampler1D", SpvDim1D, false, false, false, true))
|
||||
, fSampler2D_Type(new Type("sampler2D", SpvDim2D, false, false, false, true))
|
||||
, fSampler3D_Type(new Type("sampler3D", SpvDim3D, false, false, false, true))
|
||||
, fSamplerExternalOES_Type(new Type("samplerExternalOES", SpvDim2D, false, false, false, true))
|
||||
, fSamplerCube_Type(new Type("samplerCube"))
|
||||
, fSampler2DRect_Type(new Type("sampler2DRect"))
|
||||
, fSampler1DArray_Type(new Type("sampler1DArray"))
|
||||
@ -169,6 +170,7 @@ public:
|
||||
const std::unique_ptr<Type> fSampler1D_Type;
|
||||
const std::unique_ptr<Type> fSampler2D_Type;
|
||||
const std::unique_ptr<Type> fSampler3D_Type;
|
||||
const std::unique_ptr<Type> fSamplerExternalOES_Type;
|
||||
const std::unique_ptr<Type> fSamplerCube_Type;
|
||||
const std::unique_ptr<Type> fSampler2DRect_Type;
|
||||
const std::unique_ptr<Type> fSampler1DArray_Type;
|
||||
|
@ -14,8 +14,11 @@
|
||||
#include "ir/SkSLExpressionStatement.h"
|
||||
#include "ir/SkSLExtension.h"
|
||||
#include "ir/SkSLIndexExpression.h"
|
||||
#include "ir/SkSLModifiersDeclaration.h"
|
||||
#include "ir/SkSLVariableReference.h"
|
||||
|
||||
#define SK_FRAGCOLOR_BUILTIN 10001
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
void GLSLCodeGenerator::write(const char* s) {
|
||||
@ -66,7 +69,7 @@ void GLSLCodeGenerator::writeType(const Type& type) {
|
||||
this->writeLine("struct " + type.name() + " {");
|
||||
fIndentation++;
|
||||
for (const auto& f : type.fields()) {
|
||||
this->writeModifiers(f.fModifiers);
|
||||
this->writeModifiers(f.fModifiers, false);
|
||||
// sizes (which must be static in structs) are part of the type name here
|
||||
this->writeType(*f.fType);
|
||||
this->writeLine(" " + f.fName + ";");
|
||||
@ -124,7 +127,42 @@ void GLSLCodeGenerator::writeExpression(const Expression& expr, Precedence paren
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_abs(Expression& expr) {
|
||||
if (expr.fKind != Expression::kFunctionCall_Kind) {
|
||||
return false;
|
||||
}
|
||||
return ((FunctionCall&) expr).fFunction.fName == "abs";
|
||||
}
|
||||
|
||||
// turns min(abs(x), y) into ((tmpVar1 = abs(x)) < (tmpVar2 = y) ? tmpVar1 : tmpVar2) to avoid a
|
||||
// Tegra3 compiler bug.
|
||||
void GLSLCodeGenerator::writeMinAbsHack(Expression& absExpr, Expression& otherExpr) {
|
||||
ASSERT(!fCaps.fCanUseMinAndAbsTogether);
|
||||
std::string tmpVar1 = "minAbsHackVar" + to_string(fVarCount++);
|
||||
std::string tmpVar2 = "minAbsHackVar" + to_string(fVarCount++);
|
||||
this->fFunctionHeader += " " + absExpr.fType.name() + " " + tmpVar1 + ";\n";
|
||||
this->fFunctionHeader += " " + otherExpr.fType.name() + " " + tmpVar2 + ";\n";
|
||||
this->write("((" + tmpVar1 + " = ");
|
||||
this->writeExpression(absExpr, kTopLevel_Precedence);
|
||||
this->write(") < (" + tmpVar2 + " = ");
|
||||
this->writeExpression(otherExpr, kAssignment_Precedence);
|
||||
this->write(") ? " + tmpVar1 + " : " + tmpVar2 + ")");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeFunctionCall(const FunctionCall& c) {
|
||||
if (!fCaps.fCanUseMinAndAbsTogether && c.fFunction.fName == "min") {
|
||||
ASSERT(c.fArguments.size() == 2);
|
||||
if (is_abs(*c.fArguments[0])) {
|
||||
this->writeMinAbsHack(*c.fArguments[0], *c.fArguments[1]);
|
||||
return;
|
||||
}
|
||||
if (is_abs(*c.fArguments[1])) {
|
||||
// note that this violates the GLSL left-to-right evaluation semantics. I doubt it will
|
||||
// ever end up mattering, but it's worth calling out.
|
||||
this->writeMinAbsHack(*c.fArguments[1], *c.fArguments[0]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
this->write(c.fFunction.fName + "(");
|
||||
const char* separator = "";
|
||||
for (const auto& arg : c.fArguments) {
|
||||
@ -147,7 +185,15 @@ void GLSLCodeGenerator::writeConstructor(const Constructor& c) {
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeVariableReference(const VariableReference& ref) {
|
||||
this->write(ref.fVariable.fName);
|
||||
if (ref.fVariable.fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN) {
|
||||
if (fCaps.fMustDeclareFragmentShaderOutput) {
|
||||
this->write("sk_FragColor");
|
||||
} else {
|
||||
this->write("gl_FragColor");
|
||||
}
|
||||
} else {
|
||||
this->write(ref.fVariable.fName);
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeIndexExpression(const IndexExpression& expr) {
|
||||
@ -270,7 +316,11 @@ void GLSLCodeGenerator::writeBoolLiteral(const BoolLiteral& b) {
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeIntLiteral(const IntLiteral& i) {
|
||||
this->write(to_string(i.fValue));
|
||||
if (i.fType == *fContext.fUInt_Type) {
|
||||
this->write(to_string(i.fValue & 0xffffffff) + "u");
|
||||
} else {
|
||||
this->write(to_string((int32_t) i.fValue));
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeFloatLiteral(const FloatLiteral& f) {
|
||||
@ -284,28 +334,99 @@ void GLSLCodeGenerator::writeFunction(const FunctionDefinition& f) {
|
||||
for (const auto& param : f.fDeclaration.fParameters) {
|
||||
this->write(separator);
|
||||
separator = ", ";
|
||||
this->writeModifiers(param->fModifiers);
|
||||
this->writeType(param->fType);
|
||||
this->writeModifiers(param->fModifiers, false);
|
||||
std::vector<int> sizes;
|
||||
const Type* type = ¶m->fType;
|
||||
while (type->kind() == Type::kArray_Kind) {
|
||||
sizes.push_back(type->columns());
|
||||
type = &type->componentType();
|
||||
}
|
||||
this->writeType(*type);
|
||||
this->write(" " + param->fName);
|
||||
for (int s : sizes) {
|
||||
if (s <= 0) {
|
||||
this->write("[]");
|
||||
} else {
|
||||
this->write("[" + to_string(s) + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
this->write(") ");
|
||||
this->writeBlock(*f.fBody);
|
||||
this->writeLine();
|
||||
this->writeLine(") {");
|
||||
|
||||
fFunctionHeader = "";
|
||||
std::ostream* oldOut = fOut;
|
||||
std::stringstream buffer;
|
||||
fOut = &buffer;
|
||||
fIndentation++;
|
||||
for (const auto& s : f.fBody->fStatements) {
|
||||
this->writeStatement(*s);
|
||||
this->writeLine();
|
||||
}
|
||||
fIndentation--;
|
||||
this->writeLine("}");
|
||||
|
||||
fOut = oldOut;
|
||||
this->write(fFunctionHeader);
|
||||
this->write(buffer.str());
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers) {
|
||||
this->write(modifiers.description());
|
||||
void GLSLCodeGenerator::writeModifiers(const Modifiers& modifiers,
|
||||
bool globalContext) {
|
||||
if (modifiers.fFlags & Modifiers::kNoPerspective_Flag) {
|
||||
this->write("noperspective ");
|
||||
}
|
||||
if (modifiers.fFlags & Modifiers::kFlat_Flag) {
|
||||
this->write("flat ");
|
||||
}
|
||||
std::string layout = modifiers.fLayout.description();
|
||||
if (layout.length()) {
|
||||
this->write(layout + " ");
|
||||
}
|
||||
if ((modifiers.fFlags & Modifiers::kIn_Flag) &&
|
||||
(modifiers.fFlags & Modifiers::kOut_Flag)) {
|
||||
this->write("inout ");
|
||||
} else if (modifiers.fFlags & Modifiers::kIn_Flag) {
|
||||
if (globalContext && fCaps.fVersion < 130) {
|
||||
this->write(fProgramKind == Program::kVertex_Kind ? "attribute "
|
||||
: "varying ");
|
||||
} else {
|
||||
this->write("in ");
|
||||
}
|
||||
} else if (modifiers.fFlags & Modifiers::kOut_Flag) {
|
||||
if (globalContext && fCaps.fVersion < 130) {
|
||||
this->write("varying ");
|
||||
} else {
|
||||
this->write("out ");
|
||||
}
|
||||
}
|
||||
if (modifiers.fFlags & Modifiers::kUniform_Flag) {
|
||||
this->write("uniform ");
|
||||
}
|
||||
if (modifiers.fFlags & Modifiers::kConst_Flag) {
|
||||
this->write("const ");
|
||||
}
|
||||
if (fCaps.fUsesPrecisionModifiers) {
|
||||
if (modifiers.fFlags & Modifiers::kLowp_Flag) {
|
||||
this->write("lowp ");
|
||||
}
|
||||
if (modifiers.fFlags & Modifiers::kMediump_Flag) {
|
||||
this->write("mediump ");
|
||||
}
|
||||
if (modifiers.fFlags & Modifiers::kHighp_Flag) {
|
||||
this->write("highp ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
|
||||
if (intf.fVariable.fName == "gl_PerVertex") {
|
||||
return;
|
||||
}
|
||||
this->writeModifiers(intf.fVariable.fModifiers);
|
||||
this->writeModifiers(intf.fVariable.fModifiers, true);
|
||||
this->writeLine(intf.fVariable.fType.name() + " {");
|
||||
fIndentation++;
|
||||
for (const auto& f : intf.fVariable.fType.fields()) {
|
||||
this->writeModifiers(f.fModifiers);
|
||||
this->writeModifiers(f.fModifiers, false);
|
||||
this->writeType(*f.fType);
|
||||
this->writeLine(" " + f.fName + ";");
|
||||
}
|
||||
@ -313,9 +434,9 @@ void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
|
||||
this->writeLine("};");
|
||||
}
|
||||
|
||||
void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl) {
|
||||
void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl, bool global) {
|
||||
ASSERT(decl.fVars.size() > 0);
|
||||
this->writeModifiers(decl.fVars[0].fVar->fModifiers);
|
||||
this->writeModifiers(decl.fVars[0].fVar->fModifiers, global);
|
||||
this->writeType(decl.fBaseType);
|
||||
std::string separator = " ";
|
||||
for (const auto& var : decl.fVars) {
|
||||
@ -325,7 +446,9 @@ void GLSLCodeGenerator::writeVarDeclarations(const VarDeclarations& decl) {
|
||||
this->write(var.fVar->fName);
|
||||
for (const auto& size : var.fSizes) {
|
||||
this->write("[");
|
||||
this->writeExpression(*size, kTopLevel_Precedence);
|
||||
if (size) {
|
||||
this->writeExpression(*size, kTopLevel_Precedence);
|
||||
}
|
||||
this->write("]");
|
||||
}
|
||||
if (var.fValue) {
|
||||
@ -349,7 +472,7 @@ void GLSLCodeGenerator::writeStatement(const Statement& s) {
|
||||
this->writeReturnStatement((ReturnStatement&) s);
|
||||
break;
|
||||
case Statement::kVarDeclarations_Kind:
|
||||
this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration);
|
||||
this->writeVarDeclarations(*((VarDeclarationsStatement&) s).fDeclaration, false);
|
||||
break;
|
||||
case Statement::kIf_Kind:
|
||||
this->writeIfStatement((IfStatement&) s);
|
||||
@ -444,22 +567,57 @@ void GLSLCodeGenerator::writeReturnStatement(const ReturnStatement& r) {
|
||||
void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out) {
|
||||
ASSERT(fOut == nullptr);
|
||||
fOut = &out;
|
||||
fProgramKind = program.fKind;
|
||||
this->write("#version " + to_string(fCaps.fVersion));
|
||||
if (fCaps.fStandard == GLCaps::kGLES_Standard) {
|
||||
if (fCaps.fStandard == GLCaps::kGLES_Standard && fCaps.fVersion >= 300) {
|
||||
this->write(" es");
|
||||
} else if (fCaps.fIsCoreProfile) {
|
||||
this->write(" core");
|
||||
}
|
||||
this->writeLine();
|
||||
for (const auto& e : program.fElements) {
|
||||
if (e->fKind == ProgramElement::kExtension_Kind) {
|
||||
this->writeExtension((Extension&) *e);
|
||||
}
|
||||
}
|
||||
if (fCaps.fStandard == GLCaps::kGLES_Standard) {
|
||||
this->write("precision ");
|
||||
switch (program.fDefaultPrecision) {
|
||||
case Modifiers::kLowp_Flag:
|
||||
this->write("lowp");
|
||||
break;
|
||||
case Modifiers::kMediump_Flag:
|
||||
this->write("mediump");
|
||||
break;
|
||||
case Modifiers::kHighp_Flag:
|
||||
this->write("highp");
|
||||
break;
|
||||
default:
|
||||
ASSERT(false);
|
||||
this->write("<error>");
|
||||
}
|
||||
this->writeLine(" float;");
|
||||
}
|
||||
for (const auto& e : program.fElements) {
|
||||
switch (e->fKind) {
|
||||
case ProgramElement::kExtension_Kind:
|
||||
this->writeExtension((Extension&) *e);
|
||||
break;
|
||||
case ProgramElement::kVar_Kind: {
|
||||
VarDeclarations& decl = (VarDeclarations&) *e;
|
||||
if (decl.fVars.size() > 0 &&
|
||||
decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin == -1) {
|
||||
this->writeVarDeclarations(decl);
|
||||
this->writeLine();
|
||||
if (decl.fVars.size() > 0) {
|
||||
int builtin = decl.fVars[0].fVar->fModifiers.fLayout.fBuiltin;
|
||||
if (builtin == -1) {
|
||||
// normal var
|
||||
this->writeVarDeclarations(decl, true);
|
||||
this->writeLine();
|
||||
} else if (builtin == SK_FRAGCOLOR_BUILTIN &&
|
||||
fCaps.fMustDeclareFragmentShaderOutput) {
|
||||
this->write("out ");
|
||||
if (fCaps.fUsesPrecisionModifiers) {
|
||||
this->write("mediump ");
|
||||
}
|
||||
this->writeLine("vec4 sk_FragColor;");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -469,6 +627,10 @@ void GLSLCodeGenerator::generateCode(const Program& program, std::ostream& out)
|
||||
case ProgramElement::kFunction_Kind:
|
||||
this->writeFunction((FunctionDefinition&) *e);
|
||||
break;
|
||||
case ProgramElement::kModifiers_Kind:
|
||||
this->writeModifiers(((ModifiersDeclaration&) *e).fModifiers, true);
|
||||
this->writeLine(";");
|
||||
break;
|
||||
default:
|
||||
printf("%s\n", e->description().c_str());
|
||||
ABORT("unsupported program element");
|
||||
|
@ -50,6 +50,11 @@ struct GLCaps {
|
||||
kGL_Standard,
|
||||
kGLES_Standard
|
||||
} fStandard;
|
||||
bool fIsCoreProfile;
|
||||
bool fUsesPrecisionModifiers;
|
||||
bool fMustDeclareFragmentShaderOutput;
|
||||
// The Tegra3 compiler will sometimes never return if we have min(abs(x), y)
|
||||
bool fCanUseMinAndAbsTogether;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -81,6 +86,8 @@ public:
|
||||
GLSLCodeGenerator(const Context* context, GLCaps caps)
|
||||
: fContext(*context)
|
||||
, fCaps(caps)
|
||||
, fOut(nullptr)
|
||||
, fVarCount(0)
|
||||
, fIndentation(0)
|
||||
, fAtLineStart(true) {}
|
||||
|
||||
@ -111,11 +118,11 @@ private:
|
||||
|
||||
void writeLayout(const Layout& layout);
|
||||
|
||||
void writeModifiers(const Modifiers& modifiers);
|
||||
void writeModifiers(const Modifiers& modifiers, bool globalContext);
|
||||
|
||||
void writeGlobalVars(const VarDeclaration& vs);
|
||||
|
||||
void writeVarDeclarations(const VarDeclarations& decl);
|
||||
void writeVarDeclarations(const VarDeclarations& decl, bool global);
|
||||
|
||||
void writeVariableReference(const VariableReference& ref);
|
||||
|
||||
@ -123,6 +130,8 @@ private:
|
||||
|
||||
void writeIntrinsicCall(const FunctionCall& c);
|
||||
|
||||
void writeMinAbsHack(Expression& absExpr, Expression& otherExpr);
|
||||
|
||||
void writeFunctionCall(const FunctionCall& c);
|
||||
|
||||
void writeConstructor(const Constructor& c);
|
||||
@ -164,6 +173,9 @@ private:
|
||||
const Context& fContext;
|
||||
const GLCaps fCaps;
|
||||
std::ostream* fOut;
|
||||
std::string fFunctionHeader;
|
||||
Program::Kind fProgramKind;
|
||||
int fVarCount;
|
||||
int fIndentation;
|
||||
bool fAtLineStart;
|
||||
// Keeps track of which struct types we have written. Given that we are unlikely to ever write
|
||||
|
@ -189,7 +189,11 @@ std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTVa
|
||||
}
|
||||
value = this->coerce(std::move(value), *type);
|
||||
}
|
||||
if ("gl_FragCoord" == varDecl.fName && (*fSymbolTable)[varDecl.fName]) {
|
||||
if ("sk_FragColor" == varDecl.fName && (*fSymbolTable)[varDecl.fName]) {
|
||||
// already defined, ignore
|
||||
} else if ((*fSymbolTable)[varDecl.fName] &&
|
||||
(*fSymbolTable)[varDecl.fName]->fKind == Symbol::kVariable_Kind &&
|
||||
((Variable*) (*fSymbolTable)[varDecl.fName])->fModifiers.fLayout.fBuiltin >= 0) {
|
||||
// already defined, just update the modifiers
|
||||
Variable* old = (Variable*) (*fSymbolTable)[varDecl.fName];
|
||||
old->fModifiers = var->fModifiers;
|
||||
@ -203,6 +207,12 @@ std::unique_ptr<VarDeclarations> IRGenerator::convertVarDeclarations(const ASTVa
|
||||
std::move(variables)));
|
||||
}
|
||||
|
||||
std::unique_ptr<ModifiersDeclaration> IRGenerator::convertModifiersDeclaration(
|
||||
const ASTModifiersDeclaration& m) {
|
||||
Modifiers modifiers = this->convertModifiers(m.fModifiers);
|
||||
return std::unique_ptr<ModifiersDeclaration>(new ModifiersDeclaration(modifiers));
|
||||
}
|
||||
|
||||
std::unique_ptr<Statement> IRGenerator::convertIf(const ASTIfStatement& s) {
|
||||
std::unique_ptr<Expression> test = this->coerce(this->convertExpression(*s.fTest),
|
||||
*fContext.fBool_Type);
|
||||
@ -419,8 +429,9 @@ std::unique_ptr<FunctionDefinition> IRGenerator::convertFunction(const ASTFuncti
|
||||
for (size_t i = 0; i < parameters.size(); i++) {
|
||||
if (parameters[i]->fModifiers != other->fParameters[i]->fModifiers) {
|
||||
fErrors.error(f.fPosition, "modifiers on parameter " +
|
||||
to_string(i + 1) + " differ between " +
|
||||
"declaration and definition");
|
||||
to_string((uint64_t) i + 1) +
|
||||
" differ between declaration and "
|
||||
"definition");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
@ -616,8 +627,9 @@ std::unique_ptr<Expression> IRGenerator::coerce(std::unique_ptr<Expression> expr
|
||||
ASSERT(ctor);
|
||||
return this->call(Position(), std::move(ctor), std::move(args));
|
||||
}
|
||||
ABORT("cannot coerce %s to %s", expr->fType.description().c_str(),
|
||||
type.description().c_str());
|
||||
std::vector<std::unique_ptr<Expression>> args;
|
||||
args.push_back(std::move(expr));
|
||||
return std::unique_ptr<Expression>(new Constructor(Position(), type, std::move(args)));
|
||||
}
|
||||
|
||||
static bool is_matrix_multiply(const Type& left, const Type& right) {
|
||||
@ -832,12 +844,12 @@ std::unique_ptr<Expression> IRGenerator::call(Position position,
|
||||
std::vector<std::unique_ptr<Expression>> arguments) {
|
||||
if (function.fParameters.size() != arguments.size()) {
|
||||
std::string msg = "call to '" + function.fName + "' expected " +
|
||||
to_string(function.fParameters.size()) +
|
||||
to_string((uint64_t) function.fParameters.size()) +
|
||||
" argument";
|
||||
if (function.fParameters.size() != 1) {
|
||||
msg += "s";
|
||||
}
|
||||
msg += ", but found " + to_string(arguments.size());
|
||||
msg += ", but found " + to_string((uint64_t) arguments.size());
|
||||
fErrors.error(position, msg);
|
||||
return nullptr;
|
||||
}
|
||||
@ -921,7 +933,8 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(
|
||||
std::vector<std::unique_ptr<Expression>> args) {
|
||||
// FIXME: add support for structs and arrays
|
||||
Type::Kind kind = type.kind();
|
||||
if (!type.isNumber() && kind != Type::kVector_Kind && kind != Type::kMatrix_Kind) {
|
||||
if (!type.isNumber() && kind != Type::kVector_Kind && kind != Type::kMatrix_Kind &&
|
||||
kind != Type::kArray_Kind) {
|
||||
fErrors.error(position, "cannot construct '" + type.description() + "'");
|
||||
return nullptr;
|
||||
}
|
||||
@ -938,7 +951,7 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(
|
||||
if (args.size() != 1) {
|
||||
fErrors.error(position, "invalid arguments to '" + type.description() +
|
||||
"' constructor, (expected exactly 1 argument, but found " +
|
||||
to_string(args.size()) + ")");
|
||||
to_string((uint64_t) args.size()) + ")");
|
||||
}
|
||||
if (args[0]->fType == *fContext.fBool_Type) {
|
||||
std::unique_ptr<IntLiteral> zero(new IntLiteral(fContext, position, 0));
|
||||
@ -953,6 +966,18 @@ std::unique_ptr<Expression> IRGenerator::convertConstructor(
|
||||
"' constructor (expected a number or bool, but found '" +
|
||||
args[0]->fType.description() + "')");
|
||||
}
|
||||
if (args[0]->fKind == Expression::kIntLiteral_Kind && (type == *fContext.fInt_Type ||
|
||||
type == *fContext.fUInt_Type)) {
|
||||
return std::unique_ptr<Expression>(new IntLiteral(fContext,
|
||||
position,
|
||||
((IntLiteral&) *args[0]).fValue,
|
||||
&type));
|
||||
}
|
||||
} else if (kind == Type::kArray_Kind) {
|
||||
const Type& base = type.componentType();
|
||||
for (size_t i = 0; i < args.size(); i++) {
|
||||
args[i] = this->coerce(std::move(args[i]), base);
|
||||
}
|
||||
} else {
|
||||
ASSERT(kind == Type::kVector_Kind || kind == Type::kMatrix_Kind);
|
||||
int actual = 0;
|
||||
@ -1037,7 +1062,7 @@ std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(
|
||||
}
|
||||
this->markWrittenTo(*base);
|
||||
break;
|
||||
case Token::NOT:
|
||||
case Token::LOGICALNOT:
|
||||
if (base->fType != *fContext.fBool_Type) {
|
||||
fErrors.error(expression.fPosition,
|
||||
"'" + Token::OperatorName(expression.fOperator) +
|
||||
@ -1045,6 +1070,14 @@ std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
case Token::BITWISENOT:
|
||||
if (base->fType != *fContext.fInt_Type) {
|
||||
fErrors.error(expression.fPosition,
|
||||
"'" + Token::OperatorName(expression.fOperator) +
|
||||
"' cannot operate on '" + base->fType.description() + "'");
|
||||
return nullptr;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
ABORT("unsupported prefix operator\n");
|
||||
}
|
||||
@ -1054,7 +1087,8 @@ std::unique_ptr<Expression> IRGenerator::convertPrefixExpression(
|
||||
|
||||
std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression> base,
|
||||
const ASTExpression& index) {
|
||||
if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind) {
|
||||
if (base->fType.kind() != Type::kArray_Kind && base->fType.kind() != Type::kMatrix_Kind &&
|
||||
base->fType.kind() != Type::kVector_Kind) {
|
||||
fErrors.error(base->fPosition, "expected array, but found '" + base->fType.description() +
|
||||
"'");
|
||||
return nullptr;
|
||||
@ -1063,9 +1097,11 @@ std::unique_ptr<Expression> IRGenerator::convertIndex(std::unique_ptr<Expression
|
||||
if (!converted) {
|
||||
return nullptr;
|
||||
}
|
||||
converted = this->coerce(std::move(converted), *fContext.fInt_Type);
|
||||
if (!converted) {
|
||||
return nullptr;
|
||||
if (converted->fType != *fContext.fUInt_Type) {
|
||||
converted = this->coerce(std::move(converted), *fContext.fInt_Type);
|
||||
if (!converted) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
return std::unique_ptr<Expression>(new IndexExpression(fContext, std::move(base),
|
||||
std::move(converted)));
|
||||
@ -1143,9 +1179,21 @@ std::unique_ptr<Expression> IRGenerator::convertSuffixExpression(
|
||||
return nullptr;
|
||||
}
|
||||
switch (expression.fSuffix->fKind) {
|
||||
case ASTSuffix::kIndex_Kind:
|
||||
return this->convertIndex(std::move(base),
|
||||
*((ASTIndexSuffix&) *expression.fSuffix).fExpression);
|
||||
case ASTSuffix::kIndex_Kind: {
|
||||
const ASTExpression* expr = ((ASTIndexSuffix&) *expression.fSuffix).fExpression.get();
|
||||
if (expr) {
|
||||
return this->convertIndex(std::move(base), *expr);
|
||||
} else if (base->fKind == Expression::kTypeReference_Kind) {
|
||||
const Type& oldType = ((TypeReference&) *base).fValue;
|
||||
Type* newType = new Type(oldType.name() + "[]", Type::kArray_Kind, oldType,
|
||||
-1);
|
||||
fSymbolTable->takeOwnership(newType);
|
||||
return std::unique_ptr<Expression>(new TypeReference(fContext, base->fPosition,
|
||||
*newType));
|
||||
} else {
|
||||
fErrors.error(expression.fPosition, "'[]' must follow a type name");
|
||||
}
|
||||
}
|
||||
case ASTSuffix::kCall_Kind: {
|
||||
auto rawArguments = &((ASTCallSuffix&) *expression.fSuffix).fArguments;
|
||||
std::vector<std::unique_ptr<Expression>> arguments;
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "ast/SkSLASTIfStatement.h"
|
||||
#include "ast/SkSLASTInterfaceBlock.h"
|
||||
#include "ast/SkSLASTModifiers.h"
|
||||
#include "ast/SkSLASTModifiersDeclaration.h"
|
||||
#include "ast/SkSLASTPrefixExpression.h"
|
||||
#include "ast/SkSLASTReturnStatement.h"
|
||||
#include "ast/SkSLASTStatement.h"
|
||||
@ -39,6 +40,7 @@
|
||||
#include "ir/SkSLFunctionDefinition.h"
|
||||
#include "ir/SkSLInterfaceBlock.h"
|
||||
#include "ir/SkSLModifiers.h"
|
||||
#include "ir/SkSLModifiersDeclaration.h"
|
||||
#include "ir/SkSLSymbolTable.h"
|
||||
#include "ir/SkSLStatement.h"
|
||||
#include "ir/SkSLType.h"
|
||||
@ -61,6 +63,8 @@ public:
|
||||
std::unique_ptr<FunctionDefinition> convertFunction(const ASTFunction& f);
|
||||
std::unique_ptr<Statement> convertStatement(const ASTStatement& statement);
|
||||
std::unique_ptr<Expression> convertExpression(const ASTExpression& expression);
|
||||
std::unique_ptr<ModifiersDeclaration> convertModifiersDeclaration(
|
||||
const ASTModifiersDeclaration& m);
|
||||
|
||||
private:
|
||||
void pushSymbolTable();
|
||||
|
@ -9,6 +9,24 @@
|
||||
#include <fstream>
|
||||
#include "SkSLCompiler.h"
|
||||
|
||||
bool endsWith(const std::string& s, const std::string& ending) {
|
||||
if (s.length() >= ending.length()) {
|
||||
return (0 == s.compare(s.length() - ending.length(), ending.length(), ending));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static SkSL::GLCaps default_caps() {
|
||||
return {
|
||||
400,
|
||||
SkSL::GLCaps::kGL_Standard,
|
||||
false, // isCoreProfile
|
||||
false, // usesPrecisionModifiers;
|
||||
false, // mustDeclareFragmentShaderOutput
|
||||
true // canUseMinAndAbsTogether
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Very simple standalone executable to facilitate testing.
|
||||
*/
|
||||
@ -35,14 +53,30 @@ int main(int argc, const char** argv) {
|
||||
printf("error reading '%s'\n", argv[1]);
|
||||
exit(2);
|
||||
}
|
||||
std::ofstream out(argv[2], std::ofstream::binary);
|
||||
SkSL::Compiler compiler;
|
||||
if (!compiler.toSPIRV(kind, text, out)) {
|
||||
printf("%s", compiler.errorText().c_str());
|
||||
exit(3);
|
||||
}
|
||||
if (out.rdstate()) {
|
||||
printf("error writing '%s'\n", argv[2]);
|
||||
exit(4);
|
||||
std::string name(argv[2]);
|
||||
if (endsWith(name, ".spirv")) {
|
||||
std::ofstream out(argv[2], std::ofstream::binary);
|
||||
SkSL::Compiler compiler;
|
||||
if (!compiler.toSPIRV(kind, text, out)) {
|
||||
printf("%s", compiler.errorText().c_str());
|
||||
exit(3);
|
||||
}
|
||||
if (out.rdstate()) {
|
||||
printf("error writing '%s'\n", argv[2]);
|
||||
exit(4);
|
||||
}
|
||||
} else if (endsWith(name, ".glsl")) {
|
||||
std::ofstream out(argv[2], std::ofstream::binary);
|
||||
SkSL::Compiler compiler;
|
||||
if (!compiler.toGLSL(kind, text, default_caps(), out)) {
|
||||
printf("%s", compiler.errorText().c_str());
|
||||
exit(3);
|
||||
}
|
||||
if (out.rdstate()) {
|
||||
printf("error writing '%s'\n", argv[2]);
|
||||
exit(4);
|
||||
}
|
||||
} else {
|
||||
printf("expected output filename to end with '.spirv' or '.glsl'");
|
||||
}
|
||||
}
|
||||
|
@ -56,7 +56,9 @@
|
||||
#include "ast/SkSLASTIndexSuffix.h"
|
||||
#include "ast/SkSLASTInterfaceBlock.h"
|
||||
#include "ast/SkSLASTIntLiteral.h"
|
||||
#include "ast/SkSLASTModifiersDeclaration.h"
|
||||
#include "ast/SkSLASTParameter.h"
|
||||
#include "ast/SkSLASTPrecision.h"
|
||||
#include "ast/SkSLASTPrefixExpression.h"
|
||||
#include "ast/SkSLASTReturnStatement.h"
|
||||
#include "ast/SkSLASTStatement.h"
|
||||
@ -97,9 +99,13 @@ std::vector<std::unique_ptr<ASTDeclaration>> Parser::file() {
|
||||
switch (this->peek().fKind) {
|
||||
case Token::END_OF_FILE:
|
||||
return result;
|
||||
case Token::PRECISION:
|
||||
this->precision();
|
||||
case Token::PRECISION: {
|
||||
std::unique_ptr<ASTDeclaration> precision = this->precision();
|
||||
if (precision) {
|
||||
result.push_back(std::move(precision));
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Token::DIRECTIVE: {
|
||||
std::unique_ptr<ASTDeclaration> decl = this->directive();
|
||||
if (decl) {
|
||||
@ -163,29 +169,37 @@ bool Parser::isType(std::string name) {
|
||||
}
|
||||
|
||||
/* PRECISION (LOWP | MEDIUMP | HIGHP) type SEMICOLON */
|
||||
void Parser::precision() {
|
||||
std::unique_ptr<ASTDeclaration> Parser::precision() {
|
||||
if (!this->expect(Token::PRECISION, "'precision'")) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
Modifiers::Flag result;
|
||||
Token p = this->nextToken();
|
||||
switch (p.fKind) {
|
||||
case Token::LOWP: // fall through
|
||||
case Token::MEDIUMP: // fall through
|
||||
case Token::LOWP:
|
||||
result = Modifiers::kLowp_Flag;
|
||||
break;
|
||||
case Token::MEDIUMP:
|
||||
result = Modifiers::kMediump_Flag;
|
||||
break;
|
||||
case Token::HIGHP:
|
||||
// ignored for now
|
||||
result = Modifiers::kHighp_Flag;
|
||||
break;
|
||||
default:
|
||||
this->error(p.fPosition, "expected 'lowp', 'mediump', or 'highp', but found '" +
|
||||
p.fText + "'");
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
// FIXME handle the type
|
||||
if (!this->type()) {
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
this->expect(Token::SEMICOLON, "';'");
|
||||
return std::unique_ptr<ASTDeclaration>(new ASTPrecision(p.fPosition, result));
|
||||
}
|
||||
|
||||
/* DIRECTIVE(#version) INT_LITERAL | DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
|
||||
/* DIRECTIVE(#version) INT_LITERAL ("es" | "compatibility")? |
|
||||
DIRECTIVE(#extension) IDENTIFIER COLON IDENTIFIER */
|
||||
std::unique_ptr<ASTDeclaration> Parser::directive() {
|
||||
Token start;
|
||||
if (!this->expect(Token::DIRECTIVE, "a directive", &start)) {
|
||||
@ -193,7 +207,12 @@ std::unique_ptr<ASTDeclaration> Parser::directive() {
|
||||
}
|
||||
if (start.fText == "#version") {
|
||||
this->expect(Token::INT_LITERAL, "a version number");
|
||||
// ignored for now
|
||||
Token next = this->peek();
|
||||
if (next.fText == "es" || next.fText == "compatibility") {
|
||||
this->nextToken();
|
||||
}
|
||||
// version is ignored for now; it will eventually become an error when we stop pretending
|
||||
// to be GLSL
|
||||
return nullptr;
|
||||
} else if (start.fText == "#extension") {
|
||||
Token name;
|
||||
@ -227,6 +246,10 @@ std::unique_ptr<ASTDeclaration> Parser::declaration() {
|
||||
if (lookahead.fKind == Token::STRUCT) {
|
||||
return this->structVarDeclaration(modifiers);
|
||||
}
|
||||
if (lookahead.fKind == Token::SEMICOLON) {
|
||||
this->nextToken();
|
||||
return std::unique_ptr<ASTDeclaration>(new ASTModifiersDeclaration(modifiers));
|
||||
}
|
||||
std::unique_ptr<ASTType> type(this->type());
|
||||
if (!type) {
|
||||
return nullptr;
|
||||
@ -477,10 +500,13 @@ ASTLayout Parser::layout() {
|
||||
int set = -1;
|
||||
int builtin = -1;
|
||||
bool originUpperLeft = false;
|
||||
bool overrideCoverage = false;
|
||||
bool blendSupportAllEquations = false;
|
||||
if (this->peek().fKind == Token::LAYOUT) {
|
||||
this->nextToken();
|
||||
if (!this->expect(Token::LPAREN, "'('")) {
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft,
|
||||
overrideCoverage, blendSupportAllEquations);
|
||||
}
|
||||
for (;;) {
|
||||
Token t = this->nextToken();
|
||||
@ -496,6 +522,10 @@ ASTLayout Parser::layout() {
|
||||
builtin = this->layoutInt();
|
||||
} else if (t.fText == "origin_upper_left") {
|
||||
originUpperLeft = true;
|
||||
} else if (t.fText == "override_coverage") {
|
||||
overrideCoverage = true;
|
||||
} else if (t.fText == "blend_support_all_equations") {
|
||||
blendSupportAllEquations = true;
|
||||
} else {
|
||||
this->error(t.fPosition, ("'" + t.fText +
|
||||
"' is not a valid layout qualifier").c_str());
|
||||
@ -509,7 +539,8 @@ ASTLayout Parser::layout() {
|
||||
}
|
||||
}
|
||||
}
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft);
|
||||
return ASTLayout(location, binding, index, set, builtin, originUpperLeft, overrideCoverage,
|
||||
blendSupportAllEquations);
|
||||
}
|
||||
|
||||
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE)* */
|
||||
@ -1211,10 +1242,11 @@ std::unique_ptr<ASTExpression> Parser::multiplicativeExpression() {
|
||||
/* postfixExpression | (PLUS | MINUS | NOT | PLUSPLUS | MINUSMINUS) unaryExpression */
|
||||
std::unique_ptr<ASTExpression> Parser::unaryExpression() {
|
||||
switch (this->peek().fKind) {
|
||||
case Token::PLUS: // fall through
|
||||
case Token::MINUS: // fall through
|
||||
case Token::NOT: // fall through
|
||||
case Token::PLUSPLUS: // fall through
|
||||
case Token::PLUS: // fall through
|
||||
case Token::MINUS: // fall through
|
||||
case Token::LOGICALNOT: // fall through
|
||||
case Token::BITWISENOT: // fall through
|
||||
case Token::PLUSPLUS: // fall through
|
||||
case Token::MINUSMINUS: {
|
||||
Token t = this->nextToken();
|
||||
std::unique_ptr<ASTExpression> expr = this->unaryExpression();
|
||||
@ -1254,12 +1286,16 @@ std::unique_ptr<ASTExpression> Parser::postfixExpression() {
|
||||
}
|
||||
}
|
||||
|
||||
/* LBRACKET expression RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
|
||||
/* LBRACKET expression? RBRACKET | DOT IDENTIFIER | LPAREN parameters RPAREN |
|
||||
PLUSPLUS | MINUSMINUS */
|
||||
std::unique_ptr<ASTSuffix> Parser::suffix() {
|
||||
Token next = this->nextToken();
|
||||
switch (next.fKind) {
|
||||
case Token::LBRACKET: {
|
||||
if (this->peek().fKind == Token::RBRACKET) {
|
||||
this->nextToken();
|
||||
return std::unique_ptr<ASTSuffix>(new ASTIndexSuffix(next.fPosition));
|
||||
}
|
||||
std::unique_ptr<ASTExpression> e = this->expression();
|
||||
if (!e) {
|
||||
return nullptr;
|
||||
|
@ -35,6 +35,7 @@ struct ASTInterfaceBlock;
|
||||
struct ASTLayout;
|
||||
struct ASTModifiers;
|
||||
struct ASTParameter;
|
||||
struct ASTPrecision;
|
||||
struct ASTReturnStatement;
|
||||
struct ASTStatement;
|
||||
struct ASTSuffix;
|
||||
@ -100,7 +101,7 @@ private:
|
||||
// don't need to call any of these outside of the parser. The function declarations in the .cpp
|
||||
// file have comments describing the grammar rules.
|
||||
|
||||
void precision();
|
||||
std::unique_ptr<ASTDeclaration> precision();
|
||||
|
||||
std::unique_ptr<ASTDeclaration> directive();
|
||||
|
||||
|
@ -15,6 +15,7 @@
|
||||
#include "ir/SkSLExtension.h"
|
||||
#include "ir/SkSLIndexExpression.h"
|
||||
#include "ir/SkSLVariableReference.h"
|
||||
#include "SkSLCompiler.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
@ -2162,13 +2163,19 @@ SpvId SPIRVCodeGenerator::writePrefixExpression(const PrefixExpression& p, std::
|
||||
lv->store(result, out);
|
||||
return result;
|
||||
}
|
||||
case Token::NOT: {
|
||||
case Token::LOGICALNOT: {
|
||||
ASSERT(p.fOperand->fType == *fContext.fBool_Type);
|
||||
SpvId result = this->nextId();
|
||||
this->writeInstruction(SpvOpLogicalNot, this->getType(p.fOperand->fType), result,
|
||||
this->writeExpression(*p.fOperand, out), out);
|
||||
return result;
|
||||
}
|
||||
case Token::BITWISENOT: {
|
||||
SpvId result = this->nextId();
|
||||
this->writeInstruction(SpvOpNot, this->getType(p.fOperand->fType), result,
|
||||
this->writeExpression(*p.fOperand, out), out);
|
||||
return result;
|
||||
}
|
||||
default:
|
||||
ABORT("unsupported prefix expression: %s", p.description().c_str());
|
||||
}
|
||||
@ -2321,7 +2328,7 @@ void SPIRVCodeGenerator::writeLayout(const Layout& layout, SpvId target) {
|
||||
this->writeInstruction(SpvOpDecorate, target, SpvDecorationDescriptorSet, layout.fSet,
|
||||
fDecorationBuffer);
|
||||
}
|
||||
if (layout.fBuiltin >= 0) {
|
||||
if (layout.fBuiltin >= 0 && layout.fBuiltin != SK_FRAGCOLOR_BUILTIN) {
|
||||
this->writeInstruction(SpvOpDecorate, target, SpvDecorationBuiltIn, layout.fBuiltin,
|
||||
fDecorationBuffer);
|
||||
}
|
||||
@ -2363,10 +2370,19 @@ SpvId SPIRVCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
|
||||
return result;
|
||||
}
|
||||
|
||||
void SPIRVCodeGenerator::writeGlobalVars(const VarDeclarations& decl, std::ostream& out) {
|
||||
#define BUILTIN_IGNORE 9999
|
||||
void SPIRVCodeGenerator::writeGlobalVars(Program::Kind kind, const VarDeclarations& decl,
|
||||
std::ostream& out) {
|
||||
for (size_t i = 0; i < decl.fVars.size(); i++) {
|
||||
const VarDeclaration& varDecl = decl.fVars[i];
|
||||
const Variable* var = varDecl.fVar;
|
||||
if (var->fModifiers.fLayout.fBuiltin == BUILTIN_IGNORE) {
|
||||
continue;
|
||||
}
|
||||
if (var->fModifiers.fLayout.fBuiltin == SK_FRAGCOLOR_BUILTIN &&
|
||||
kind != Program::kFragment_Kind) {
|
||||
continue;
|
||||
}
|
||||
if (!var->fIsReadFrom && !var->fIsWrittenTo &&
|
||||
!(var->fModifiers.fFlags & (Modifiers::kIn_Flag |
|
||||
Modifiers::kOut_Flag |
|
||||
@ -2562,7 +2578,8 @@ void SPIRVCodeGenerator::writeInstructions(const Program& program, std::ostream&
|
||||
}
|
||||
for (size_t i = 0; i < program.fElements.size(); i++) {
|
||||
if (program.fElements[i]->fKind == ProgramElement::kVar_Kind) {
|
||||
this->writeGlobalVars(((VarDeclarations&) *program.fElements[i]), body);
|
||||
this->writeGlobalVars(program.fKind, ((VarDeclarations&) *program.fElements[i]),
|
||||
body);
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < program.fElements.size(); i++) {
|
||||
|
@ -115,7 +115,7 @@ private:
|
||||
|
||||
SpvId writeFunction(const FunctionDefinition& f, std::ostream& out);
|
||||
|
||||
void writeGlobalVars(const VarDeclarations& v, std::ostream& out);
|
||||
void writeGlobalVars(Program::Kind kind, const VarDeclarations& v, std::ostream& out);
|
||||
|
||||
void writeVarDeclarations(const VarDeclarations& decl, std::ostream& out);
|
||||
|
||||
|
@ -49,10 +49,11 @@ struct Token {
|
||||
BITWISEOR,
|
||||
BITWISEXOR,
|
||||
BITWISEAND,
|
||||
BITWISENOT,
|
||||
LOGICALOR,
|
||||
LOGICALXOR,
|
||||
LOGICALAND,
|
||||
NOT,
|
||||
LOGICALNOT,
|
||||
QUESTION,
|
||||
COLON,
|
||||
EQ,
|
||||
@ -111,9 +112,11 @@ struct Token {
|
||||
case Token::PERCENT: return "%";
|
||||
case Token::SHL: return "<<";
|
||||
case Token::SHR: return ">>";
|
||||
case Token::LOGICALNOT: return "!";
|
||||
case Token::LOGICALAND: return "&&";
|
||||
case Token::LOGICALOR: return "||";
|
||||
case Token::LOGICALXOR: return "^^";
|
||||
case Token::BITWISENOT: return "~";
|
||||
case Token::BITWISEAND: return "&";
|
||||
case Token::BITWISEOR: return "|";
|
||||
case Token::BITWISEXOR: return "^";
|
||||
@ -139,7 +142,6 @@ struct Token {
|
||||
case Token::BITWISEXOREQ: return "^=";
|
||||
case Token::PLUSPLUS: return "++";
|
||||
case Token::MINUSMINUS: return "--";
|
||||
case Token::NOT: return "!";
|
||||
default:
|
||||
ABORT("unsupported operator: %d\n", kind);
|
||||
}
|
||||
|
@ -9,7 +9,48 @@
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
std::string to_string(double value) {
|
||||
std::stringstream buffer;
|
||||
buffer << std::setprecision(std::numeric_limits<double>::digits10) << value;
|
||||
std::string result = buffer.str();
|
||||
if (result.find_last_of(".") == std::string::npos &&
|
||||
result.find_last_of("e") == std::string::npos) {
|
||||
result += ".0";
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
std::string to_string(int32_t value) {
|
||||
std::stringstream buffer;
|
||||
buffer << value;
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::string to_string(uint32_t value) {
|
||||
std::stringstream buffer;
|
||||
buffer << value;
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::string to_string(int64_t value) {
|
||||
std::stringstream buffer;
|
||||
buffer << value;
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
std::string to_string(uint64_t value) {
|
||||
std::stringstream buffer;
|
||||
buffer << value;
|
||||
return buffer.str();
|
||||
}
|
||||
|
||||
int stoi(std::string s) {
|
||||
if (s.size() > 2 && s[0] == '0' && s[1] == 'x') {
|
||||
char* p;
|
||||
int result = strtoul(s.substr(2).c_str(), &p, 16);
|
||||
ASSERT(*p == 0);
|
||||
return result;
|
||||
}
|
||||
return atoi(s.c_str());
|
||||
}
|
||||
|
||||
@ -18,6 +59,12 @@ double stod(std::string s) {
|
||||
}
|
||||
|
||||
long stol(std::string s) {
|
||||
if (s.size() > 2 && s[0] == '0' && s[1] == 'x') {
|
||||
char* p;
|
||||
long result = strtoul(s.substr(2).c_str(), &p, 16);
|
||||
ASSERT(*p == 0);
|
||||
return result;
|
||||
}
|
||||
return atol(s.c_str());
|
||||
}
|
||||
|
||||
|
@ -19,11 +19,15 @@ namespace SkSL {
|
||||
|
||||
// our own definitions of certain std:: functions, because they are not always present on Android
|
||||
|
||||
template <typename T> std::string to_string(T value) {
|
||||
std::stringstream buffer;
|
||||
buffer << std::setprecision(std::numeric_limits<T>::digits10) << value;
|
||||
return buffer.str();
|
||||
}
|
||||
std::string to_string(double value);
|
||||
|
||||
std::string to_string(int32_t value);
|
||||
|
||||
std::string to_string(uint32_t value);
|
||||
|
||||
std::string to_string(int64_t value);
|
||||
|
||||
std::string to_string(uint64_t value);
|
||||
|
||||
#if _MSC_VER
|
||||
#define NORETURN __declspec(noreturn)
|
||||
|
@ -20,7 +20,9 @@ struct ASTDeclaration : public ASTPositionNode {
|
||||
kVar_Kind,
|
||||
kFunction_Kind,
|
||||
kInterfaceBlock_Kind,
|
||||
kExtension_Kind
|
||||
kExtension_Kind,
|
||||
kPrecision_Kind,
|
||||
kModifiers_Kind
|
||||
};
|
||||
|
||||
ASTDeclaration(Position position, Kind kind)
|
||||
|
@ -14,17 +14,27 @@
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* A bracketed expression, as in '[0]', indicating an array access.
|
||||
* A bracketed expression, as in '[0]', indicating an array access. Empty brackets (as occur in
|
||||
* 'float[](5, 6)' are represented with a null fExpression.
|
||||
*/
|
||||
struct ASTIndexSuffix : public ASTSuffix {
|
||||
ASTIndexSuffix(Position position)
|
||||
: INHERITED(position, ASTSuffix::kIndex_Kind)
|
||||
, fExpression(nullptr) {}
|
||||
|
||||
ASTIndexSuffix(std::unique_ptr<ASTExpression> expression)
|
||||
: INHERITED(expression->fPosition, ASTSuffix::kIndex_Kind)
|
||||
: INHERITED(expression ? expression->fPosition : Position(), ASTSuffix::kIndex_Kind)
|
||||
, fExpression(std::move(expression)) {}
|
||||
|
||||
std::string description() const override {
|
||||
return "[" + fExpression->description() + "]";
|
||||
if (fExpression) {
|
||||
return "[" + fExpression->description() + "]";
|
||||
} else {
|
||||
return "[]";
|
||||
}
|
||||
}
|
||||
|
||||
// may be null
|
||||
std::unique_ptr<ASTExpression> fExpression;
|
||||
|
||||
typedef ASTSuffix INHERITED;
|
||||
|
@ -20,13 +20,16 @@ namespace SkSL {
|
||||
*/
|
||||
struct ASTLayout : public ASTNode {
|
||||
// For all parameters, a -1 means no value
|
||||
ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
|
||||
ASTLayout(int location, int binding, int index, int set, int builtin, bool originUpperLeft,
|
||||
bool overrideCoverage, bool blendSupportAllEquations)
|
||||
: fLocation(location)
|
||||
, fBinding(binding)
|
||||
, fIndex(index)
|
||||
, fSet(set)
|
||||
, fBuiltin(builtin)
|
||||
, fOriginUpperLeft(originUpperLeft) {}
|
||||
, fOriginUpperLeft(originUpperLeft)
|
||||
, fOverrideCoverage(overrideCoverage)
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations) {}
|
||||
|
||||
std::string description() const {
|
||||
std::string result;
|
||||
@ -55,6 +58,14 @@ struct ASTLayout : public ASTNode {
|
||||
result += separator + "origin_upper_left";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fOverrideCoverage) {
|
||||
result += separator + "override_coverage";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fBlendSupportAllEquations) {
|
||||
result += separator + "blend_support_all_equations";
|
||||
separator = ", ";
|
||||
}
|
||||
if (result.length() > 0) {
|
||||
result = "layout (" + result + ")";
|
||||
}
|
||||
@ -67,6 +78,8 @@ struct ASTLayout : public ASTNode {
|
||||
const int fSet;
|
||||
const int fBuiltin;
|
||||
const bool fOriginUpperLeft;
|
||||
const bool fOverrideCoverage;
|
||||
const bool fBlendSupportAllEquations;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
37
src/sksl/ast/SkSLASTModifiersDeclaration.h
Normal file
37
src/sksl/ast/SkSLASTModifiersDeclaration.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SKSL_ASTMODIFIERDECLARATION
|
||||
#define SKSL_ASTMODIFIERDECLARATION
|
||||
|
||||
#include "SkSLASTDeclaration.h"
|
||||
#include "SkSLASTModifiers.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* A declaration that consists only of modifiers, e.g.:
|
||||
*
|
||||
* layout(blend_support_all_equations) out;
|
||||
*/
|
||||
struct ASTModifiersDeclaration : public ASTDeclaration {
|
||||
ASTModifiersDeclaration(ASTModifiers modifiers)
|
||||
: INHERITED(Position(), kModifiers_Kind)
|
||||
, fModifiers(modifiers) {}
|
||||
|
||||
std::string description() const {
|
||||
return fModifiers.description() + ";";
|
||||
}
|
||||
|
||||
ASTModifiers fModifiers;
|
||||
|
||||
typedef ASTDeclaration INHERITED;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
45
src/sksl/ast/SkSLASTPrecision.h
Normal file
45
src/sksl/ast/SkSLASTPrecision.h
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SKSL_ASTPRECISION
|
||||
#define SKSL_ASTPRECISION
|
||||
|
||||
#include "SkSLASTDeclaration.h"
|
||||
#include "../ir/SkSLModifiers.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* Represents a precision declaration (e.g. 'precision mediump float;').
|
||||
*/
|
||||
struct ASTPrecision : public ASTDeclaration {
|
||||
// FIXME handle the type
|
||||
ASTPrecision(Position position, Modifiers::Flag precision)
|
||||
: INHERITED(position, kPrecision_Kind)
|
||||
, fPrecision(precision) {}
|
||||
|
||||
std::string description() const {
|
||||
switch (fPrecision) {
|
||||
case Modifiers::kLowp_Flag: return "precision lowp float;";
|
||||
case Modifiers::kMediump_Flag: return "precision mediump float;";
|
||||
case Modifiers::kHighp_Flag: return "precision highp float;";
|
||||
default:
|
||||
ASSERT(false);
|
||||
return "<error>";
|
||||
}
|
||||
ASSERT(false);
|
||||
return "<error>";
|
||||
}
|
||||
|
||||
const Modifiers::Flag fPrecision;
|
||||
|
||||
typedef ASTDeclaration INHERITED;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
@ -19,7 +19,7 @@ namespace SkSL {
|
||||
static const Type& index_type(const Context& context, const Type& type) {
|
||||
if (type.kind() == Type::kMatrix_Kind) {
|
||||
if (type.componentType() == *context.fFloat_Type) {
|
||||
switch (type.columns()) {
|
||||
switch (type.rows()) {
|
||||
case 2: return *context.fVec2_Type;
|
||||
case 3: return *context.fVec3_Type;
|
||||
case 4: return *context.fVec4_Type;
|
||||
@ -27,7 +27,7 @@ static const Type& index_type(const Context& context, const Type& type) {
|
||||
}
|
||||
} else {
|
||||
ASSERT(type.componentType() == *context.fDouble_Type);
|
||||
switch (type.columns()) {
|
||||
switch (type.rows()) {
|
||||
case 2: return *context.fDVec2_Type;
|
||||
case 3: return *context.fDVec3_Type;
|
||||
case 4: return *context.fDVec4_Type;
|
||||
@ -47,7 +47,7 @@ struct IndexExpression : public Expression {
|
||||
: INHERITED(base->fPosition, kIndex_Kind, index_type(context, base->fType))
|
||||
, fBase(std::move(base))
|
||||
, fIndex(std::move(index)) {
|
||||
ASSERT(fIndex->fType == *context.fInt_Type);
|
||||
ASSERT(fIndex->fType == *context.fInt_Type || fIndex->fType == *context.fUInt_Type);
|
||||
}
|
||||
|
||||
std::string description() const override {
|
||||
|
@ -18,8 +18,8 @@ namespace SkSL {
|
||||
struct IntLiteral : public Expression {
|
||||
// FIXME: we will need to revisit this if/when we add full support for both signed and unsigned
|
||||
// 64-bit integers, but for right now an int64_t will hold every value we care about
|
||||
IntLiteral(const Context& context, Position position, int64_t value)
|
||||
: INHERITED(position, kIntLiteral_Kind, *context.fInt_Type)
|
||||
IntLiteral(const Context& context, Position position, int64_t value, const Type* type = nullptr)
|
||||
: INHERITED(position, kIntLiteral_Kind, type ? *type : *context.fInt_Type)
|
||||
, fValue(value) {}
|
||||
|
||||
virtual std::string description() const override {
|
||||
|
@ -22,15 +22,20 @@ struct Layout {
|
||||
, fIndex(layout.fIndex)
|
||||
, fSet(layout.fSet)
|
||||
, fBuiltin(layout.fBuiltin)
|
||||
, fOriginUpperLeft(layout.fOriginUpperLeft) {}
|
||||
, fOriginUpperLeft(layout.fOriginUpperLeft)
|
||||
, fOverrideCoverage(layout.fOverrideCoverage)
|
||||
, fBlendSupportAllEquations(layout.fBlendSupportAllEquations) {}
|
||||
|
||||
Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft)
|
||||
Layout(int location, int binding, int index, int set, int builtin, bool originUpperLeft,
|
||||
bool overrideCoverage, bool blendSupportAllEquations)
|
||||
: fLocation(location)
|
||||
, fBinding(binding)
|
||||
, fIndex(index)
|
||||
, fSet(set)
|
||||
, fBuiltin(builtin)
|
||||
, fOriginUpperLeft(originUpperLeft) {}
|
||||
, fOriginUpperLeft(originUpperLeft)
|
||||
, fOverrideCoverage(overrideCoverage)
|
||||
, fBlendSupportAllEquations(blendSupportAllEquations) {}
|
||||
|
||||
std::string description() const {
|
||||
std::string result;
|
||||
@ -59,6 +64,14 @@ struct Layout {
|
||||
result += separator + "origin_upper_left";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fOverrideCoverage) {
|
||||
result += separator + "override_coverage";
|
||||
separator = ", ";
|
||||
}
|
||||
if (fBlendSupportAllEquations) {
|
||||
result += separator + "blend_support_all_equations";
|
||||
separator = ", ";
|
||||
}
|
||||
if (result.length() > 0) {
|
||||
result = "layout (" + result + ")";
|
||||
}
|
||||
@ -66,11 +79,14 @@ struct Layout {
|
||||
}
|
||||
|
||||
bool operator==(const Layout& other) const {
|
||||
return fLocation == other.fLocation &&
|
||||
fBinding == other.fBinding &&
|
||||
fIndex == other.fIndex &&
|
||||
fSet == other.fSet &&
|
||||
fBuiltin == other.fBuiltin;
|
||||
return fLocation == other.fLocation &&
|
||||
fBinding == other.fBinding &&
|
||||
fIndex == other.fIndex &&
|
||||
fSet == other.fSet &&
|
||||
fBuiltin == other.fBuiltin &&
|
||||
fOriginUpperLeft == other.fOriginUpperLeft &&
|
||||
fOverrideCoverage == other.fOverrideCoverage &&
|
||||
fBlendSupportAllEquations == other.fBlendSupportAllEquations;
|
||||
}
|
||||
|
||||
bool operator!=(const Layout& other) const {
|
||||
@ -85,6 +101,8 @@ struct Layout {
|
||||
int fSet;
|
||||
int fBuiltin;
|
||||
bool fOriginUpperLeft;
|
||||
bool fOverrideCoverage;
|
||||
bool fBlendSupportAllEquations;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
37
src/sksl/ir/SkSLModifiersDeclaration.h
Normal file
37
src/sksl/ir/SkSLModifiersDeclaration.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2016 Google Inc.
|
||||
*
|
||||
* Use of this source code is governed by a BSD-style license that can be
|
||||
* found in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef SKSL_MODIFIERDECLARATION
|
||||
#define SKSL_MODIFIERDECLARATION
|
||||
|
||||
#include "SkSLProgramElement.h"
|
||||
#include "SkSLModifiers.h"
|
||||
|
||||
namespace SkSL {
|
||||
|
||||
/**
|
||||
* A declaration that consists only of modifiers, e.g.:
|
||||
*
|
||||
* layout(blend_support_all_equations) out;
|
||||
*/
|
||||
struct ModifiersDeclaration : public ProgramElement {
|
||||
ModifiersDeclaration(Modifiers modifiers)
|
||||
: INHERITED(Position(), kModifiers_Kind)
|
||||
, fModifiers(modifiers) {}
|
||||
|
||||
std::string description() const {
|
||||
return fModifiers.description() + ";";
|
||||
}
|
||||
|
||||
Modifiers fModifiers;
|
||||
|
||||
typedef ProgramElement INHERITED;
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
@ -11,6 +11,7 @@
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include "SkSLModifiers.h"
|
||||
#include "SkSLProgramElement.h"
|
||||
#include "SkSLSymbolTable.h"
|
||||
|
||||
@ -25,14 +26,18 @@ struct Program {
|
||||
kVertex_Kind
|
||||
};
|
||||
|
||||
Program(Kind kind, std::vector<std::unique_ptr<ProgramElement>> elements,
|
||||
Program(Kind kind,
|
||||
Modifiers::Flag defaultPrecision,
|
||||
std::vector<std::unique_ptr<ProgramElement>> elements,
|
||||
std::shared_ptr<SymbolTable> symbols)
|
||||
: fKind(kind)
|
||||
, fDefaultPrecision(defaultPrecision)
|
||||
, fElements(std::move(elements))
|
||||
, fSymbols(symbols) {}
|
||||
|
||||
Kind fKind;
|
||||
|
||||
// FIXME handle different types; currently it assumes this is for floats
|
||||
Modifiers::Flag fDefaultPrecision;
|
||||
std::vector<std::unique_ptr<ProgramElement>> fElements;
|
||||
std::shared_ptr<SymbolTable> fSymbols;
|
||||
};
|
||||
|
@ -20,7 +20,8 @@ struct ProgramElement : public IRNode {
|
||||
kVar_Kind,
|
||||
kFunction_Kind,
|
||||
kInterfaceBlock_Kind,
|
||||
kExtension_Kind
|
||||
kExtension_Kind,
|
||||
kModifiers_Kind
|
||||
};
|
||||
|
||||
ProgramElement(Position position, Kind kind)
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -30,6 +30,8 @@ LETTER [a-zA-Z_$]
|
||||
|
||||
{DIGIT}+ { return SkSL::Token::INT_LITERAL; }
|
||||
|
||||
"0x"[0-9a-fA-F]+ { return SkSL::Token::INT_LITERAL; }
|
||||
|
||||
true { return SkSL::Token::TRUE_LITERAL; }
|
||||
|
||||
false { return SkSL::Token::FALSE_LITERAL; }
|
||||
@ -122,13 +124,15 @@ precision { return SkSL::Token::PRECISION; }
|
||||
|
||||
"&" { return SkSL::Token::BITWISEAND; }
|
||||
|
||||
"~" { return SkSL::Token::BITWISENOT; }
|
||||
|
||||
"||" { return SkSL::Token::LOGICALOR; }
|
||||
|
||||
"^^" { return SkSL::Token::LOGICALXOR; }
|
||||
|
||||
"&&" { return SkSL::Token::LOGICALAND; }
|
||||
|
||||
"!" { return SkSL::Token::NOT; }
|
||||
"!" { return SkSL::Token::LOGICALNOT; }
|
||||
|
||||
"?" { return SkSL::Token::QUESTION; }
|
||||
|
||||
|
@ -244,6 +244,8 @@ int textureQueryLevels(samplerCubeArrayShadow sampler);
|
||||
$gvec4 texture($gsampler1D sampler, float P);
|
||||
$gvec4 texture($gsampler1D sampler, float P, float bias);
|
||||
$gvec4 texture($gsampler2D sampler, vec2 P);
|
||||
vec4 texture(samplerExternalOES sampler, vec2 P, float bias);
|
||||
vec4 texture(samplerExternalOES sampler, vec2 P);
|
||||
$gvec4 texture($gsampler2D sampler, vec2 P, float bias);
|
||||
$gvec4 texture($gsampler3D sampler, vec3 P);
|
||||
$gvec4 texture($gsampler3D sampler, vec3 P, float bias);
|
||||
@ -464,6 +466,7 @@ vec4 texture1DLod(sampler1D sampler, float coord, float lod);
|
||||
vec4 texture1DProjLod(sampler1D sampler, vec2 coord, float lod);
|
||||
vec4 texture1DProjLod(sampler1D sampler, vec4 coord, float lod);
|
||||
vec4 texture2D(sampler2D sampler, vec2 coord);
|
||||
vec4 texture2D(samplerExternalOES sampler, vec2 coord);
|
||||
vec4 texture2D(sampler2D sampler, vec2 coord, float bias);
|
||||
vec4 texture2DProj(sampler2D sampler, vec3 coord);
|
||||
vec4 texture2DProj(sampler2D sampler, vec3 coord, float bias);
|
||||
|
@ -4,5 +4,17 @@ STRINGIFY(
|
||||
|
||||
layout(builtin=15) in vec4 gl_FragCoord;
|
||||
|
||||
)
|
||||
// 9999 is a temporary value that causes us to ignore these declarations beyond
|
||||
// adding them to the symbol table. This works fine in GLSL (where they do not
|
||||
// require any further handling) but will fail in SPIR-V. We'll have a better
|
||||
// solution for this soon.
|
||||
layout(builtin=9999) vec4 gl_LastFragData[1];
|
||||
layout(builtin=9999) vec4 gl_LastFragColor;
|
||||
layout(builtin=9999) vec4 gl_LastFragColorARM;
|
||||
layout(builtin=9999) int gl_SampleMaskIn[];
|
||||
layout(builtin=9999) out int gl_SampleMask[];
|
||||
layout(builtin=9999) vec4 gl_SecondaryFragColorEXT;
|
||||
|
||||
layout(location=0,index=0,builtin=10001) out vec4 sk_FragColor;
|
||||
|
||||
)
|
||||
|
@ -263,8 +263,8 @@ DEF_TEST(SkSLBadIndex, r) {
|
||||
"void main() { int x = 2[0]; }",
|
||||
"error: 1: expected array, but found 'int'\n1 error\n");
|
||||
test_failure(r,
|
||||
"void main() { vec2 x = vec2(0); int y = x[0]; }",
|
||||
"error: 1: expected array, but found 'vec2'\n1 error\n");
|
||||
"void main() { vec2 x = vec2(0); int y = x[0][0]; }",
|
||||
"error: 1: expected array, but found 'float'\n1 error\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLTernaryMismatch, r) {
|
||||
|
@ -26,46 +26,52 @@ static void test(skiatest::Reporter* r, const char* src, SkSL::GLCaps caps, cons
|
||||
}
|
||||
}
|
||||
|
||||
static SkSL::GLCaps default_caps() {
|
||||
return {
|
||||
400,
|
||||
SkSL::GLCaps::kGL_Standard,
|
||||
false, // isCoreProfile
|
||||
false, // usesPrecisionModifiers;
|
||||
false, // mustDeclareFragmentShaderOutput
|
||||
true // canUseMinAndAbsTogether
|
||||
};
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLHelloWorld, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"out vec4 fragColor; void main() { fragColor = vec4(0.75); }",
|
||||
caps,
|
||||
"void main() { sk_FragColor = vec4(0.75); }",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"void main() {\n"
|
||||
" fragColor = vec4(0.75);\n"
|
||||
" gl_FragColor = vec4(0.75);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLControl, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"out vec4 fragColor;"
|
||||
"void main() {"
|
||||
"if (1 + 2 + 3 > 5) { fragColor = vec4(0.75); } else { discard; }"
|
||||
"if (1 + 2 + 3 > 5) { sk_FragColor = vec4(0.75); } else { discard; }"
|
||||
"int i = 0;"
|
||||
"while (i < 10) fragColor *= 0.5;"
|
||||
"do { fragColor += 0.01; } while (fragColor.x < 0.7);"
|
||||
"while (i < 10) sk_FragColor *= 0.5;"
|
||||
"do { sk_FragColor += 0.01; } while (sk_FragColor.x < 0.7);"
|
||||
"for (int i = 0; i < 10; i++) {"
|
||||
"if (i % 0 == 1) break; else continue;"
|
||||
"}"
|
||||
"return;"
|
||||
"}",
|
||||
caps,
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"void main() {\n"
|
||||
" if ((1 + 2) + 3 > 5) {\n"
|
||||
" fragColor = vec4(0.75);\n"
|
||||
" gl_FragColor = vec4(0.75);\n"
|
||||
" } else {\n"
|
||||
" discard;\n"
|
||||
" }\n"
|
||||
" int i = 0;\n"
|
||||
" while (i < 10) fragColor *= 0.5;\n"
|
||||
" while (i < 10) gl_FragColor *= 0.5;\n"
|
||||
" do {\n"
|
||||
" fragColor += 0.01;\n"
|
||||
" } while (fragColor.x < 0.7);\n"
|
||||
" gl_FragColor += 0.01;\n"
|
||||
" } while (gl_FragColor.x < 0.7);\n"
|
||||
" for (int i = 0;i < 10; i++) {\n"
|
||||
" if (i % 0 == 1) break; else continue;\n"
|
||||
" }\n"
|
||||
@ -74,34 +80,30 @@ DEF_TEST(SkSLControl, r) {
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLFunctions, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"out vec4 fragColor;"
|
||||
"float foo(float v[2]) { return v[0] * v[1]; }"
|
||||
"void bar(inout float x) { float y[2], z; y[0] = x; y[1] = x * 2; z = foo(y); x = z; }"
|
||||
"void main() { float x = 10; bar(x); fragColor = vec4(x); }",
|
||||
caps,
|
||||
"void main() { float x = 10; bar(x); sk_FragColor = vec4(x); }",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"out vec4 fragColor;\n"
|
||||
"float foo(in float[2] v) {\n"
|
||||
"float foo(in float v[2]) {\n"
|
||||
" return v[0] * v[1];\n"
|
||||
"}\n"
|
||||
"void bar(inout float x) {\n"
|
||||
" float y[2], z;\n"
|
||||
" y[0] = x;\n"
|
||||
" y[1] = x * 2;\n"
|
||||
" y[1] = x * 2.0;\n"
|
||||
" z = foo(y);\n"
|
||||
" x = z;\n"
|
||||
"}\n"
|
||||
"void main() {\n"
|
||||
" float x = 10;\n"
|
||||
" float x = 10.0;\n"
|
||||
" bar(x);\n"
|
||||
" fragColor = vec4(x);\n"
|
||||
" gl_FragColor = vec4(x);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLOperators, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float x = 1, y = 2;"
|
||||
@ -123,17 +125,17 @@ DEF_TEST(SkSLOperators, r) {
|
||||
"z <<= 4;"
|
||||
"z %= 5;"
|
||||
"}",
|
||||
caps,
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" float x = 1, y = 2;\n"
|
||||
" float x = 1.0, y = 2.0;\n"
|
||||
" int z = 3;\n"
|
||||
" x = x + ((y * float(z)) * x) * (y - float(z));\n"
|
||||
" y = (x / y) / float(z);\n"
|
||||
" z = (((z / 2) % 3 << 4) >> 2) << 1;\n"
|
||||
" bool b = x > 4 == x < 2 || (2 >= 5 && y <= float(z)) && 12 != 11;\n"
|
||||
" x += 12;\n"
|
||||
" x -= 12;\n"
|
||||
" bool b = x > 4.0 == x < 2.0 || (2 >= 5 && y <= float(z)) && 12 != 11;\n"
|
||||
" x += 12.0;\n"
|
||||
" x -= 12.0;\n"
|
||||
" x *= (y /= float(z = 10));\n"
|
||||
" b ||= false;\n"
|
||||
" b &&= true;\n"
|
||||
@ -148,7 +150,6 @@ DEF_TEST(SkSLOperators, r) {
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLMatrices, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"void main() {"
|
||||
"mat2x4 x = mat2x4(1);"
|
||||
@ -157,19 +158,18 @@ DEF_TEST(SkSLMatrices, r) {
|
||||
"vec3 v1 = mat3(1) * vec3(1);"
|
||||
"vec3 v2 = vec3(1) * mat3(1);"
|
||||
"}",
|
||||
caps,
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" mat2x4 x = mat2x4(1);\n"
|
||||
" mat3x2 y = mat3x2(1, 0, 0, 1, vec2(2, 2));\n"
|
||||
" mat2x4 x = mat2x4(1.0);\n"
|
||||
" mat3x2 y = mat3x2(1.0, 0.0, 0.0, 1.0, vec2(2.0, 2.0));\n"
|
||||
" mat3x4 z = x * y;\n"
|
||||
" vec3 v1 = mat3(1) * vec3(1);\n"
|
||||
" vec3 v2 = vec3(1) * mat3(1);\n"
|
||||
" vec3 v1 = mat3(1.0) * vec3(1.0);\n"
|
||||
" vec3 v2 = vec3(1.0) * mat3(1.0);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLInterfaceBlock, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"uniform testBlock {"
|
||||
"float x;"
|
||||
@ -179,12 +179,12 @@ DEF_TEST(SkSLInterfaceBlock, r) {
|
||||
"};"
|
||||
"void main() {"
|
||||
"}",
|
||||
caps,
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"uniform testBlock {\n"
|
||||
" float x;\n"
|
||||
" float[2] y;\n"
|
||||
" layout (binding = 12)mat3x2 z;\n"
|
||||
" layout (binding = 12) mat3x2 z;\n"
|
||||
" bool w;\n"
|
||||
"};\n"
|
||||
"void main() {\n"
|
||||
@ -192,7 +192,6 @@ DEF_TEST(SkSLInterfaceBlock, r) {
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLStructs, r) {
|
||||
SkSL::GLCaps caps = { 400, SkSL::GLCaps::kGL_Standard };
|
||||
test(r,
|
||||
"struct A {"
|
||||
"int x;"
|
||||
@ -207,7 +206,7 @@ DEF_TEST(SkSLStructs, r) {
|
||||
"B b1, b2, b3;"
|
||||
"void main() {"
|
||||
"}",
|
||||
caps,
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"struct A {\n"
|
||||
" int x;\n"
|
||||
@ -218,10 +217,151 @@ DEF_TEST(SkSLStructs, r) {
|
||||
"struct B {\n"
|
||||
" float x;\n"
|
||||
" float[2] y;\n"
|
||||
" layout (binding = 1)A z;\n"
|
||||
" layout (binding = 1) A z;\n"
|
||||
"}\n"
|
||||
" b1, b2, b3;\n"
|
||||
"void main() {\n"
|
||||
"}\n");
|
||||
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLVersion, r) {
|
||||
SkSL::GLCaps caps = default_caps();
|
||||
caps.fVersion = 450;
|
||||
caps.fIsCoreProfile = true;
|
||||
test(r,
|
||||
"in float test; void main() { sk_FragColor = vec4(0.75); }",
|
||||
caps,
|
||||
"#version 450 core\n"
|
||||
"in float test;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = vec4(0.75);\n"
|
||||
"}\n");
|
||||
caps.fVersion = 110;
|
||||
caps.fIsCoreProfile = false;
|
||||
test(r,
|
||||
"in float test; void main() { sk_FragColor = vec4(0.75); }",
|
||||
caps,
|
||||
"#version 110\n"
|
||||
"varying float test;\n"
|
||||
"void main() {\n"
|
||||
" gl_FragColor = vec4(0.75);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLDeclareOutput, r) {
|
||||
SkSL::GLCaps caps = default_caps();
|
||||
caps.fMustDeclareFragmentShaderOutput = true;
|
||||
test(r,
|
||||
"void main() { sk_FragColor = vec4(0.75); }",
|
||||
caps,
|
||||
"#version 400\n"
|
||||
"out vec4 sk_FragColor;\n"
|
||||
"void main() {\n"
|
||||
" sk_FragColor = vec4(0.75);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLUsesPrecisionModifiers, r) {
|
||||
SkSL::GLCaps caps = default_caps();
|
||||
test(r,
|
||||
"void main() { float x = 0.75; highp float y = 1; }",
|
||||
caps,
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" float x = 0.75;\n"
|
||||
" float y = 1.0;\n"
|
||||
"}\n");
|
||||
caps.fStandard = SkSL::GLCaps::kGLES_Standard;
|
||||
caps.fUsesPrecisionModifiers = true;
|
||||
test(r,
|
||||
"void main() { float x = 0.75; highp float y = 1; }",
|
||||
caps,
|
||||
"#version 400 es\n"
|
||||
"precision highp float;\n"
|
||||
"void main() {\n"
|
||||
" float x = 0.75;\n"
|
||||
" highp float y = 1.0;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLMinAbs, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float x = -5;"
|
||||
"x = min(abs(x), 6);"
|
||||
"}",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" float x = -5.0;\n"
|
||||
" x = min(abs(x), 6.0);\n"
|
||||
"}\n");
|
||||
|
||||
SkSL::GLCaps caps = default_caps();
|
||||
caps.fCanUseMinAndAbsTogether = false;
|
||||
test(r,
|
||||
"void main() {"
|
||||
"float x = -5.0;"
|
||||
"x = min(abs(x), 6.0);"
|
||||
"}",
|
||||
caps,
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" float minAbsHackVar0;\n"
|
||||
" float minAbsHackVar1;\n"
|
||||
" float x = -5.0;\n"
|
||||
" x = ((minAbsHackVar0 = abs(x)) < (minAbsHackVar1 = 6.0) ? minAbsHackVar0 : "
|
||||
"minAbsHackVar1);\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLModifiersDeclaration, r) {
|
||||
test(r,
|
||||
"layout(blend_support_all_equations) out;"
|
||||
"void main() { }",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"layout (blend_support_all_equations) out ;\n"
|
||||
"void main() {\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLHex, r) {
|
||||
test(r,
|
||||
"void main() {"
|
||||
"int i1 = 0x0;"
|
||||
"int i2 = 0x1234abcd;"
|
||||
"int i3 = 0x7fffffff;"
|
||||
"int i4 = 0xffffffff;"
|
||||
"int i5 = -0xbeef;"
|
||||
"uint u1 = 0x0;"
|
||||
"uint u2 = 0x1234abcd;"
|
||||
"uint u3 = 0x7fffffff;"
|
||||
"uint u4 = 0xffffffff;"
|
||||
"}",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"void main() {\n"
|
||||
" int i1 = 0;\n"
|
||||
" int i2 = 305441741;\n"
|
||||
" int i3 = 2147483647;\n"
|
||||
" int i4 = -1;\n"
|
||||
" int i5 = -48879;\n"
|
||||
" uint u1 = 0u;\n"
|
||||
" uint u2 = 305441741u;\n"
|
||||
" uint u3 = 2147483647u;\n"
|
||||
" uint u4 = 4294967295u;\n"
|
||||
"}\n");
|
||||
}
|
||||
|
||||
DEF_TEST(SkSLArrayConstructors, r) {
|
||||
test(r,
|
||||
"float test1[] = float[](1, 2, 3, 4);"
|
||||
"vec2 test2[] = vec2[](vec2(1, 2), vec2(3, 4));"
|
||||
"mat4 test3[] = mat4[]();",
|
||||
default_caps(),
|
||||
"#version 400\n"
|
||||
"float test1[] = float[](1.0, 2.0, 3.0, 4.0);\n"
|
||||
"vec2 test2[] = vec2[](vec2(1.0, 2.0), vec2(3.0, 4.0));\n"
|
||||
"mat4 test3[] = mat4[]();\n");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user