Skip to content
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

Add MSAA option for Webgl2 #10052

Merged
merged 37 commits into from
Feb 18, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
fbbe3f3
SceneFramebuffer MSAA
ebogo1 Jan 6, 2022
f86c95b
Invert classification
ebogo1 Jan 19, 2022
59d7d2b
Invert classification with changing numSamples, cleanup
ebogo1 Jan 21, 2022
b9ac432
Cleanup for shared attachments
ebogo1 Jan 21, 2022
bd876c5
blit globeDepth before OIT translucent commands
ebogo1 Jan 26, 2022
5532131
Fix OIT debug framebufer
ebogo1 Jan 26, 2022
f56f3e4
Fix translucent tile classification spec
ebogo1 Jan 26, 2022
4aa7b2e
Merge tag 'pre-let-const' into msaa-es6-merge
ebogo1 Jan 27, 2022
818e24e
Merge tag 'post-let-const' into msaa-es6-merge
ebogo1 Jan 27, 2022
d8977d6
Merge remote-tracking branch 'origin/main' into msaa-es6-merge
ebogo1 Jan 27, 2022
183782f
Add let-const in changed files
ebogo1 Jan 27, 2022
9209c99
MultisampleFramebuffer specs, doc cleanup
ebogo1 Jan 27, 2022
614c88c
Clean up renderTranslucentDepthForPick logic in Scene.js
ebogo1 Jan 27, 2022
d22ee26
Prettier, fix Webgl2 specs
ebogo1 Jan 28, 2022
cbd8c45
Disable multisampling during pick frames
ebogo1 Jan 28, 2022
a3ad889
Disable webgl2 in failing FramebufferManager test
ebogo1 Jan 28, 2022
b443feb
Remove extra createGuid() calls
ebogo1 Jan 28, 2022
8c26a13
Remove PassThrough stage from PostProcessStageCollection
ebogo1 Jan 28, 2022
dd0a7f8
Remove passThrough check in Scene.js
ebogo1 Jan 28, 2022
1301ddd
Check for dirty OIT frames
ebogo1 Jan 28, 2022
dd29f44
Check view.oit is defined
ebogo1 Jan 28, 2022
cd2b741
Scene.js prettier
ebogo1 Jan 31, 2022
1bfb1f1
Store a picking-only Framebuffer in GlobeDepth for pick frames
ebogo1 Feb 1, 2022
87997e2
Rename numberSamples to msaaSamples, fix TranslucentTileClassification
ebogo1 Feb 2, 2022
895c641
Fix HDR, add float and half float RenderbufferFormats
ebogo1 Feb 3, 2022
0fa4811
Add msaaSamples to constructor options, clamp value to GL_MAX_SAMPLES
ebogo1 Feb 3, 2022
c017f5a
Merge branch 'main' into manager-msaa
ebogo1 Feb 3, 2022
67cdee4
Prettier, update getWebGLStub for GL_MAX_SAMPLES
ebogo1 Feb 3, 2022
b982262
Merge branch 'manager-msaa' of github.com:CesiumGS/cesium into manage…
ebogo1 Feb 3, 2022
fd84fd9
Update CHANGES.md and add Sandcastle example
ebogo1 Feb 3, 2022
4c2d6f6
Sandcastle prettier
ebogo1 Feb 3, 2022
496b1c1
Remove blit before pickDepth update
ebogo1 Feb 4, 2022
a2fa0e4
Move MSAA Sandcastle to Showcases, change balloon view, fix MSAA gett…
ebogo1 Feb 17, 2022
06190d3
Do not set stencil buffer bit before blit
ebogo1 Feb 17, 2022
2a04209
Fix TranslucentTileClassificationSpec
ebogo1 Feb 17, 2022
fbf3de9
Pass undefined instead of GlobeDepth texture for failing unit test
ebogo1 Feb 17, 2022
ca82c10
Fix doc [skip ci]
lilleyse Feb 18, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion Source/Renderer/Framebuffer.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ function attachRenderbuffer(framebuffer, attachment, renderbuffer) {
* Framebuffers are used for render-to-texture effects; they allow us to render to
* textures in one pass, and read from it in a later pass.
*
* @param {Object} options The initial framebuffer attachments as shown in the example below. <code>context</code> is required. The possible properties are <code>colorTextures</code>, <code>colorRenderbuffers</code>, <code>depthTexture</code>, <code>depthRenderbuffer</code>, <code>stencilRenderbuffer</code>, <code>depthStencilTexture</code>, and <code>depthStencilRenderbuffer</code>.
* @param {Object} options The initial framebuffer attachments as shown in the example below. <code>context</code> is required. The possible properties are <code>colorTextures</code>, <code>colorRenderbuffers</code>, <code>depthTexture</code>, <code>depthRenderbuffer</code>, <code>stencilRenderbuffer</code>, <code>depthStencilTexture</code>, <code>depthStencilRenderbuffer</code>, and <code>destroyAttachments</code>.
*
* @exception {DeveloperError} Cannot have both color texture and color renderbuffer attachments.
* @exception {DeveloperError} Cannot have both a depth texture and depth renderbuffer attachment.
Expand Down Expand Up @@ -362,6 +362,16 @@ Framebuffer.prototype._unBind = function () {
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
};

Framebuffer.prototype.bindDraw = function () {
const gl = this._gl;
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._framebuffer);
};

