2 Copyright (c) 2023 The Khronos Group Inc.
3 Use of this source code is governed by an MIT-style license that can be
4 found in the LICENSE.txt file.
10 <meta charset=
"utf-8">
11 <title>WebGL OES_shader_multisample_interpolation Conformance Tests
</title>
12 <link rel=
"stylesheet" href=
"../../resources/js-test-style.css"/>
13 <script src=
"../../js/js-test-pre.js"></script>
14 <script src=
"../../js/webgl-test-utils.js"></script>
17 <canvas width=
"32" height=
"32" id=
"c"></canvas>
18 <div id=
"description"></div>
19 <div id=
"console"></div>
22 description("This test verifies the functionality of the OES_shader_multisample_interpolation extension, if it is available.");
26 var wtu
= WebGLTestUtils
;
27 var gl
= wtu
.create3DContext("c", { antialias
: false }, 2);
30 function runShaderTests(extensionEnabled
) {
32 debug("Testing various shader compiles with extension " + (extensionEnabled
? "enabled" : "disabled"));
34 const macroVertex
= `#version 300 es
37 #ifdef GL_OES_shader_multisample_interpolation
38 gl_Position = vPosition;
40 #error no GL_OES_shader_multisample_interpolation;
44 const macroFragment
= `#version 300 es
45 precision highp float;
46 out vec4 my_FragColor;
48 #ifdef GL_OES_shader_multisample_interpolation
49 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
51 #error no GL_OES_shader_multisample_interpolation;
55 for (const shaders
of [[wtu
.simpleVertexShaderESSL300
, macroFragment
],
56 [macroVertex
, wtu
.simpleColorFragmentShaderESSL300
]]) {
57 // Expect the macro shader to succeed ONLY if enabled
58 if (wtu
.setupProgram(gl
, shaders
)) {
59 if (extensionEnabled
) {
60 testPassed("Macro defined in shaders when extension is enabled");
62 testFailed("Macro defined in shaders when extension is disabled");
65 if (extensionEnabled
) {
66 testFailed("Macro not defined in shaders when extension is enabled");
68 testPassed("Macro not defined in shaders when extension is disabled");
73 const missingVertex
= `#version 300 es
74 sample out float interpolant;
77 gl_Position = vPosition;
80 const missingFragment
= `#version 300 es
81 precision highp float;
82 sample in float interpolant;
83 out vec4 my_FragColor;
85 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
88 // Always expect the shader missing the #extension pragma to fail (whether enabled or not)
89 for (const shaders
of [[missingVertex
, wtu
.simpleColorFragmentShaderESSL300
],
90 [wtu
.simpleVertexShaderESSL300
, missingFragment
],
91 [missingVertex
, missingFragment
]]) {
92 if (wtu
.setupProgram(gl
, shaders
)) {
93 testFailed("Sample interpolation qualifier allowed without #extension pragma");
95 testPassed("Sample interpolation qualifier disallowed without #extension pragma");
99 const validVertex
= `#version 300 es
100 #extension GL_OES_shader_multisample_interpolation : enable
101 sample out float interpolant;
104 gl_Position = vPosition;
107 const validFragment
= `#version 300 es
108 #extension GL_OES_shader_multisample_interpolation : enable
109 precision highp float;
110 sample in float interpolant;
111 out vec4 my_FragColor;
113 my_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
116 // Try to compile a shader using a sample qualifier that should only succeed if enabled
117 if (wtu
.setupProgram(gl
, [validVertex
, validFragment
])) {
118 if (extensionEnabled
) {
119 testPassed("Sample interpolation qualifier compiled successfully when extension enabled");
121 testFailed("Sample interpolation qualifier compiled successfully when extension disabled");
124 if (extensionEnabled
) {
125 testFailed("Sample interpolation qualifier failed to compile when extension enabled");
127 testPassed("Sample interpolation qualifier failed to compile when extension disabled");
132 function runQueryTests(extensionEnabled
) {
134 debug("Testing parameters with extension " + (extensionEnabled
? "enabled" : "disabled"));
135 if (extensionEnabled
) {
136 shouldBeGreaterThanOrEqual("gl.getParameter(ext.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES)", "4");
137 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
139 const limit
= 0.5 - Math
.pow(2, -gl
.getParameter(ext
.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES
));
140 shouldBeLessThanOrEqual("gl.getParameter(ext.MIN_FRAGMENT_INTERPOLATION_OFFSET_OES)", `-${limit}`);
141 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
142 shouldBeGreaterThanOrEqual("gl.getParameter(ext.MAX_FRAGMENT_INTERPOLATION_OFFSET_OES)", `${limit}`);
143 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
145 shouldBeNull("gl.getParameter(0x8E5B /* MIN_FRAGMENT_INTERPOLATION_OFFSET_OES */)");
146 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
147 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
148 shouldBeNull("gl.getParameter(0x8E5C /* MAX_FRAGMENT_INTERPOLATION_OFFSET_OES */)");
149 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
150 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
151 shouldBeNull("gl.getParameter(0x8E5D /* FRAGMENT_INTERPOLATION_OFFSET_BITS_OES */)");
152 wtu
.glErrorShouldBe(gl
, gl
.INVALID_ENUM
, "parameter unknown without enabling the extension");
153 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
157 function checkEnums() {
159 debug("Check enums");
160 shouldBe("ext.MIN_FRAGMENT_INTERPOLATION_OFFSET_OES", "0x8E5B");
161 shouldBe("ext.MAX_FRAGMENT_INTERPOLATION_OFFSET_OES", "0x8E5C");
162 shouldBe("ext.FRAGMENT_INTERPOLATION_OFFSET_BITS_OES", "0x8E5D");
166 * This test renders a triangle using MSAAx4 and 1x1 viewport
167 * with the following vertex colors.
169 * | Position | Color |
170 * |==========|===========|
171 * | (-1, -1) | (0, 0, 0) |
172 * | (-1, +1) | (0, 1, 0) |
173 * | (+1, -1) | (1, 0, 0) |
175 * This triangle cannot cover all four samples.
177 * When default interpolation is used, the vertex color is interpolated
178 * once, most likely in the pixel center.
180 * When per-sample interpolation is used, the vertex color is interpolated
181 * several times, producing a distinct value for each covered sample.
182 * Due to the asymmetry of sample positions, the resolved pixel color must
183 * not match the color produced by default interpolation.
185 * OpenGL specs do not guarantee specific sample positions, so the test
186 * checks only that the resolved colors are different.
188 function runInterpolationTest() {
190 debug("Testing multisample interpolation");
192 function draw(program
) {
193 gl
.viewport(0, 0, 1, 1);
194 gl
.useProgram(program
);
196 const posLoc
= gl
.getAttribLocation(program
, "position");
197 const buf
= gl
.createBuffer();
198 gl
.bindBuffer(gl
.ARRAY_BUFFER
, buf
);
207 gl
.vertexAttribPointer(posLoc
, 2, gl
.FLOAT
, false, 0, 0);
208 gl
.enableVertexAttribArray(posLoc
);
210 const rbo
= gl
.createRenderbuffer();
211 gl
.bindRenderbuffer(gl
.RENDERBUFFER
, rbo
);
212 gl
.renderbufferStorageMultisample(gl
.RENDERBUFFER
, 4, gl
.RGBA8
, 1, 1);
214 const fbo
= gl
.createFramebuffer();
215 gl
.bindFramebuffer(gl
.FRAMEBUFFER
, fbo
);
216 gl
.framebufferRenderbuffer(gl
.FRAMEBUFFER
, gl
.COLOR_ATTACHMENT0
, gl
.RENDERBUFFER
, rbo
);
218 wtu
.framebufferStatusShouldBe(gl
, gl
.FRAMEBUFFER
, gl
.FRAMEBUFFER_COMPLETE
);
220 gl
.clear(gl
.COLOR_BUFFER_BIT
);
221 gl
.drawArrays(gl
.TRIANGLES
, 0, 3);
223 gl
.bindFramebuffer(gl
.READ_FRAMEBUFFER
, fbo
);
224 gl
.bindFramebuffer(gl
.DRAW_FRAMEBUFFER
, null);
225 gl
.blitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, gl
.COLOR_BUFFER_BIT
, gl
.NEAREST
);
226 wtu
.glErrorShouldBe(gl
, gl
.NO_ERROR
, "should be no errors");
228 gl
.bindFramebuffer(gl
.READ_FRAMEBUFFER
, null);
231 const vertexCenter
= `#version 300 es
233 out vec4 interp_color;
235 gl_Position = position;
236 interp_color = vec4(position.xy * 0.5 + 0.5, 0.0, 1.0);
239 const fragmentCenter
= `#version 300 es
240 precision highp float;
241 in vec4 interp_color;
244 fragColor = interp_color;
246 const programCenter
= wtu
.setupProgram(gl
, [vertexCenter
, fragmentCenter
]);
249 const centerColor
= new Uint8Array(4);
250 gl
.readPixels(0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, centerColor
);
252 const vertexSample
= `#version 300 es
253 #extension GL_OES_shader_multisample_interpolation : require
255 sample out vec4 interp_color;
257 gl_Position = position;
258 interp_color = vec4(position.xy * 0.5 + 0.5, 0.0, 1.0);
261 const fragmentSample
= `#version 300 es
262 #extension GL_OES_shader_multisample_interpolation : require
263 precision highp float;
264 sample in vec4 interp_color;
267 fragColor = interp_color;
269 const programSample
= wtu
.setupProgram(gl
, [vertexSample
, fragmentSample
]);
272 const sampleColor
= new Uint8Array(4);
273 gl
.readPixels(0, 0, 1, 1, gl
.RGBA
, gl
.UNSIGNED_BYTE
, sampleColor
);
275 const message
= `Pixel-center value: ${centerColor}, sample-average value: ${sampleColor}`;
276 if (centerColor
[0] == sampleColor
[0] && centerColor
[1] == sampleColor
[1]) {
285 testFailed("WebGL context does not exist");
288 testPassed("WebGL context exists");
290 runQueryTests(false);
291 runShaderTests(false);
294 ext
= gl
.getExtension("OES_shader_multisample_interpolation");
295 wtu
.runExtensionSupportedTest(gl
, "OES_shader_multisample_interpolation", ext
!== null);
298 testPassed("No OES_shader_multisample_interpolation support -- this is legal");
300 testPassed("Successfully enabled OES_shader_multisample_interpolation extension");
302 runShaderTests(true);
303 runInterpolationTest();
309 var successfullyParsed
= true;
311 <script src=
"../../js/js-test-post.js"></script>