ovr_multiview2_util.js (9584B)
1 /* 2 Copyright (c) 2019 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. 5 */ 6 7 "use strict"; 8 9 function createTextureWithNearestFiltering(target) 10 { 11 let texture = gl.createTexture(); 12 gl.bindTexture(target, texture); 13 gl.texParameteri(target, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 14 gl.texParameteri(target, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 15 gl.texParameteri(target, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 16 gl.texParameteri(target, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 17 wtu.glErrorShouldBe(gl, gl.NO_ERROR, "texture parameter setup should succeed"); 18 return texture; 19 } 20 21 // Write a transformation matrix to elements of floatArray starting from index. 22 // The matrix transforms a unit square (-1 to 1) to a rectangle with the width scaleX and the left edge at offsetX. 23 function setupTranslateAndScaleXMatrix(floatArray, index, scaleX, offsetX) 24 { 25 // x position is transformed according to this equation: scaleX * x0 + translateX = offsetX 26 // By substituting x0 with -1 (unit square x value for the left edge), we get the following: 27 let translateX = offsetX + scaleX; 28 29 floatArray[index] = scaleX; 30 floatArray[index + 1] = 0.0; 31 floatArray[index + 2] = 0.0; 32 floatArray[index + 3] = 0.0; 33 34 floatArray[index + 4] = 0.0; 35 floatArray[index + 5] = 1.0; 36 floatArray[index + 6] = 0.0; 37 floatArray[index + 7] = 0.0; 38 39 floatArray[index + 8] = 0.0; 40 floatArray[index + 9] = 0.0; 41 floatArray[index + 10] = 1.0; 42 floatArray[index + 11] = 0.0; 43 44 floatArray[index + 12] = translateX; 45 floatArray[index + 13] = 0.0; 46 floatArray[index + 14] = 0.0; 47 floatArray[index + 15] = 1.0; 48 } 49 50 // Check the currently bound read framebuffer with dimensions <width> x <height>. 51 // The framebuffer should be divided into <strips> equally wide vertical strips, with the one indicated by 52 // <coloredStripIndex> colored with <expectedStripColor>. The rest of the framebuffer should be colored transparent black. 53 // A two pixel wide region at each edge of the colored region is left unchecked to allow for some tolerance for rasterization. 54 function checkVerticalStrip(width, height, strips, coloredStripIndex, expectedStripColor, framebufferDescription) 55 { 56 let colorRegionLeftEdge = (width / strips) * coloredStripIndex; 57 let colorRegionRightEdge = (width / strips) * (coloredStripIndex + 1); 58 if (coloredStripIndex > 0) { 59 wtu.checkCanvasRect(gl, 0, 0, colorRegionLeftEdge - 1, height, [0, 0, 0, 0], 'the left edge of ' + framebufferDescription + ' should be untouched'); 60 } 61 if (coloredStripIndex < strips - 1) { 62 wtu.checkCanvasRect(gl, colorRegionRightEdge + 1, 0, width - colorRegionRightEdge - 1, height, [0, 0, 0, 0], 'the right edge of ' + framebufferDescription + ' should be untouched'); 63 } 64 wtu.checkCanvasRect(gl, colorRegionLeftEdge + 1, 0, colorRegionRightEdge - colorRegionLeftEdge - 2, height, expectedStripColor, 'a thin strip in ' + framebufferDescription + ' should be colored ' + expectedStripColor); 65 } 66 67 function getMultiviewPassthroughVertexShader(views) { 68 let shaderCode = ['#version 300 es', 69 '#extension GL_OVR_multiview2 : require', 70 71 'layout(num_views = $(num_views)) in;', 72 73 'in vec4 a_position;', 74 75 'void main() {', 76 ' gl_Position = a_position;', 77 '}'].join('\n'); 78 return wtu.replaceParams(shaderCode, {'num_views': views}); 79 } 80 81 // This shader splits the viewport into <views> equally sized vertical strips. 82 // The input quad defined by "a_position" is transformed to fill a different 83 // strip in each view. 84 function getMultiviewOffsetVertexShader(views) { 85 let shaderCode = ['#version 300 es', 86 '#extension GL_OVR_multiview2 : require', 87 88 'layout(num_views = $(num_views)) in;', 89 90 'in vec4 a_position;', 91 92 'void main() {', 93 ' vec4 pos = a_position;', 94 " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id.", 95 ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR)) * 2.0 / $(num_views).0 - 1.0;', 96 ' gl_Position = pos;', 97 '}'].join('\n'); 98 return wtu.replaceParams(shaderCode, {'num_views': views}); 99 } 100 101 // This shader transforms the incoming "a_position" with transforms for each 102 // view given in the uniform array "transform". 103 function getMultiviewRealisticUseCaseVertexShader(views) { 104 let shaderCode = ['#version 300 es', 105 '#extension GL_OVR_multiview2 : require', 106 107 'layout(num_views = $(num_views)) in;', 108 109 'uniform mat4 transform[$(num_views)];', 110 'in vec4 a_position;', 111 112 'void main() {', 113 " // Transform the quad with the transformation matrix chosen according to gl_ViewID_OVR.", 114 ' vec4 pos = transform[gl_ViewID_OVR] * a_position;', 115 ' gl_Position = pos;', 116 '}'].join('\n'); 117 return wtu.replaceParams(shaderCode, {'num_views': views}); 118 } 119 120 function getMultiviewColorFragmentShader() { 121 return ['#version 300 es', 122 '#extension GL_OVR_multiview2 : require', 123 'precision highp float;', 124 125 'out vec4 my_FragColor;', 126 127 'void main() {', 128 ' uint mask = gl_ViewID_OVR + 1u;', 129 ' my_FragColor = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,', 130 ' ((mask & 2u) != 0u) ? 1.0 : 0.0,', 131 ' ((mask & 1u) != 0u) ? 1.0 : 0.0,', 132 ' 1.0);', 133 '}'].join('\n'); 134 } 135 136 function getMultiviewColorFragmentShaderForDrawBuffers(drawBuffers) { 137 let shaderCode = ['#version 300 es', 138 '#extension GL_OVR_multiview2 : require', 139 'precision highp float;', 140 141 'out vec4 my_FragColor[$(drawBuffers)];', 142 143 'void main() {', 144 ' uint mask;']; 145 146 for (let i = 0; i < drawBuffers; ++i) { 147 shaderCode.push(wtu.replaceParams(' mask = gl_ViewID_OVR + $(i)u;', {'i': i + 1})); 148 shaderCode.push(wtu.replaceParams(' my_FragColor[$(i)] = vec4(((mask & 4u) != 0u) ? 1.0 : 0.0,', {'i': i})); 149 shaderCode.push(' ((mask & 2u) != 0u) ? 1.0 : 0.0,'); 150 shaderCode.push(' ((mask & 1u) != 0u) ? 1.0 : 0.0,'); 151 shaderCode.push(' 1.0);'); 152 } 153 shaderCode.push('}'); 154 shaderCode = shaderCode.join('\n'); 155 return wtu.replaceParams(shaderCode, {'drawBuffers' : drawBuffers}); 156 } 157 158 function getMultiviewVaryingVertexShader(views) { 159 let shaderCode = ['#version 300 es', 160 '#extension GL_OVR_multiview2 : require', 161 162 'layout(num_views = $(num_views)) in;', 163 164 'in vec4 a_position;', 165 'out float testVarying;', 166 167 'void main() {', 168 ' gl_Position = a_position;', 169 ' testVarying = float(gl_ViewID_OVR);', 170 '}'].join('\n'); 171 return wtu.replaceParams(shaderCode, {'num_views': views}); 172 } 173 174 function getMultiviewVaryingFragmentShader() { 175 return ['#version 300 es', 176 '#extension GL_OVR_multiview2 : require', 177 'precision highp float;', 178 179 'in float testVarying;', 180 'out vec4 my_FragColor;', 181 182 'void main() {', 183 ' int mask = int(testVarying + 0.1) + 1;', 184 ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,', 185 ' ((mask & 2) != 0) ? 1.0 : 0.0,', 186 ' ((mask & 1) != 0) ? 1.0 : 0.0,', 187 ' 1.0);', 188 '}'].join('\n'); 189 } 190 191 function getMultiviewFlatVaryingVertexShader(views) { 192 let shaderCode = ['#version 300 es', 193 '#extension GL_OVR_multiview2 : require', 194 195 'layout(num_views = $(num_views)) in;', 196 197 'in vec4 a_position;', 198 'flat out int testVarying;', 199 200 'void main() {', 201 ' gl_Position = a_position;', 202 ' testVarying = int(gl_ViewID_OVR);', 203 '}'].join('\n'); 204 return wtu.replaceParams(shaderCode, {'num_views': views}); 205 } 206 207 function getMultiviewFlatVaryingFragmentShader() { 208 return ['#version 300 es', 209 '#extension GL_OVR_multiview2 : require', 210 'precision highp float;', 211 212 'flat in int testVarying;', 213 'out vec4 my_FragColor;', 214 215 'void main() {', 216 ' int mask = testVarying + 1;', 217 ' my_FragColor = vec4(((mask & 4) != 0) ? 1.0 : 0.0,', 218 ' ((mask & 2) != 0) ? 1.0 : 0.0,', 219 ' ((mask & 1) != 0) ? 1.0 : 0.0,', 220 ' 1.0);', 221 '}'].join('\n'); 222 } 223 224 function getMultiviewInstancedVertexShader(views) { 225 let shaderCode = ['#version 300 es', 226 '#extension GL_OVR_multiview2 : require', 227 228 'layout(num_views = $(num_views)) in;', 229 230 'in vec4 a_position;', 231 'out vec4 color;', 232 233 'void main() {', 234 ' vec4 pos = a_position;', 235 " // Transform the quad to a thin vertical strip that's offset along the x axis according to the view id and instance id.", 236 ' pos.x = (pos.x * 0.5 + 0.5 + float(gl_ViewID_OVR) + float(gl_InstanceID)) * 2.0 / ($(num_views).0 * 2.0) - 1.0;', 237 ' int mask = gl_InstanceID + 1;', 238 ' color = vec4(((mask & 4) != 0) ? 1.0 : 0.0,', 239 ' ((mask & 2) != 0) ? 1.0 : 0.0,', 240 ' ((mask & 1) != 0) ? 1.0 : 0.0,', 241 ' 1.0);', 242 ' gl_Position = pos;', 243 '}'].join('\n'); 244 return wtu.replaceParams(shaderCode, {'num_views': views}); 245 } 246 247 function getInstanceColorFragmentShader() { 248 return ['#version 300 es', 249 '#extension GL_OVR_multiview2 : require', 250 'precision highp float;', 251 252 'in vec4 color;', 253 'out vec4 my_FragColor;', 254 255 'void main() {', 256 ' my_FragColor = color;', 257 '}'].join('\n'); 258 } 259 260 function getExpectedColor(view) { 261 var mask = (view + 1); 262 return [(mask & 4) ? 255 : 0, (mask & 2) ? 255 : 0, (mask & 1) ? 255 : 0, 255]; 263 }