-
Notifications
You must be signed in to change notification settings - Fork 671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Initial submit of WEBGL_multisampled_render_to_texture proposal #3342
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,160 @@ | ||
<?xml version="1.0"?> | ||
|
||
<extension href="WEBGL_multisampled_render_to_texture/"> | ||
<name>WEBGL_multisampled_render_to_texture</name> | ||
<contact> | ||
<a href="https://www.khronos.org/webgl/public-mailing-list/">WebGL working group</a> (public_webgl 'at' khronos.org) | ||
</contact> | ||
<contributors> | ||
<contributor>Rik Cabanier, Facebook</contributor> | ||
</contributors> | ||
<number>??</number> | ||
<depends> | ||
<api version="1.0"/> | ||
</depends> | ||
<overview> | ||
<mirrors href="https://www.khronos.org/registry/OpenGL/extensions/EXT/EXT_multisampled_render_to_texture2.txt" name="EXT_multisampled_render_to_texture2"> | ||
</mirrors> | ||
<features> | ||
<feature> | ||
Adds support for rendering multisampled to a color renderable texture, without requiring an explicit resolve of multisample data. | ||
</feature> | ||
</features> | ||
</overview> | ||
<idl xml:space="preserve"> | ||
[Exposed=(Window,Worker), LegacyNoInterfaceObject] | ||
interface WEBGL_multisampled_render_to_texture { | ||
const GLenum RENDERBUFFER_SAMPLES_EXT = 0x8CAB; | ||
const GLenum FRAMEBUFFER_INCOMPLETE_MULTISAMPLE_EXT = 0x8D56; | ||
const GLenum MAX_SAMPLES_EXT = 0x8D57; | ||
const GLenum FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT = 0x8D6C; | ||
|
||
undefined renderbufferStorageMultisampleEXT( | ||
GLenum target, GLsizei samples, | ||
GLenum internalformat, | ||
GLsizei width, GLsizei height); | ||
|
||
undefined framebufferTexture2DMultisampleEXT( | ||
GLenum target, GLenum attachment, | ||
GLenum textarget, WebGLTexture? texture, | ||
GLint level, GLsizei samples); | ||
}; | ||
</idl> | ||
<newfun> | ||
<function name="renderbufferStorageMultisampleEXT" type="undefined"> | ||
<param name="target" type="GLenum"/> | ||
<param name="samples" type="GLsizei"/> | ||
<param name="internalformat" type="GLenum"/> | ||
<param name="width" type="GLsizei"/> | ||
<param name="height" type="GLsizei"/> | ||
</function> | ||
</newfun> | ||
<newfun> | ||
<function name="framebufferTexture2DMultisampleEXT" type="undefined"> | ||
<param name="target" type="GLenum"/> | ||
<param name="attachment" type="GLenum"/> | ||
<param name="textarget" type="GLenum"/> | ||
<param name="texture" type="GLuint"/> | ||
<param name="level" type="GLint"/> | ||
<param name="samples" type="GLsizei"/> | ||
</function> | ||
</newfun> | ||
<newtok> | ||
<function name="GetRenderbufferParameter" type="any"> | ||
<param name="target" type="GLenum"/> | ||
<param name="pname" type="GLenum"/> | ||
Calling with the <code>pname</code> set to <code>RENDERBUFFER_SAMPLES_EXT</code> returns the number of samples. | ||
<br/> | ||
<!-- | ||
If <code>renderbufferStorageMultisampleEXT</code> is called with <code>samples</code> is zero, then <code>RENDERBUFFER_SAMPLES_EXT</code> is set to zero. | ||
Otherwise <code>samples</code> represents a request for a desired minimum number | ||
of samples. Since different implementations may support different | ||
sample counts for multisampled rendering, the actual number of samples | ||
allocated for the renderbuffer image is implementation-dependent. | ||
However, the resulting value for <code>RENDERBUFFER_SAMPLES_EXT</code> is | ||
guaranteed to be greater than or equal to samples and no more than the | ||
next larger sample count supported by the implementation. | ||
<br/> | ||
--> | ||
The return type depends on the parameter queried: | ||
<table width="30%"> | ||
<tr><th>pname</th><th>returned type</th></tr> | ||
<tr><td>RENDERBUFFER_SAMPLES_EXT</td><td>GLint</td></tr> | ||
</table> | ||
</function> | ||
<function name="checkFramebufferStatus" type="GLenum"> | ||
<param name="target" type="GLenum"/> | ||
</function> | ||
<function name="getParameter" type="any"> | ||
<param name="pname" type="GLenum"/> | ||
Calling with the <code>pname</code> set to <code>MAX_SAMPLES_EXT</code> returns the maximum number of samples. | ||
<br/> | ||
|
||
The return type depends on the parameter queried: | ||
<table width="30%"> | ||
<tr><th>pname</th><th>returned type</th></tr> | ||
<tr><td>MAX_SAMPLES_EXT</td><td>GLint</td></tr> | ||
</table> | ||
</function> | ||
<function name="getFramebufferAttachmentParameter" type="any"> | ||
<param name="target" type="GLenum"/> | ||
<param name="attachment" type="GLenum"/> | ||
<param name="pname" type="GLenum"/> | ||
Calling with the <code>pname</code> set to <code>FRAMEBUFFER_ATTACHMENT_TEXTURE_SAMPLES_EXT</code> returns the number of samples in the multisampled texture. | ||
<br/> | ||
The return type depends on the parameter queried: | ||
<table width="30%"> | ||
<tr><th>pname</th><th>returned type</th></tr> | ||
<tr><td>MAX_SAMPLES_EXT</td><td>GLint</td></tr> | ||
</table> | ||
</function> | ||
</newtok> | ||
<errors> | ||
<error> | ||
The error <code>OUT_OF_MEMORY</code> is generated when <code>RenderbufferStorageMultisampleEXT</code> cannot create storage of the specified size. | ||
</error> | ||
<error> | ||
If <code>RenderbufferStorageMultisampleEXT</code> is called with a value of <code>samples</code> that is greater than <code>MAX_SAMPLES_EXT</code>, then the error <code>INVALID_VALUE</code> is generated. | ||
</error> | ||
<error> | ||
The error <code>INVALID_ENUM</code> is generated if<code> FramebufferTexture2DMultisampleEXT</code> is called with a target that is not <code>FRAMEBUFFER</code>, <code>DRAW_FRAMEBUFFER</code>, or <code>READ_FRAMEBUFFER</code>. | ||
</error> | ||
<error> | ||
The error <code>INVALID_ENUM</code> is generated if <code>FramebufferTexture2DMultisampleEXT</code> is called with an <code>attachment</code> that is not <code>COLOR_ATTACHMENT0</code>. | ||
</error> | ||
<error> | ||
The error <code>INVALID_ENUM</code> is generated if <code>FramebufferTexture2DMultisampleEXT</code> is called with a textarget that is not <code>TEXTURE_2D</code>, <code>TEXTURE_CUBE_MAP_POSITIVE_X</code>, <code>TEXTURE_CUBE_MAP_POSITIVE_Y</code>, <code>TEXTURE_CUBE_MAP_POSITIVE_Z</code>, <code>TEXTURE_CUBE_MAP_NEGATIVE_X</code>, <code>TEXTURE_CUBE_MAP_NEGATIVE_Y</code>, or <code>TEXTURE_CUBE_MAP_NEGATIVE_Z</code>. | ||
</error> | ||
<error> | ||
The error <code>INVALID_OPERATION</code> is generated if <code>FramebufferTexture2DMultisampleEXT</code> is called with samples greater than the maximum number of samples supported for target and its internalformat. | ||
</error> | ||
</errors> | ||
<samplecode xml:space="preserve"> | ||
<pre> | ||
var gl = document.createElement('canvas').getContext('webgl2'); | ||
var ext = gl.getExtension('WEBGL_multisampled_render_to_texture'); | ||
var samples = gl.getParameter(ext.MAX_SAMPLES_EXT); | ||
var fb = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, fb); | ||
|
||
// Create color texture and storage. | ||
var colorTex = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, colorTex); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 512, 512); | ||
ext.framebufferTexture2DMultisampleEXT(gl.DRAW_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0, samples); | ||
|
||
// Create depth texture and storage. | ||
var depthStencilTex = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, depthStencilTex); | ||
ext.renderbufferStorageMultisampleEXT(gl.RENDER_BUFFER, samples, gl.DEPTH32F_STENCIL8, 512, 512); | ||
ext.framebufferTexture2DMultisampleEXT(gl.DRAW_FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.TEXTURE_2D, depthStencilTex, 0, samples); | ||
|
||
gl.drawElements(...); // Draw will be done with multisampling and flushed to the non-multisample texture. | ||
</pre> | ||
</samplecode> | ||
<history> | ||
<revision date="2021/10/09"> | ||
<change>Initial revision.</change> | ||
</revision> | ||
</history> | ||
</extension> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
<!-- | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add any new tests to For WebGL 1.0 tests, use For WebGL 2.0 tests, use |
||
Copyright (c) 2019 The Khronos Group Inc. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 2021 |
||
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 OVR_multiview2 Conformance Tests</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> | ||
</head> | ||
<body> | ||
<div id="description"></div> | ||
<div id="console"></div> | ||
<script> | ||
"use strict"; | ||
|
||
let wtu = WebGLTestUtils; | ||
let gl = wtu.create3DContext(null, null, 2); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Since the extension is written against the WebGL 1.0 specification, this test should be placed in |
||
let ext = null; | ||
|
||
function runMultisampledTest() { | ||
debug(""); | ||
debug("Testing that color is written as multisampled"); | ||
let program = wtu.setupColorQuad(gl, 0); | ||
gl.viewport(0, 0, 2, 2); | ||
let color = [0, 1.0, 0, 1.0]; | ||
|
||
let fb = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb); | ||
|
||
let colorTex = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, colorTex); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); | ||
ext.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0, 4); | ||
|
||
gl.clearColor(1, 1, 1, 1); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear"); | ||
|
||
gl.useProgram(program); | ||
wtu.drawFloatColorQuad(gl, color); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from drawFloatColorQuad"); | ||
|
||
gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0); | ||
let buf = new Uint8Array(4); | ||
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); | ||
if (buf[0] != 0 || | ||
buf[1] != 255 || | ||
buf[2] != 0 || | ||
buf[3] != 255) { | ||
testFailed("Pixel at should have been (0, 255, 0, 255), " + | ||
"was (" + buf[0] + ", " + buf[1] + ", " + buf[2] + ", " + buf[3] + ")"); | ||
} else | ||
testPassed("runMultisampledTest with full green rgb"); | ||
|
||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb); | ||
let colorTex_partial = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, colorTex_partial); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 1, 1); | ||
ext.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex_partial, 0, 4); | ||
|
||
gl.clearColor(1, 1, 1, 1); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear"); | ||
|
||
program = wtu.setupColorQuad(gl, 0, { scale: 0.5 }); | ||
gl.useProgram(program); | ||
wtu.drawFloatColorQuad(gl, color); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from drawFloatColorQuad"); | ||
|
||
gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex_partial, 0); | ||
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); | ||
if (buf[0] != 191 || | ||
buf[1] != 255 || | ||
buf[2] != 191 || | ||
buf[3] != 255) { | ||
testFailed("Pixel at should have been (191, 255, 191, 255), " + | ||
"was (" + buf[0] + ", " + buf[1] + ", " + buf[2] + ", " + buf[3] + ")"); | ||
} else | ||
testPassed("runMultisampledTest with partial green rgb"); | ||
|
||
let colorTex_srgb = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, colorTex_srgb); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.SRGB8_ALPHA8, 1, 1); | ||
ext.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex_srgb, 0, 4); | ||
|
||
gl.clearColor(0, 0, 0, 0); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear"); | ||
|
||
gl.useProgram(program); | ||
wtu.drawFloatColorQuad(gl, color); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from drawFloatColorQuad"); | ||
|
||
gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex_srgb, 0); | ||
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, buf); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from readpixels"); | ||
if (buf[0] != 0 || | ||
buf[1] != 63 || | ||
buf[2] != 0 || | ||
buf[3] != 63) { | ||
testFailed("Pixel at should have been (0, 63, 0, 63), " + | ||
"was (" + buf[0] + ", " + buf[1] + ", " + buf[2] + ", " + buf[3] + ")"); | ||
} else | ||
testPassed("runMultisampledTest with partial srgb green"); | ||
|
||
debug(""); | ||
} | ||
|
||
function runDrawBuffersClearTest() | ||
{ | ||
debug("Testing that calling clear() clears all views in all draw buffers"); | ||
|
||
let width = 256; | ||
let height = 256; | ||
|
||
let samples = gl.getParameter(ext.MAX_SAMPLES_EXT); | ||
|
||
let fb = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb); | ||
let colorTex = [null, null, null]; | ||
let drawBuffers = [0, 0, 0]; | ||
for (let texIndex = 0; texIndex < colorTex.length; ++texIndex) { | ||
colorTex[texIndex] = gl.createTexture(); | ||
gl.bindTexture(gl.TEXTURE_2D, colorTex[texIndex]); | ||
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, width, height); | ||
ext.framebufferTexture2DMultisampleEXT(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0 + texIndex, gl.TEXTURE_2D, colorTex[texIndex], 0, samples); | ||
drawBuffers[texIndex] = gl.COLOR_ATTACHMENT0 + texIndex; | ||
} | ||
|
||
gl.viewport(0, 0, width, height); | ||
gl.drawBuffers(drawBuffers); | ||
|
||
gl.clearColor(0, 1, 1, 1); | ||
gl.clear(gl.COLOR_BUFFER_BIT); | ||
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "should be no errors from clear"); | ||
|
||
let readFb = gl.createFramebuffer(); | ||
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, readFb); | ||
for (let texIndex = 0; texIndex < colorTex.length; ++texIndex) { | ||
gl.framebufferTexture2D(gl.READ_FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex[texIndex], 0); | ||
let expectedColor = [0, 255, 255, 255]; | ||
wtu.checkCanvasRect(gl, 0, 0, width, height, expectedColor, 'color attachment ' + texIndex + ' should be cyan'); | ||
} | ||
|
||
testPassed("runDrawBuffersClearTest"); | ||
} | ||
|
||
description("This test verifies the functionality of the WEBGL_multisampled_render_to_texture extension, if it is available."); | ||
|
||
debug(""); | ||
|
||
if (!gl) { | ||
testFailed("WebGL context does not exist"); | ||
} else { | ||
testPassed("WebGL context exists"); | ||
|
||
if (!gl.getExtension("WEBGL_multisampled_render_to_texture")) { | ||
testPassed("No WEBGL_multisampled_render_to_texture support -- this is legal"); | ||
} else { | ||
testPassed("Successfully enabled WEBGL_multisampled_render_to_texture extension"); | ||
ext = gl.getExtension('WEBGL_multisampled_render_to_texture'); | ||
|
||
runMultisampledTest(); | ||
|
||
runDrawBuffersClearTest(); | ||
} | ||
} | ||
|
||
debug(""); | ||
var successfullyParsed = true; | ||
</script> | ||
<script src="../../js/js-test-post.js"></script> | ||
|
||
</body> | ||
</html> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please run "make" under the
extensions/
directory and fix the errors generated. At least this href is incorrect; there may be others.