summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/conformance2/rendering/multisampling-fragment-evaluation.html
blob: df7bce9b0913ce409292bccdc899806af60644b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
<!--
Copyright (c) 2019 The Khronos Group Inc.
Use of this source code is governed by an MIT-style license that can be
found in the LICENSE.txt file.
-->

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>WebGL multisampling fragment shader evaluation</title>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>

<script id="vshader" type="x-shader/x-vertex">#version 300 es
layout(location=0) in vec4 aPosition;
out vec4 vPosition;
void main()
{
    gl_Position = vec4(aPosition);
    vPosition = aPosition;
}
</script>
<script id="fshader" type="x-shader/x-fragment">#version 300 es
precision highp float;
in vec4 vPosition;
layout(location=0) out vec4 oColor;
void main()
{
    if (vPosition.x < 0.0) {
        oColor = vec4(1, 0, 0, 1);
    } else if (vPosition.y < 0.0) {
        oColor = vec4(0, 1, 0, 1);
    } else {
        oColor = vec4(0, 0, 1, 1);
    }
}
</script>

</head>
<body>
<div id="description"></div>
<div id="console"></div>

<script>
"use strict";

var wtu = WebGLTestUtils;
description("Verify that fragment shader is evaluated only once per framebuffer pixel when multisampling is used.");

// GLES 3.0.5 section 3.6.3. Polygon Multisample Rasterization:
// "Polygon rasterization produces a fragment for each framebuffer pixel with one or more sample points that satisfy
// the point sampling criteria described in section 3.6.1."

debug("Regression test for <a href='http://crbug.com/682815'>http://crbug.com/682815</a>");

function runTest(testParams) {
    let canvas = document.createElement('canvas');
    canvas.width = 1;
    canvas.height = 1;
    let gl = wtu.create3DContext(canvas, {antialias: false}, 2);

    // Find the supported samples for a multisampled renderbuffer of the appropriate internal format.
    let samples = gl.getInternalformatParameter(gl.RENDERBUFFER, gl[testParams.internalformat], gl.SAMPLES);
    if (!samples || !samples.length) {
        testFailed("Could not query supported sample counts for required multisampling format " + testParams.internalformat);
        return;
    }

    // Note that supported sample counts are required to be reported in descending order.
    debug('Testing with sample count ' + samples[0]);
    // Create a framebuffer with a multisampled renderbuffer with the maximum supported number of samples.
    let rb = gl.createRenderbuffer();
    gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
    gl.renderbufferStorageMultisample(gl.RENDERBUFFER, samples[0], gl[testParams.internalformat], 1, 1);
    let fb = gl.createFramebuffer();
    gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
    gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
    if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
        testFailed("Rendering to a multisampled renderbuffer of format " + testParams.internalformat + " is required.");
        return;
    }

    // Create a program that will choose between one of different possible colors in the fragment shader.
    // It should be evaluated only once per framebuffer pixel, so only one of the colors will end up in the framebuffer.
    // However, if the multisampling mode is incorrectly implemented by supersampling, the samples may have different
    // colors.
    let program = wtu.setupProgram(gl, ["vshader", "fshader"], ["aPosition"]);

    // Render one triangle using the program. The triangle needs to extend far outside the viewport on all sides, so
    // that we can safely assume all samples fall inside the triangle. GLES 3.0.5:
    // "The sample points associated with a pixel may be located inside or outside of the unit square that is considered to bound the pixel."
    // Here we assume that sample points are less than 9999 pixels away from the pixel they are associated with.
    let buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 10000,  30000,
                                                     -30000, -10000,
                                                      10000, -10000]), gl.STATIC_DRAW);
    gl.enableVertexAttribArray(0);
    gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
    gl.drawArrays(gl.TRIANGLES, 0, 3);

    gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, null);
    gl.blitFramebuffer(0, 0, 1, 1, 0, 0, 1, 1, gl.COLOR_BUFFER_BIT, gl.NEAREST);
    gl.bindFramebuffer(gl.READ_FRAMEBUFFER, null);

    let readBuffer = new Uint8Array(4);
    gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, readBuffer);

    // Check that the canvas is one of the colors that the fragment shader may generate, and not a blend of them.
    let possibleColors = [
        [255, 0, 0, 255],
        [0, 255, 0, 255],
        [0, 0, 255, 255]
    ];
    let anyColorMatched = false;
    for (let i = 0; i < possibleColors.length; ++i) {
        let colorMatched = true;
        for (let j = 0; j < 4; ++j) {
            if (Math.abs(readBuffer[j] - possibleColors[i][j]) > 2) {
                colorMatched = false;
            }
        }
        if (colorMatched) {
            anyColorMatched = true;
        }
    }
    if (!anyColorMatched) {
        testFailed("Color in framebuffer was not one of the colors generated by the fragment shader: " + readBuffer);
    } else {
        testPassed("Color in framebuffer was one of the colors generated by the fragment shader: " + readBuffer);
    }
}

runTest({internalformat: 'RGBA8'});

var successfullyParsed = true;
</script>
<script src="../../js/js-test-post.js"></script>

</body>
</html>