Skip to content
This repository was archived by the owner on Dec 8, 2025. It is now read-only.

Commit 8030f33

Browse files
authored
Support qualifiers on interface block (#1150)
Fixes #1149.
1 parent 80e69c1 commit 8030f33

9 files changed

Lines changed: 241 additions & 35 deletions

File tree

ast/src/main/antlr4/com/graphicsfuzz/parser/GLSL.g4

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -683,14 +683,19 @@ interface_block:
683683
;
684684

685685
basic_interface_block:
686-
interface_qualifier IDENTIFIER LBRACE member_list RBRACE instance_name? SEMICOLON
686+
interface_qualifier+ IDENTIFIER LBRACE member_list RBRACE instance_name? SEMICOLON
687687
;
688688

689689
interface_qualifier:
690690
IN_TOK
691691
| OUT_TOK
692692
| UNIFORM
693693
| BUFFER
694+
| COHERENT
695+
| VOLATILE
696+
| RESTRICT
697+
| READONLY
698+
| WRITEONLY
694699
;
695700

696701
instance_name:

ast/src/main/java/com/graphicsfuzz/common/ast/decl/InterfaceBlock.java

Lines changed: 51 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,33 +23,57 @@
2323
import java.util.ArrayList;
2424
import java.util.Arrays;
2525
import java.util.Collections;
26+
import java.util.HashSet;
2627
import java.util.List;
2728
import java.util.Optional;
29+
import java.util.Set;
2830
import java.util.stream.Collectors;
2931

3032
public class InterfaceBlock extends Declaration {
3133

3234
private final Optional<LayoutQualifierSequence> layoutQualifier;
33-
private final TypeQualifier interfaceQualifier;
35+
private final List<TypeQualifier> interfaceQualifiers;
3436
private final String structName;
3537
private final List<String> memberNames;
3638
private final List<Type> memberTypes;
3739
private final Optional<String> instanceName;
3840

3941
public InterfaceBlock(
4042
Optional<LayoutQualifierSequence> layoutQualifier,
41-
TypeQualifier interfaceQualifier,
43+
List<TypeQualifier> interfaceQualifiers,
4244
String structName,
4345
List<String> memberNames,
4446
List<Type> memberTypes,
4547
Optional<String> instanceName) {
48+
// Check that there are no repeated qualifiers
49+
assert interfaceQualifiers.size() == new HashSet<>(interfaceQualifiers).size() : "Interface "
50+
+ "block qualifiers must not be repeated";
51+
52+
// Check that there is only one qualifier specifying the kind of block this is
53+
final Set<TypeQualifier> allowedQualifiers =
54+
new HashSet<>(Arrays.asList(TypeQualifier.SHADER_INPUT, TypeQualifier.SHADER_OUTPUT,
55+
TypeQualifier.UNIFORM, TypeQualifier.BUFFER));
56+
allowedQualifiers.retainAll(interfaceQualifiers);
57+
assert allowedQualifiers.size() == 1 :
58+
"An interface block must have exactly one of the 'in', 'out', 'uniform' or 'buffer' "
59+
+ "qualifiers";
60+
61+
// A buffer block is allowed to have memory qualifiers
62+
if (allowedQualifiers.contains(TypeQualifier.BUFFER)) {
63+
allowedQualifiers.addAll(new HashSet<>(Arrays.asList(
64+
TypeQualifier.COHERENT,
65+
TypeQualifier.VOLATILE,
66+
TypeQualifier.RESTRICT,
67+
TypeQualifier.READONLY,
68+
TypeQualifier.WRITEONLY)));
69+
}
70+
71+
// Check that there are no unexpected qualifiers
72+
assert allowedQualifiers.containsAll(interfaceQualifiers) :
73+
"Only certain qualifiers are allowed on an interface block";
74+
4675
this.layoutQualifier = layoutQualifier;
47-
this.interfaceQualifier = interfaceQualifier;
48-
assert Arrays.asList(TypeQualifier.SHADER_INPUT,
49-
TypeQualifier.SHADER_OUTPUT,
50-
TypeQualifier.UNIFORM,
51-
TypeQualifier.BUFFER)
52-
.contains(interfaceQualifier);
76+
this.interfaceQualifiers = new ArrayList<>(interfaceQualifiers);
5377
this.structName = structName;
5478
this.memberNames = new ArrayList<>();
5579
this.memberNames.addAll(memberNames);
@@ -58,15 +82,6 @@ public InterfaceBlock(
5882
this.instanceName = instanceName;
5983
}
6084

61-
public InterfaceBlock(LayoutQualifierSequence layoutQualifierSequence,
62-
TypeQualifier interfaceQualifier, String name,
63-
String memberName,
64-
Type memberType,
65-
String instanceName) {
66-
this(Optional.of(layoutQualifierSequence), interfaceQualifier,
67-
name, Arrays.asList(memberName), Arrays.asList(memberType), Optional.of(instanceName));
68-
}
69-
7085
public List<Type> getMemberTypes() {
7186
return Collections.unmodifiableList(memberTypes);
7287
}
@@ -84,8 +99,8 @@ public LayoutQualifierSequence getLayoutQualifierSequence() {
8499
return layoutQualifier.get();
85100
}
86101

87-
public TypeQualifier getInterfaceQualifier() {
88-
return interfaceQualifier;
102+
public List<TypeQualifier> getInterfaceQualifiers() {
103+
return Collections.unmodifiableList(interfaceQualifiers);
89104
}
90105

91106
public String getStructName() {
@@ -109,6 +124,22 @@ public Optional<Type> getMemberType(String name) {
109124
return Optional.empty();
110125
}
111126

127+
public boolean isUniformBlock() {
128+
return interfaceQualifiers.contains(TypeQualifier.UNIFORM);
129+
}
130+
131+
public boolean isShaderStorageBlock() {
132+
return interfaceQualifiers.contains(TypeQualifier.BUFFER);
133+
}
134+
135+
public boolean isInputBlock() {
136+
return interfaceQualifiers.contains(TypeQualifier.SHADER_INPUT);
137+
}
138+
139+
public boolean isOutputBlock() {
140+
return interfaceQualifiers.contains(TypeQualifier.SHADER_OUTPUT);
141+
}
142+
112143
@Override
113144
public void accept(IAstVisitor visitor) {
114145
visitor.visitInterfaceBlock(this);
@@ -117,7 +148,7 @@ public void accept(IAstVisitor visitor) {
117148
@Override
118149
public InterfaceBlock clone() {
119150
return new InterfaceBlock(layoutQualifier,
120-
interfaceQualifier,
151+
interfaceQualifiers,
121152
structName,
122153
memberNames,
123154
memberTypes.stream().map(item -> item.clone()).collect(Collectors.toList()),

ast/src/main/java/com/graphicsfuzz/common/ast/type/TypeQualifier.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ public class TypeQualifier {
2121
private final String text;
2222

2323
/**
24-
* Deliverately package-visible: we do not want arbitrary type qualifiers
24+
* Deliberately package-visible: we do not want arbitrary type qualifiers
2525
* to be created, except via designated subclasses.
2626
*/
2727
TypeQualifier(String text) {

ast/src/main/java/com/graphicsfuzz/common/ast/visitors/AstBuilder.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -481,16 +481,18 @@ public Declaration visitInterface_block(Interface_blockContext ctx) {
481481
? Optional.empty()
482482
: Optional.of(visitLayout_qualifier(ctx.layout_qualifier()));
483483
final Basic_interface_blockContext basicCtx = ctx.basic_interface_block();
484-
final TypeQualifier interfaceQualifier =
485-
visitInterface_qualifier(basicCtx.interface_qualifier());
484+
final List<TypeQualifier> interfaceQualifiers = new ArrayList<>();
485+
for (Interface_qualifierContext interfaceQualifierContext : basicCtx.interface_qualifier()) {
486+
interfaceQualifiers.add(visitInterface_qualifier(interfaceQualifierContext));
487+
}
486488
if (basicCtx.instance_name() != null) {
487489
throw new UnsupportedLanguageFeatureException("Named interface blocks are not currently "
488490
+ "supported.");
489491
}
490492
final Pair<List<String>, List<Type>> members = getMembers(basicCtx.member_list());
491493
return new InterfaceBlock(
492494
maybeLayoutQualifier,
493-
interfaceQualifier,
495+
interfaceQualifiers,
494496
basicCtx.IDENTIFIER().getText(),
495497
members.a,
496498
members.b,
@@ -508,6 +510,16 @@ public TypeQualifier visitInterface_qualifier(Interface_qualifierContext ctx) {
508510
return TypeQualifier.UNIFORM;
509511
case "buffer":
510512
return TypeQualifier.BUFFER;
513+
case "coherent":
514+
return TypeQualifier.COHERENT;
515+
case "volatile":
516+
return TypeQualifier.VOLATILE;
517+
case "restrict":
518+
return TypeQualifier.RESTRICT;
519+
case "readonly":
520+
return TypeQualifier.READONLY;
521+
case "writeonly":
522+
return TypeQualifier.WRITEONLY;
511523
default:
512524
// The above is supposed to capture all the interface qualifiers, so this
513525
// indicates that the input is bad (rather than lack of support).

ast/src/main/java/com/graphicsfuzz/common/tool/PrettyPrinterVisitor.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,7 @@ public void visitInterfaceBlock(InterfaceBlock interfaceBlock) {
734734

735735
// If a uniform block is being declared and we have a uniform supplier that provides known
736736
// values for the uniform wrapped in, we emit details of those known values in comments.
737-
if (interfaceBlock.getInterfaceQualifier().equals(TypeQualifier.UNIFORM)) {
737+
if (interfaceBlock.isUniformBlock()) {
738738
// It is guaranteed that a block, for which getInterfaceQualifier() returns "uniform",
739739
// has a single field.
740740
assert interfaceBlock.getMemberNames().size() == 1;
@@ -763,9 +763,10 @@ public void visitInterfaceBlock(InterfaceBlock interfaceBlock) {
763763
if (interfaceBlock.hasLayoutQualifierSequence()) {
764764
out.append(interfaceBlock.getLayoutQualifierSequence().toString()).append(" ");
765765
}
766-
out.append(interfaceBlock.getInterfaceQualifier().toString())
767-
.append(" ")
768-
.append(interfaceBlock.getStructName())
766+
for (TypeQualifier qualifier : interfaceBlock.getInterfaceQualifiers()) {
767+
out.append(qualifier.toString()).append(" ");
768+
}
769+
out.append(interfaceBlock.getStructName())
769770
.append(" {");
770771
newLine();
771772

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright 2021 The GraphicsFuzz Project Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.graphicsfuzz.common.ast.decl;
18+
19+
import static org.junit.Assert.assertEquals;
20+
import static org.junit.Assert.assertFalse;
21+
import static org.junit.Assert.assertTrue;
22+
23+
import com.graphicsfuzz.common.ast.TranslationUnit;
24+
import com.graphicsfuzz.common.ast.type.TypeQualifier;
25+
import com.graphicsfuzz.common.util.ParseHelper;
26+
import org.junit.Test;
27+
28+
public class InterfaceBlockTest {
29+
30+
@Test
31+
public void getInterfaceQualifiers() throws Exception {
32+
final String shader = "#version 320 es\n"
33+
+ "buffer coherent readonly restrict someblock {\n"
34+
+ " int a;\n"
35+
+ "};\n";
36+
final TranslationUnit tu = ParseHelper.parse(shader);
37+
final InterfaceBlock interfaceBlock = (InterfaceBlock) tu.getTopLevelDeclarations().get(0);
38+
assertEquals(4, interfaceBlock.getInterfaceQualifiers().size());
39+
assertTrue(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.BUFFER));
40+
assertTrue(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.COHERENT));
41+
assertTrue(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.READONLY));
42+
assertTrue(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.RESTRICT));
43+
assertFalse(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.UNIFORM));
44+
assertFalse(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.SHADER_INPUT));
45+
assertFalse(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.SHADER_OUTPUT));
46+
assertFalse(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.VOLATILE));
47+
assertFalse(interfaceBlock.getInterfaceQualifiers().contains(TypeQualifier.WRITEONLY));
48+
}
49+
50+
@Test
51+
public void isUniformBlock() throws Exception {
52+
final String shader = "#version 320 es\n"
53+
+ "uniform someblock {\n"
54+
+ " int a;\n"
55+
+ "};\n";
56+
final TranslationUnit tu = ParseHelper.parse(shader);
57+
final InterfaceBlock interfaceBlock = (InterfaceBlock) tu.getTopLevelDeclarations().get(0);
58+
assertTrue(interfaceBlock.isUniformBlock());
59+
assertEquals(1, interfaceBlock.getInterfaceQualifiers().size());
60+
}
61+
62+
@Test
63+
public void isShaderStorageBlock() throws Exception {
64+
final String shader = "#version 320 es\n"
65+
+ "buffer someblock {\n"
66+
+ " int a;\n"
67+
+ "};\n";
68+
final TranslationUnit tu = ParseHelper.parse(shader);
69+
final InterfaceBlock interfaceBlock = (InterfaceBlock) tu.getTopLevelDeclarations().get(0);
70+
assertTrue(interfaceBlock.isShaderStorageBlock());
71+
assertEquals(1, interfaceBlock.getInterfaceQualifiers().size());
72+
}
73+
74+
@Test
75+
public void isInputBlock() throws Exception {
76+
final String shader = "#version 320 es\n"
77+
+ "in someblock {\n"
78+
+ " int a;\n"
79+
+ "};\n";
80+
final TranslationUnit tu = ParseHelper.parse(shader);
81+
final InterfaceBlock interfaceBlock = (InterfaceBlock) tu.getTopLevelDeclarations().get(0);
82+
assertTrue(interfaceBlock.isInputBlock());
83+
assertEquals(1, interfaceBlock.getInterfaceQualifiers().size());
84+
}
85+
86+
@Test
87+
public void isOutputBlock() throws Exception {
88+
final String shader = "#version 320 es\n"
89+
+ "out someblock {\n"
90+
+ " int a;\n"
91+
+ "};\n";
92+
final TranslationUnit tu = ParseHelper.parse(shader);
93+
final InterfaceBlock interfaceBlock = (InterfaceBlock) tu.getTopLevelDeclarations().get(0);
94+
assertTrue(interfaceBlock.isOutputBlock());
95+
assertEquals(1, interfaceBlock.getInterfaceQualifiers().size());
96+
}
97+
}

ast/src/test/java/com/graphicsfuzz/common/tool/PrettyPrinterVisitorTest.java

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import java.nio.charset.StandardCharsets;
3838
import java.util.ArrayList;
3939
import java.util.Arrays;
40+
import java.util.Collections;
4041
import java.util.List;
4142
import java.util.Optional;
4243
import org.apache.commons.io.FileUtils;
@@ -158,7 +159,7 @@ public void testUniformBlockContentsInComments() throws Exception {
158159
if (name.equals("_GLF_uniform_int_values")) {
159160
return Optional.of(Arrays.asList("0", "1"));
160161
} else if (name.equals("_GLF_uniform_float_values")) {
161-
return Optional.of(Arrays.asList("3.0"));
162+
return Optional.of(Collections.singletonList("3.0"));
162163
}
163164
return Optional.empty();
164165
};
@@ -919,4 +920,64 @@ public void length() throws Exception {
919920
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
920921
}
921922

923+
@Test
924+
public void coherentSsbo() throws Exception {
925+
final String shader =
926+
"#version 320 es\n"
927+
+ "layout(std430, binding = 0) buffer coherent buffer_0 {\n"
928+
+ " int a;\n"
929+
+ "};\n";
930+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
931+
}
932+
933+
@Test
934+
public void volatileSsbo() throws Exception {
935+
final String shader =
936+
"#version 320 es\n"
937+
+ "layout(std430, binding = 0) volatile buffer buffer_0 {\n"
938+
+ " int a;\n"
939+
+ "};\n";
940+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
941+
}
942+
943+
@Test
944+
public void restrictSsbo() throws Exception {
945+
final String shader =
946+
"#version 320 es\n"
947+
+ "layout(std430, binding = 0) restrict buffer buffer_0 {\n"
948+
+ " int a;\n"
949+
+ "};\n";
950+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
951+
}
952+
953+
@Test
954+
public void readonlySsbo() throws Exception {
955+
final String shader =
956+
"#version 320 es\n"
957+
+ "layout(std430, binding = 0) buffer readonly buffer_0 {\n"
958+
+ " int a;\n"
959+
+ "};\n";
960+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
961+
}
962+
963+
@Test
964+
public void writeonlySsbo() throws Exception {
965+
final String shader =
966+
"#version 320 es\n"
967+
+ "layout(std430, binding = 0) writeonly buffer buffer_0 {\n"
968+
+ " int a;\n"
969+
+ "};\n";
970+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
971+
}
972+
973+
@Test
974+
public void ssboMultipleQualifiers() throws Exception {
975+
final String shader =
976+
"#version 320 es\n"
977+
+ "layout(std430, binding = 0) volatile buffer restrict writeonly buffer_0 {\n"
978+
+ " int a;\n"
979+
+ "};\n";
980+
assertEquals(shader, PrettyPrinterVisitor.prettyPrintAsString(ParseHelper.parse(shader)));
981+
}
982+
922983
}

0 commit comments

Comments
 (0)