#include "sksl_frag.include"
;
+static const char* SKSL_GEOM_INCLUDE =
+#include "sksl_geom.include"
+;
+
namespace SkSL {
Compiler::Compiler()
case Program::kFragment_Kind:
this->internalConvertProgram(SkString(SKSL_FRAG_INCLUDE), &ignored, &elements);
break;
+ case Program::kGeometry_Kind:
+ this->internalConvertProgram(SkString(SKSL_GEOM_INCLUDE), &ignored, &elements);
+ break;
}
fIRGenerator->fSymbolTable->markAllFunctionsBuiltin();
Modifiers::Flag defaultPrecision;
#include "SkSLIRGenerator.h"
#define SK_FRAGCOLOR_BUILTIN 10001
+#define SK_IN_BUILTIN 10002
#define SK_FRAGCOORD_BUILTIN 15
#define SK_VERTEXID_BUILTIN 5
#define SK_CLIPDISTANCE_BUILTIN 3
+#define SK_INVOCATIONID_BUILTIN 8
namespace SkSL {
case SK_CLIPDISTANCE_BUILTIN:
this->write("gl_ClipDistance");
break;
+ case SK_IN_BUILTIN:
+ this->write("gl_in");
+ break;
+ case SK_INVOCATIONID_BUILTIN:
+ this->write("gl_InvocationID");
+ break;
default:
this->write(ref.fVariable.fName);
}
}
void GLSLCodeGenerator::writeInterfaceBlock(const InterfaceBlock& intf) {
- if (intf.fTypeName == "gl_PerVertex") {
+ if (intf.fTypeName == "sk_PerVertex") {
return;
}
this->writeModifiers(intf.fVariable.fModifiers, true);
kind = SkSL::Program::kVertex_Kind;
} else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".frag")) {
kind = SkSL::Program::kFragment_Kind;
+ } else if (len > 5 && !strcmp(argv[1] + strlen(argv[1]) - 5, ".geom")) {
+ kind = SkSL::Program::kGeometry_Kind;
} else {
- printf("input filename must end in '.vert' or '.frag'\n");
+ printf("input filename must end in '.vert', '.frag', or '.geom'\n");
exit(1);
}
fLayoutKeys[SkString("override_coverage")] = kOverrideCoverage_LayoutKey;
fLayoutKeys[SkString("blend_support_all_equations")] = kBlendSupportAllEquations_LayoutKey;
fLayoutKeys[SkString("push_constant")] = kPushConstant_LayoutKey;
+ fLayoutKeys[SkString("points")] = kPoints_LayoutKey;
+ fLayoutKeys[SkString("lines")] = kLines_LayoutKey;
+ fLayoutKeys[SkString("line_strip")] = kLineStrip_LayoutKey;
+ fLayoutKeys[SkString("lines_adjacency")] = kLinesAdjacency_LayoutKey;
+ fLayoutKeys[SkString("triangles")] = kTriangles_LayoutKey;
+ fLayoutKeys[SkString("triangle_strip")] = kTriangleStrip_LayoutKey;
+ fLayoutKeys[SkString("triangles_adjacency")] = kTrianglesAdjacency_LayoutKey;
+ fLayoutKeys[SkString("max_vertices")] = kMaxVertices_LayoutKey;
+ fLayoutKeys[SkString("invocations")] = kInvocations_LayoutKey;
}
Parser::~Parser() {
bool blendSupportAllEquations = false;
Layout::Format format = Layout::Format::kUnspecified;
bool pushConstant = false;
+ Layout::Primitive primitive = Layout::kUnspecified_Primitive;
+ int maxVertices = -1;
+ int invocations = -1;
if (this->peek().fKind == Token::LAYOUT) {
this->nextToken();
if (!this->expect(Token::LPAREN, "'('")) {
return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
- pushConstant);
+ pushConstant, primitive, maxVertices, invocations);
}
for (;;) {
Token t = this->nextToken();
case kPushConstant_LayoutKey:
pushConstant = true;
break;
+ case kPoints_LayoutKey:
+ primitive = Layout::kPoints_Primitive;
+ break;
+ case kLines_LayoutKey:
+ primitive = Layout::kLines_Primitive;
+ break;
+ case kLineStrip_LayoutKey:
+ primitive = Layout::kLineStrip_Primitive;
+ break;
+ case kLinesAdjacency_LayoutKey:
+ primitive = Layout::kLinesAdjacency_Primitive;
+ break;
+ case kTriangles_LayoutKey:
+ primitive = Layout::kTriangles_Primitive;
+ break;
+ case kTriangleStrip_LayoutKey:
+ primitive = Layout::kTriangleStrip_Primitive;
+ break;
+ case kTrianglesAdjacency_LayoutKey:
+ primitive = Layout::kTrianglesAdjacency_Primitive;
+ break;
+ case kMaxVertices_LayoutKey:
+ maxVertices = this->layoutInt();
+ break;
+ case kInvocations_LayoutKey:
+ invocations = this->layoutInt();
+ break;
}
} else if (Layout::ReadFormat(t.fText, &format)) {
// AST::ReadFormat stored the result in 'format'.
}
return Layout(location, offset, binding, index, set, builtin, inputAttachmentIndex,
originUpperLeft, overrideCoverage, blendSupportAllEquations, format,
- pushConstant);
+ pushConstant, primitive, maxVertices, invocations);
}
/* layout? (UNIFORM | CONST | IN | OUT | INOUT | LOWP | MEDIUMP | HIGHP | FLAT | NOPERSPECTIVE |
kOriginUpperLeft_LayoutKey,
kOverrideCoverage_LayoutKey,
kBlendSupportAllEquations_LayoutKey,
- kPushConstant_LayoutKey
+ kPushConstant_LayoutKey,
+ kPoints_LayoutKey,
+ kLines_LayoutKey,
+ kLineStrip_LayoutKey,
+ kLinesAdjacency_LayoutKey,
+ kTriangles_LayoutKey,
+ kTriangleStrip_LayoutKey,
+ kTrianglesAdjacency_LayoutKey,
+ kMaxVertices_LayoutKey,
+ kInvocations_LayoutKey
};
std::unordered_map<SkString, LayoutKey> fLayoutKeys;
SkString name("sksl_synthetic_uniforms");
Type intfStruct(Position(), name, fields);
Layout layout(-1, -1, 1, -1, -1, -1, -1, false, false, false, Layout::Format::kUnspecified,
- false);
+ false, Layout::kUnspecified_Primitive, -1, -1);
Variable intfVar(Position(), Modifiers(layout, Modifiers::kUniform_Flag), name,
intfStruct, Variable::kGlobal_Storage);
InterfaceBlock intf(Position(), intfVar, name, SkString(""),
case Program::kFragment_Kind:
this->writeWord(SpvExecutionModelFragment, out);
break;
+ case Program::kGeometry_Kind:
+ this->writeWord(SpvExecutionModelGeometry, out);
+ break;
}
this->writeWord(fFunctionMap[main], out);
this->writeString(main->fName.c_str(), out);
* layout (location = 0) int x;
*/
struct Layout {
+ enum Primitive {
+ kUnspecified_Primitive = -1,
+ kPoints_Primitive,
+ kLines_Primitive,
+ kLineStrip_Primitive,
+ kLinesAdjacency_Primitive,
+ kTriangles_Primitive,
+ kTriangleStrip_Primitive,
+ kTrianglesAdjacency_Primitive
+ };
+
// These are used by images in GLSL. We only support a subset of what GL supports.
enum class Format {
kUnspecified = -1,
Layout(int location, int offset, int binding, int index, int set, int builtin,
int inputAttachmentIndex, bool originUpperLeft, bool overrideCoverage,
- bool blendSupportAllEquations, Format format, bool pushconstant)
+ bool blendSupportAllEquations, Format format, bool pushconstant, Primitive primitive,
+ int maxVertices, int invocations)
: fLocation(location)
, fOffset(offset)
, fBinding(binding)
, fOverrideCoverage(overrideCoverage)
, fBlendSupportAllEquations(blendSupportAllEquations)
, fFormat(format)
- , fPushConstant(pushconstant) {}
+ , fPushConstant(pushconstant)
+ , fPrimitive(primitive)
+ , fMaxVertices(maxVertices)
+ , fInvocations(invocations) {}
Layout()
: fLocation(-1)
, fOverrideCoverage(false)
, fBlendSupportAllEquations(false)
, fFormat(Format::kUnspecified)
- , fPushConstant(false) {}
+ , fPushConstant(false)
+ , fPrimitive(kUnspecified_Primitive)
+ , fMaxVertices(-1)
+ , fInvocations(-1) {}
SkString description() const {
SkString result;
result += separator + "push_constant";
separator = ", ";
}
+ switch (fPrimitive) {
+ case kPoints_Primitive:
+ result += separator + "points";
+ separator = ", ";
+ break;
+ case kLines_Primitive:
+ result += separator + "lines";
+ separator = ", ";
+ break;
+ case kLineStrip_Primitive:
+ result += separator + "line_strip";
+ separator = ", ";
+ break;
+ case kLinesAdjacency_Primitive:
+ result += separator + "lines_adjacency";
+ separator = ", ";
+ break;
+ case kTriangles_Primitive:
+ result += separator + "triangles";
+ separator = ", ";
+ break;
+ case kTriangleStrip_Primitive:
+ result += separator + "triangle_strip";
+ separator = ", ";
+ break;
+ case kTrianglesAdjacency_Primitive:
+ result += separator + "triangles_adjacency";
+ separator = ", ";
+ break;
+ case kUnspecified_Primitive:
+ break;
+ }
+ if (fMaxVertices >= 0) {
+ result += separator + "max_vertices = " + to_string(fMaxVertices);
+ separator = ", ";
+ }
+ if (fInvocations >= 0) {
+ result += separator + "invocations = " + to_string(fInvocations);
+ separator = ", ";
+ }
if (result.size() > 0) {
result = "layout (" + result + ")";
}
fOriginUpperLeft == other.fOriginUpperLeft &&
fOverrideCoverage == other.fOverrideCoverage &&
fBlendSupportAllEquations == other.fBlendSupportAllEquations &&
- fFormat == other.fFormat;
+ fFormat == other.fFormat &&
+ fPrimitive == other.fPrimitive &&
+ fMaxVertices == other.fMaxVertices &&
+ fInvocations == other.fInvocations;
}
bool operator!=(const Layout& other) const {
bool fBlendSupportAllEquations;
Format fFormat;
bool fPushConstant;
+ Primitive fPrimitive;
+ int fMaxVertices;
+ int fInvocations;
};
} // namespace
enum Kind {
kFragment_Kind,
- kVertex_Kind
+ kVertex_Kind,
+ kGeometry_Kind
};
Program(Kind kind,
$genType fwidth($genType p);
$genType fwidthCoarse($genType p);
$genType fwidthFine($genType p);
-void EmitStreamVertex(int stream);
-void EndStreamPrimitive(int stream);
-void EmitVertex();
-void EndPrimitive();
void barrier();
void memoryBarrier();
void memoryBarrierAtomicCounter();
--- /dev/null
+STRINGIFY(
+
+// defines built-in interfaces supported by SkiaSL geometry shaders
+
+layout(builtin=10002) in sk_PerVertex {
+ layout(builtin=0) vec4 gl_Position;
+ layout(builtin=1) float gl_PointSize;
+ layout(builtin=3) float sk_ClipDistance[];
+} sk_in[];
+
+out sk_PerVertex {
+ layout(builtin=0) vec4 gl_Position;
+ layout(builtin=1) float gl_PointSize;
+ layout(builtin=3) float sk_ClipDistance[];
+};
+
+layout(builtin=8) int sk_InvocationID;
+
+void EmitStreamVertex(int stream);
+void EndStreamPrimitive(int stream);
+void EmitVertex();
+void EndPrimitive();
+
+)
// defines built-in interfaces supported by SkiaSL vertex shaders
-out gl_PerVertex {
- layout(builtin=0) vec4 gl_Position;
+out sk_PerVertex {
+ layout(builtin=0) vec4 gl_Position;
layout(builtin=1) float gl_PointSize;
layout(builtin=3) float sk_ClipDistance[1];
};
"}\n");
}
+DEF_TEST(SkSLGeometry, r) {
+ test(r,
+ "layout(points) in;"
+ "layout(invocations = 2) in;"
+ "layout(line_strip, max_vertices = 2) out;"
+ "void main() {"
+ "gl_Position = sk_in[0].gl_Position + vec4(-0.5, 0, 0, sk_InvocationID);"
+ "EmitVertex();"
+ "gl_Position = sk_in[0].gl_Position + vec4(0.5, 0, 0, sk_InvocationID);"
+ "EmitVertex();"
+ "EndPrimitive();"
+ "}",
+ *SkSL::ShaderCapsFactory::Default(),
+ "#version 400\n"
+ "layout (points) in ;\n"
+ "layout (invocations = 2) in ;\n"
+ "layout (line_strip, max_vertices = 2) out ;\n"
+ "void main() {\n"
+ " gl_Position = gl_in[0].gl_Position + vec4(-0.5, 0.0, 0.0, float(gl_InvocationID));\n"
+ " EmitVertex();\n"
+ " gl_Position = gl_in[0].gl_Position + vec4(0.5, 0.0, 0.0, float(gl_InvocationID));\n"
+ " EmitVertex();\n"
+ " EndPrimitive();\n"
+ "}\n",
+ SkSL::Program::kGeometry_Kind);
+}
+
#endif