Skip to content

Commit fa4ad4a

Browse files
committed
Add support for swizzling triple types.
1 parent a506425 commit fa4ad4a

File tree

6 files changed

+302
-18
lines changed

6 files changed

+302
-18
lines changed

src/liboslcomp/ast.cpp

Lines changed: 105 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -805,6 +805,65 @@ ASTstructselect::print (std::ostream &out, int indentlevel) const
805805

806806

807807

808+
ASTswizzle::ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field) :
809+
ASTfieldselect(swizzle_node, comp, expr, field)
810+
{
811+
if (field.size() == 1) m_typespec = TypeDesc::TypeFloat;
812+
else m_typespec = TypeDesc::TypeVector;
813+
}
814+
815+
816+
817+
size_t ASTswizzle::indices (ustring components, int *indexes, size_t N, bool consts)
818+
{
819+
size_t i = 0;
820+
do {
821+
switch (components[i]) {
822+
case 'r':
823+
case 'x': indexes[i] = 0; break;
824+
case 'g':
825+
case 'y': indexes[i] = 1; break;
826+
case 'b':
827+
case 'z': indexes[i] = 2; break;
828+
829+
case '0':
830+
if (!consts)
831+
return 0;
832+
indexes[i] = const_offset;
833+
break;
834+
case '1':
835+
if (!consts)
836+
return 0;
837+
indexes[i] = const_offset + 1;
838+
break;
839+
840+
case '\0': return i;
841+
842+
default: return 0;
843+
}
844+
} while (++i < N);
845+
846+
return i;
847+
}
848+
849+
850+
851+
const char *
852+
ASTswizzle::childname (size_t i) const
853+
{
854+
return type_c_str(m_typespec);
855+
}
856+
857+
858+
void
859+
ASTswizzle::print (std::ostream &out, int indentlevel) const
860+
{
861+
ASTNode::print (out, indentlevel);
862+
indent (out, indentlevel+1);
863+
out << "components " << field() << "\n";
864+
}
865+
866+
808867
ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
809868
ustring field)
810869
{
@@ -814,25 +873,55 @@ ASTNode* ASTfieldselect::create (OSLCompilerImpl *comp, ASTNode *expr,
814873
const TypeSpec &type = expr->nodetype() != structselect_node ? expr->typespec() :
815874
static_cast<ASTstructselect*>(expr)->fieldsym()->typespec();
816875

817-
if (type.aggregate() == TypeDesc::VEC3) {
818-
int component = -1;
819-
switch (field[0]) {
820-
case 'r': component = 0; break;
821-
case 'g': component = 1; break;
822-
case 'b': component = 2; break;
876+
if (type.aggregate() == TypeDesc::VEC3 && field.size() <= 3) {
877+
// Early out swizle to native component ordering.
878+
if (field == "rgb" || field == "xyz")
879+
return expr;
823880

824-
case 'x': component = 0; break;
825-
case 'y': component = 1; break;
826-
case 'z': component = 2; break;
881+
ASTindex* index = expr->nodetype() != index_node ? nullptr : static_cast<ASTindex*>(expr);
827882

828-
default: break;
829-
}
830-
if (component != -1) {
831-
if (expr->nodetype() == index_node) {
832-
static_cast<ASTindex*>(expr)->extend(new ASTliteral (comp, component));
833-
return expr;
883+
int indexes[3];
884+
switch (ASTswizzle::indices (field, indexes, 3, true)) {
885+
case 1: {
886+
if (!index)
887+
return new ASTindex (comp, expr, new ASTliteral (comp, indexes[0]));
888+
index->extend(new ASTliteral (comp, indexes[0]));
889+
return index;
890+
}
891+
892+
case 3: {
893+
// Don't leak soon to be unused expr node
894+
std::unique_ptr<ASTNode> cleanup(index);
895+
ASTNode* index0 = nullptr;
896+
if (index) {
897+
index0 = index->index().get();
898+
expr = index->lvalue().get();
899+
}
900+
901+
ASTNode *args[3];
902+
for (int i = 0; i < 3; ++i) {
903+
if (indexes[i] >= 0) {
904+
args[i] = new ASTliteral (comp, indexes[i]);
905+
if (i == 0 && index) {
906+
// Re-use expr by extending the ASTindex.
907+
index->extend (args[i]);
908+
args[0] = cleanup.release ();
909+
} else {
910+
args[i] = !index0 ? new ASTindex (comp, expr, args[i]) :
911+
new ASTindex (comp, expr, index0, args[i]);
912+
}
913+
} else {
914+
float cval = indexes[i] - ASTswizzle::const_offset;
915+
ASSERT ((cval==0) || (cval==1));
916+
args[i] = new ASTliteral (comp, cval);
917+
}
918+
}
919+
args[0]->append (args[1]);
920+
args[1]->append (args[2]);
921+
return new ASTswizzle (comp, args[0], field);
834922
}
835-
return new ASTindex (comp, expr, new ASTliteral (comp, component));
923+
924+
default: break;
836925
}
837926
}
838927

src/liboslcomp/ast.h

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class ASTNode : public OIIO::RefCnt {
6262
unknown_node, shader_declaration_node, function_declaration_node,
6363
variable_declaration_node, compound_initializer_node,
6464
variable_ref_node, preincdec_node, postincdec_node,
65-
index_node, structselect_node,
65+
index_node, structselect_node, swizzle_node,
6666
conditional_statement_node,
6767
loop_statement_node, loopmod_statement_node, return_statement_node,
6868
binary_expression_node, unary_expression_node,
@@ -645,6 +645,34 @@ class ASTstructselect : public ASTfieldselect
645645

646646

647647

648+
class ASTswizzle : public ASTfieldselect
649+
{
650+
public:
651+
ASTswizzle (OSLCompilerImpl *comp, ASTNode *expr, ustring field);
652+
653+
const char *nodetypename () const { return "swizzle"; }
654+
const char *childname (size_t i) const;
655+
void print (std::ostream &out, int indentlevel=0) const;
656+
TypeSpec typecheck (TypeSpec expected);
657+
Symbol *codegen (Symbol *dest = NULL);
658+
659+
/// Get component indeces for a swizzle string.
660+
/// consts allows '0' & '1' to be included in the string.
661+
static size_t indices (ustring components, int *indexes, size_t N, bool consts);
662+
663+
/// Offset if the component index is really a constant ('0' or '1').
664+
enum { const_offset = -2 };
665+
666+
/// Special code generation of assignment of src to proper components.
667+
Symbol* codegen_assign (Symbol *src);
668+
669+
size_t indices (int *indexes, size_t N, bool consts) const {
670+
return indices (m_field, indexes, N, consts);
671+
}
672+
};
673+
674+
675+
648676
class ASTconditional_statement : public ASTNode
649677
{
650678
public:

src/liboslcomp/codegen.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,8 @@ ASTassign_expression::codegen (Symbol *dest)
488488
// Assigning to an individual component or array element
489489
index = (ASTindex *) var().get();
490490
dest = NULL;
491+
} else if (var()->nodetype() == swizzle_node) {
492+
return static_cast<ASTswizzle*>(var().get())->codegen_assign(expr()->codegen (dest));
491493
} else if (var()->nodetype() == structselect_node) {
492494
dest = var()->codegen();
493495
} else {
@@ -1294,6 +1296,78 @@ ASTindex::codegen_assign (Symbol *src, Symbol *ind,
12941296

12951297

12961298

1299+
Symbol *
1300+
ASTswizzle::codegen (Symbol *dest)
1301+
{
1302+
// General case, construct a new triple with the swizzle indexes.
1303+
1304+
if (dest == nullptr || ! equivalent (dest->typespec(), typespec()))
1305+
dest = m_compiler->make_temporary (typespec());
1306+
1307+
Symbol *syms[4] = { dest };
1308+
1309+
int nsym = 1;
1310+
for (ref arg = child(0); arg && nsym < 4; ++nsym, arg = arg->next()) {
1311+
syms[nsym] = arg->codegen();
1312+
}
1313+
ASSERT (nsym == 4);
1314+
1315+
// emit the constructor call
1316+
emitcode (typespec().string().c_str(), nsym, syms);
1317+
return dest;
1318+
}
1319+
1320+
1321+
1322+
Symbol *
1323+
ASTswizzle::codegen_assign (Symbol *src)
1324+
{
1325+
// Swizzle assignment.
1326+
1327+
if (!m_is_lvalue) {
1328+
error ("Cannot assign to constant swizzle");
1329+
return nullptr;
1330+
}
1331+
1332+
// First child is an index, which holds the lvalue (this) to store to.
1333+
ASTindex* index = static_cast<ASTindex*>(child(0));
1334+
Symbol *syms[4] = { index->lvalue().get()->codegen() };
1335+
1336+
int nsym = 0;
1337+
if (src->typespec().is_triple()) {
1338+
int idxs[3];
1339+
if (indices(idxs, 3, false /*can't assign to constants*/) != 3) {
1340+
error ("Trying to assign to invalid swizzle");
1341+
return nullptr;
1342+
}
1343+
// Iterate all of the indexes
1344+
for (; index && nsym < 3; ++nsym, index = static_cast<ASTindex*>(index->nextptr())) {
1345+
// tmp[I] = src[N]
1346+
ASSERT (index->nodetype() == index_node);
1347+
Symbol* sym = m_compiler->make_temporary (TypeDesc::TypeFloat);
1348+
emitcode ("compref", sym, src, m_compiler->make_constant (nsym));
1349+
1350+
// sym[0] is taken, so assign to syms[i+1]
1351+
ASSERT (idxs[nsym]+1 < int(sizeof(syms)/sizeof(syms[0])));
1352+
syms[idxs[nsym]+1] = sym;
1353+
}
1354+
} else {
1355+
// Same assignment to all components
1356+
for (int n = m_typespec.aggregate(); nsym < n; ++nsym)
1357+
syms[nsym] = src;
1358+
}
1359+
1360+
ASSERT (nsym == 3);
1361+
1362+
// emit the constructor call
1363+
emitcode (typespec().string().c_str(), nsym+1, syms);
1364+
1365+
// so transitive assignment will work
1366+
return syms[0];
1367+
}
1368+
1369+
1370+
12971371
Symbol *
12981372
ASTstructselect::codegen (Symbol *dest)
12991373
{

src/liboslcomp/typecheck.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,22 @@ ASTindex::typecheck (TypeSpec expected)
225225

226226

227227

228+
TypeSpec
229+
ASTswizzle::typecheck (TypeSpec expected)
230+
{
231+
typecheck_children ();
232+
233+
// Can't be an lvalue if any of the args are constant floats.
234+
for (ref arg = child(0); arg; arg = arg->next()) {
235+
if (!(m_is_lvalue = arg->is_lvalue()))
236+
break;
237+
}
238+
239+
return m_typespec;
240+
}
241+
242+
243+
228244
TypeSpec
229245
ASTstructselect::typecheck (TypeSpec expected)
230246
{

testsuite/swizzle/ref/out.txt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,18 @@
11
Compiled swizzle.osl -> swizzle.oso
2+
c: 1 2 3
3+
c.brg = c.grb = c.bgr: 3 1 2
4+
c.rgb = c.gbr: 1 2 3
5+
c.r00: 1 0 0
6+
c.g01: 2 0 1
7+
c.b11: 3 1 1
8+
c.bg1: 3 2 1
9+
c.rgb = c.brg: 3 1 2
10+
c.rgb = c.brg: 2 3 1
11+
c.rgb = c.brg: 1 2 3
12+
c.rgb = c.bgr: 3 2 1
13+
c.bgr = c.bgr: 3 2 1
14+
c.grb = c.bgr: 2 1 3
15+
c.ggr + c.rgr: 3 2 4
216
c.r: 4
317
c.g: 3
418
c.b: 2
@@ -12,4 +26,15 @@ c4[0].b: 3
1226
c4[1].r: -1
1327
c4[1].b: -3
1428
c4[1].g: -2
29+
c.rrr: 4 4 4
30+
c.rgb: 4 3 2
31+
c.rbg: 4 2 3
32+
c.ggg: 3 3 3
33+
c.grb: 3 4 2
34+
c.gbr: 3 2 4
35+
c.bbb: 2 2 2
36+
c.brg: 2 4 3
37+
c.ggr: 3 3 4
38+
ca[0].brg: 3 1 2
39+
c.rgb = 1: 1 1 1
1540

testsuite/swizzle/swizzle.osl

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,44 @@
44

55
shader swizzle ()
66
{
7-
color c = color(4,3,2);
7+
color c = color(1,2,3);
8+
printf("c: %g\n", c);
9+
10+
// transitive
11+
// 1,2,3 -> 2,3,1 -> 3,1,2
12+
c.brg = c.grb = c.bgr;
13+
printf("c.brg = c.grb = c.bgr: %g\n", c);
14+
15+
c.rgb = c.gbr;
16+
printf("c.rgb = c.gbr: %g\n", c);
17+
18+
printf("c.r00: %g\n", c.r00);
19+
printf("c.g01: %g\n", c.g01);
20+
printf("c.b11: %g\n", c.b11);
21+
printf("c.bg1: %g\n", c.bg1);
22+
23+
c = c.brg;
24+
printf("c.rgb = c.brg: %g\n", c);
25+
26+
c = c.brg;
27+
printf("c.rgb = c.brg: %g\n", c);
28+
29+
c = c.brg;
30+
printf("c.rgb = c.brg: %g\n", c);
31+
32+
c.rgb = c.bgr;
33+
printf("c.rgb = c.bgr: %g\n", c);
34+
35+
c.bgr = c.bgr;
36+
printf("c.bgr = c.bgr: %g\n", c);
37+
38+
c.grb = c.bgr;
39+
printf("c.grb = c.bgr: %g\n", c);
40+
41+
printf("c.ggr + c.rgr: %g\n", c.ggr + c.rgr);
42+
43+
c.gbr = c.ggr + c.rgr;
44+
845
printf("c.r: %g\n", c.r);
946
printf("c.g: %g\n", c.g);
1047
printf("c.b: %g\n", c.b);
@@ -26,4 +63,19 @@ shader swizzle ()
2663
printf("c4[%d].%s: %g\n", i, i ? "b" : "g", i ? c4[i].rgb.b : c4[i].rgb.g);
2764
printf("c4[%d].%s: %g\n", i, i ? "g" : "b", i ? c4[i].rgb.g : c4[i].rgb.b);
2865
}
66+
67+
printf("c.rrr: %g\n", c.rrr);
68+
printf("c.rgb: %g\n", c.rgb);
69+
printf("c.rbg: %g\n", c.rbg);
70+
printf("c.ggg: %g\n", c.ggg);
71+
printf("c.grb: %g\n", c.grb);
72+
printf("c.gbr: %g\n", c.gbr);
73+
printf("c.bbb: %g\n", c.bbb);
74+
printf("c.brg: %g\n", c.brg);
75+
printf("c.ggr: %g\n", c.ggr);
76+
77+
printf("ca[0].brg: %g\n", ca[0].brg);
78+
79+
c.rgb = 1;
80+
printf("c.rgb = 1: %g\n", c);
2981
}

0 commit comments

Comments
 (0)