Framebuffer.prototype.bindRead = function () {
const gl = this._gl;
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, this._framebuffer);
};

Framebuffer.prototype._getActiveColorAttachments = function () {
return this._activeColorAttachments;
};
Expand Down
196 changes: 168 additions & 28 deletions Source/Renderer/FramebufferManager.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import Framebuffer from "./Framebuffer.js";
import MultisampleFramebuffer from "./MultisampleFramebuffer.js";
import PixelDatatype from "./PixelDatatype.js";
import Renderbuffer from "./Renderbuffer.js";
import RenderbufferFormat from "./RenderbufferFormat.js";
Expand Down Expand Up @@ -31,6 +32,7 @@ import PixelFormat from "../Core/PixelFormat.js";
*/
function FramebufferManager(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
this._numSamples = 1;
ebogo1 marked this conversation as resolved.
Show resolved Hide resolved
this._colorAttachmentsLength = defaultValue(
options.colorAttachmentsLength,
1
Expand Down Expand Up @@ -72,10 +74,13 @@ function FramebufferManager(options) {
this._height = undefined;

this._framebuffer = undefined;
this._multisampleFramebuffer = undefined;
this._colorTextures = undefined;
if (this._color) {
this._colorTextures = new Array(this._colorAttachmentsLength);
this._colorRenderbuffers = new Array(this._colorAttachmentsLength);
}
this._colorRenderbuffer = undefined;
this._depthStencilRenderbuffer = undefined;
this._depthStencilTexture = undefined;
this._depthRenderbuffer = undefined;
Expand All @@ -87,32 +92,43 @@ function FramebufferManager(options) {
Object.defineProperties(FramebufferManager.prototype, {
framebuffer: {
get: function () {
if (this._numSamples > 1) {
return this._multisampleFramebuffer.getRenderFramebuffer();
}
return this._framebuffer;
},
},
status: {
get: function () {
return this._framebuffer.status;
return this.framebuffer.status;
},
},
});

FramebufferManager.prototype.isDirty = function (
width,
height,
numSamples,
pixelDatatype,
pixelFormat
) {
numSamples = defaultValue(numSamples, 1);
const dimensionChanged = this._width !== width || this._height !== height;
const samplesChanged = this._numSamples !== numSamples;
const pixelChanged =
(defined(pixelDatatype) && this._pixelDatatype !== pixelDatatype) ||
(defined(pixelFormat) && this._pixelFormat !== pixelFormat);
const framebufferDefined =
numSamples === 1
? defined(this._framebuffer)
: defined(this._multisampleFramebuffer);

return (
this._attachmentsDirty ||
dimensionChanged ||
samplesChanged ||
pixelChanged ||
!defined(this._framebuffer) ||
!framebufferDefined ||
(this._color && !defined(this._colorTextures[0]))
);
};
Expand All @@ -121,6 +137,7 @@ FramebufferManager.prototype.update = function (
context,
width,
height,
numSamples,
pixelDatatype,
pixelFormat
) {
Expand All @@ -129,6 +146,7 @@ FramebufferManager.prototype.update = function (
throw new DeveloperError("width and height must be defined.");
}
//>>includeEnd('debug');
numSamples = defaultValue(numSamples, 1);
pixelDatatype = defaultValue(
pixelDatatype,
this._color
Expand All @@ -140,10 +158,11 @@ FramebufferManager.prototype.update = function (
this._color ? defaultValue(this._pixelFormat, PixelFormat.RGBA) : undefined
);

if (this.isDirty(width, height, pixelDatatype, pixelFormat)) {
if (this.isDirty(width, height, numSamples, pixelDatatype, pixelFormat)) {
this.destroy();
this._width = width;
this._height = height;
this._numSamples = numSamples;
this._pixelDatatype = pixelDatatype;
this._pixelFormat = pixelFormat;
this._attachmentsDirty = false;
Expand All @@ -159,6 +178,15 @@ FramebufferManager.prototype.update = function (
pixelDatatype: pixelDatatype,
sampler: Sampler.NEAREST,
});
if (this._numSamples > 1) {
this._colorRenderbuffers[i] = new Renderbuffer({
context: context,
width: width,
height: height,
format: RenderbufferFormat.RGBA8,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be format: pixelFormat?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so - we have a validate function in RenderbufferFormat that Renderbuffer expects to pass in its constructor:

validate: function (renderbufferFormat) {
return (
renderbufferFormat === RenderbufferFormat.RGBA4 ||
renderbufferFormat === RenderbufferFormat.RGB5_A1 ||
renderbufferFormat === RenderbufferFormat.RGB565 ||
renderbufferFormat === RenderbufferFormat.DEPTH_COMPONENT16 ||
renderbufferFormat === RenderbufferFormat.STENCIL_INDEX8 ||
renderbufferFormat === RenderbufferFormat.DEPTH_STENCIL
);
},

Though the RGBA8 format doesn't work with when the texture's datatype is floating point, which happens when HDR is turned on. Do we have a RenderbufferFormat that is expected to work with float textures?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You might have to check https://www.khronos.org/registry/webgl/extensions/WEBGL_color_buffer_float/ to see if float textures are supported for renderbuffers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interestingly, this Format Considerations section says that blitting from RGBA8 to RGBA32F (and I believe half float should work too) and vice versa should just work. Chrome and Firefox are reporting src and dst formats differ for color so I'm digging a bit deeper into this one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You may need to convert the pixelFormat to the correct RenderBufferFormat. Hardcoding the renderbuffer format to RGBA8 may break HDR.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a RenderbufferFormat.getColorFormat function in 895c641 that should do the trick. It feels a bit incorrect to pass a PixelDatatype and compare it directly to WebGLConstants values even if that works in this case; on the flip side, I didn't want to import PixelDatatype in RenderbufferFormat. Maybe the getColorFormat is better as a helper function in FramebufferManager.js?

numSamples: this._numSamples,
});
}
}
}

Expand All @@ -173,6 +201,15 @@ FramebufferManager.prototype.update = function (
pixelDatatype: PixelDatatype.UNSIGNED_INT_24_8,
sampler: Sampler.NEAREST,
});
if (this._numSamples > 1) {
this._depthStencilRenderbuffer = new Renderbuffer({
context: context,
width: width,
height: height,
format: RenderbufferFormat.DEPTH24_STENCIL8,
numSamples: this._numSamples,
});
}
} else {
this._depthStencilRenderbuffer = new Renderbuffer({
context: context,
Expand Down Expand Up @@ -204,15 +241,28 @@ FramebufferManager.prototype.update = function (
}
}

this._framebuffer = new Framebuffer({
context: context,
colorTextures: this._colorTextures,
depthTexture: this._depthTexture,
depthRenderbuffer: this._depthRenderbuffer,
depthStencilTexture: this._depthStencilTexture,
depthStencilRenderbuffer: this._depthStencilRenderbuffer,
destroyAttachments: false,
});
if (this._numSamples > 1) {
this._multisampleFramebuffer = new MultisampleFramebuffer({
context: context,
width: this._width,
height: this._height,
colorTextures: this._colorTextures,
colorRenderbuffers: this._colorRenderbuffers,
depthStencilTexture: this._depthStencilTexture,
depthStencilRenderbuffer: this._depthStencilRenderbuffer,
destroyAttachments: false,
});
} else {
this._framebuffer = new Framebuffer({
context: context,
colorTextures: this._colorTextures,
depthTexture: this._depthTexture,
depthRenderbuffer: this._depthRenderbuffer,
depthStencilTexture: this._depthStencilTexture,
depthStencilRenderbuffer: this._depthStencilRenderbuffer,
destroyAttachments: false,
});
}
}
};

Expand Down Expand Up @@ -246,6 +296,39 @@ FramebufferManager.prototype.setColorTexture = function (texture, index) {
this._colorTextures[index] = texture;
};

FramebufferManager.prototype.getColorRenderbuffer = function (index) {
index = defaultValue(index, 0);
//>>includeStart('debug', pragmas.debug);
if (index >= this._colorAttachmentsLength) {
throw new DeveloperError(
"index must be smaller than total number of color attachments."
);
}
//>>includeEnd('debug');
return this._colorRenderbuffers[index];
};

FramebufferManager.prototype.setColorRenderbuffer = function (
renderbuffer,
index
) {
index = defaultValue(index, 0);
//>>includeStart('debug', pragmas.debug);
if (this._createColorAttachments) {
throw new DeveloperError(
"createColorAttachments must be false if setColorRenderbuffer is called."
);
}
if (index >= this._colorAttachmentsLength) {
throw new DeveloperError(
"index must be smaller than total number of color attachments."
);
}
//>>includeEnd('debug');
this._attachmentsDirty = renderbuffer !== this._colorRenderbuffers[index];
this._colorRenderbuffers[index] = renderbuffer;
};

FramebufferManager.prototype.getDepthRenderbuffer = function () {
return this._depthRenderbuffer;
};
Expand Down Expand Up @@ -312,47 +395,104 @@ FramebufferManager.prototype.setDepthStencilTexture = function (texture) {
this._depthStencilTexture = texture;
};

FramebufferManager.prototype.prepareTextures = function (context) {
if (this._numSamples > 1) {
this._multisampleFramebuffer.blitFramebuffers(context);
}
};

FramebufferManager.prototype.clear = function (
context,
clearCommand,
passState
) {
const framebuffer = clearCommand.framebuffer;

clearCommand.framebuffer = this._framebuffer;
clearCommand.execute(context, passState);
if (this._numSamples > 1) {
clearCommand.framebuffer = this._multisampleFramebuffer.getRenderFramebuffer();
clearCommand.execute(context, passState);

clearCommand.framebuffer = this._multisampleFramebuffer.getColorFramebuffer();
ebogo1 marked this conversation as resolved.
Show resolved Hide resolved
clearCommand.execute(context, passState);
} else {
clearCommand.framebuffer = this._framebuffer;
clearCommand.execute(context, passState);
}

clearCommand.framebuffer = framebuffer;
};

FramebufferManager.prototype.destroyFramebuffer = function () {
this._framebuffer = this._framebuffer && this._framebuffer.destroy();
this._multisampleFramebuffer =
this._multisampleFramebuffer && this._multisampleFramebuffer.destroy();
};

FramebufferManager.prototype.destroy = function () {
if (this._color && this._createColorAttachments) {
if (this._color) {
let i;
const length = this._colorTextures.length;
for (let i = 0; i < length; ++i) {
for (i = 0; i < length; ++i) {
const texture = this._colorTextures[i];
if (defined(texture) && !texture.isDestroyed()) {
this._colorTextures[i].destroy();
if (this._createColorAttachments) {
if (defined(texture) && !texture.isDestroyed()) {
this._colorTextures[i].destroy();
this._colorTextures[i] = undefined;
}
}
if (defined(texture) && texture.isDestroyed()) {
this._colorTextures[i] = undefined;
}
const renderbuffer = this._colorRenderbuffers[i];
if (this._createColorAttachments) {
if (defined(renderbuffer) && !renderbuffer.isDestroyed()) {
this._colorRenderbuffers[i].destroy();
this._colorRenderbuffers[i] = undefined;
}
}
if (defined(renderbuffer) && renderbuffer.isDestroyed()) {
this._colorRenderbuffers[i] = undefined;
}
}
}

if (this._depthStencil && this._createDepthAttachments) {
this._depthStencilTexture =
this._depthStencilTexture && this._depthStencilTexture.destroy();
this._depthStencilRenderbuffer =
this._depthStencilRenderbuffer &&
this._depthStencilRenderbuffer.destroy();
if (this._depthStencil) {
if (this._createDepthAttachments) {
this._depthStencilTexture =
this._depthStencilTexture && this._depthStencilTexture.destroy();
this._depthStencilRenderbuffer =
this._depthStencilRenderbuffer &&
this._depthStencilRenderbuffer.destroy();
}
if (
defined(this._depthStencilTexture) &&
this._depthStencilTexture.isDestroyed()
) {
this._depthStencilTexture = undefined;
}
if (
defined(this._depthStencilRenderbuffer) &&
this._depthStencilRenderbuffer.isDestroyed()
) {
this._depthStencilRenderbuffer = undefined;
}
}

if (this._depth && this._createDepthAttachments) {
this._depthTexture = this._depthTexture && this._depthTexture.destroy();
this._depthRenderbuffer =
this._depthRenderbuffer && this._depthRenderbuffer.destroy();
if (this._depth) {
if (this._createDepthAttachments) {
this._depthTexture = this._depthTexture && this._depthTexture.destroy();
this._depthRenderbuffer =
this._depthRenderbuffer && this._depthRenderbuffer.destroy();
}
if (defined(this._depthTexture) && this._depthTexture.isDestroyed()) {
this._depthTexture = undefined;
}
if (
defined(this._depthRenderbuffer) &&
this._depthRenderbuffer.isDestroyed()
) {
this._depthRenderbuffer = undefined;
}
}

this.destroyFramebuffer();
Expand Down
Loading