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

Multisampling in FrameBufferSystem #6296

Merged
merged 6 commits into from
Feb 4, 2020
Merged

Multisampling in FrameBufferSystem #6296

merged 6 commits into from
Feb 4, 2020

Conversation

ivanpopelyshev
Copy link
Collaborator

@ivanpopelyshev ivanpopelyshev commented Dec 25, 2019

My minimal implementation for #6288

Demo: https://www.pixiplayground.com/#/edit/ZbmXFH7nt11L70Ux2jUy8

🎁 Added

  • Framebuffer.#multisample - number of samples that user wants. By default its 0 so shortcut if (multisample) can be used.

  • Extra operation blit that has to be called after renderer.render if you think that msaa is enabled on renderTexture. Operation corresponds to low-level gl.blitFramebuffer and requires extra internal framebuffer object to bind the texture.

How it works

API is secure - It won't fail in case of WegGL1 or if there's not enough samples.

Internally, colorTextures[0] for MSAA renderbuffer, so, theoretically, MRT still should work. I didn't test it though. However, colorTextures[0] still exists - that's where we blit the data for later usage.

Why not RenderBuffer object

  1. MSAA is slow and eats extra memory.
  2. WebGL2 doesn't exist in Safari.
  3. I didn't see ThreeJS projects that use MSAA in production.

I do not want to add new objects and abstractions in vanilla PixiJS for a case that cant be used in production.

However, it is good as a temporary solution for demos and prototyping games. Basically, its a Toy.

Two-three hundred lines of code are not much, we just mirror WebGL2 API a bit so people can experiment how it looks.

Future:

Both PR's should be small.

RenderTextureSystem

Add high-level blit operation, that can will either use framebuffer blit, either texture copy either scaling filter, that will enable trivial WebGL1 fallback.

FilterSystem

We can enable usage of custom texture pools per object, specify that we need particular renderTexture for dealing with a container, and that texture can have multisampling.

What cant be in vanilla:

MSAA is slow. I don't believe anyone will use it in production even after those PR's.

I'm working on a real solution that can be used in production by heavy projects:

  1. real WebGL1 antialiasing fallback
  2. caching system with atlases
  3. several antialiasing options for containers / graphics
  4. solution for strange conflation in MSAA :
    image

If this PR will be merged, I won't need to add framebuffer hacks in the plugin.

Another plugin

I hope that this thing covers @SukantPal case for filters, maybe not right now but after next FilterSystem PR.

Copy link
Member

@ShukantPal ShukantPal left a comment

Choose a reason for hiding this comment

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

I think this gets it wrong - you shouldn't have to do a manual blit if you are rendering into a render-texture. In addition, you could add a multisample property on RenderTexture that defers to this.framebuffer.multisample.

@ShukantPal ShukantPal self-requested a review December 25, 2019 17:27
Copy link
Member

@ShukantPal ShukantPal left a comment

Choose a reason for hiding this comment

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

The semantics are inconsistent - a render texture won't 'blend' if clear=false in Renderer.render & multisampling is enabled.

@ShukantPal ShukantPal self-requested a review December 25, 2019 17:37
Copy link
Member

@ShukantPal ShukantPal left a comment

Choose a reason for hiding this comment

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

Your demo doesn't work on Firefox (MacBook Pro, Catalina 2018) (that is a WebGL 2 env). It works on Safari (WebGL 1) but there is no MSAA on that.

Screen Shot 2019-12-25 at 12 37 04 PM

I think you need to fix that; have you tested on a WebGL 2 machine?

@ShukantPal
Copy link
Member

Also, "4. Strange conflation with MSAA" - I think that is because you are not clearing the frame buffer with the background before rendering to it.

@ivanpopelyshev
Copy link
Collaborator Author

ivanpopelyshev commented Dec 25, 2019

Oh, no, macs, my bane! I hate them really, I dont have one. I'll ask for a testing device on work tomorrow.

There shoulnd't be a problem with clearMode, because its an input texture that should be cleared anyway. Maybe I'll add clear there in case of forceClear just to be compliant.

Exactly, case 4 is done when something is already drawn, and the problem is that users will do it anyway. We need a way to mitigate the damage, my solution is to apply AA to all shapes befure they start combining them.

I've modified demo a bit to compare samples=4 and samples=8.

@ShukantPal
Copy link
Member

@ivanpopelyshev Why are using resolution=.125 in your demo?

@eXponenta
Copy link
Contributor

MacOS/ iOS WebGL2 support is worst.

@ShukantPal
Copy link
Member

MacOS/ iOS WebGL2 support is worst.

@eXponenta The other PR works on my machine (the one with Renderbuffer classes). It is actually a problem with this PR. @ivanpopelyshev What machine are you testing on, does it have WebGL 2?

@eXponenta
Copy link
Contributor

His machine has fully WebGL2 support.

@ShukantPal
Copy link
Member

@eXponenta WebGL 2 support depends on the browser I guess, not on the machine.

@eXponenta
Copy link
Contributor

eXponenta commented Dec 25, 2019

It isn't fully true.
Because on windows there is a AGILE (Chromium) backend for Webgl to dx translation.
But on other machines (OS) webGL use OpenGL. Apple stop support openGL greater than 2.0es (WebGL 1), and WebGL2 translate to metal, with some problems.

@ShukantPal
Copy link
Member

@eXponenta Well, MacBooks of course have the graphics ability to support WebGL 2. The browsers are supposed to bind the WebGL API to a OpenGL backend.

@ivanpopelyshev
Copy link
Collaborator Author

The heck is going on on apple devices? We'll know tomorrow when I get said devices from test team! Stay tuned!

@codecov-io
Copy link

codecov-io commented Dec 26, 2019

Codecov Report

Merging #6296 into dev will decrease coverage by 0.62%.
The diff coverage is 94.28%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev    #6296      +/-   ##
==========================================
- Coverage   77.79%   77.16%   -0.63%     
==========================================
  Files         186      183       -3     
  Lines       10219     9670     -549     
==========================================
- Hits         7950     7462     -488     
+ Misses       2269     2208      -61
Impacted Files Coverage Δ
packages/prepare/src/BasePrepare.js 73.43% <ø> (ø) ⬆️
packages/text-bitmap/src/BitmapFontData.js 100% <100%> (ø)
packages/text-bitmap/src/BitmapText.js 80.21% <100%> (-2.72%) ⬇️
packages/mixin-cache-as-bitmap/src/index.js 52.72% <100%> (ø) ⬆️
...es/core/src/filters/spriteMask/SpriteMaskFilter.js 95.23% <100%> (ø) ⬆️
packages/core/src/Renderer.js 89.61% <100%> (-1.23%) ⬇️
packages/graphics/src/utils/buildCircle.js 57.14% <100%> (ø) ⬆️
packages/text-bitmap/src/formats/index.js 100% <100%> (ø)
packages/text-bitmap/src/formats/XMLFormat.js 100% <100%> (ø)
packages/text-bitmap/src/BitmapFontLoader.js 78.43% <82.14%> (+3.43%) ⬆️
... and 9 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 353f7db...28f4c7f. Read the comment docs.

@ivanpopelyshev
Copy link
Collaborator Author

Shame on me, I had a mistake in FOR cycle! Added a unit test for it. Now it should work on mac devices that somehow support webgl2

@ivanpopelyshev
Copy link
Collaborator Author

Need to test this thing on iOS 13.2 Safari . @SukantPal whats your device?

@ShukantPal
Copy link
Member

ShukantPal commented Dec 26, 2019

@ivanpopelyshev It works now! (macOS Catalina, 2018 i7 MacBook Pro).

And MacBooks don't "somehow" support WebGL 2 - Firefox & Chrome do on all of 'em. It is just that Safari developers aren't implementing that API.

Copy link
Member

@GoodBoyDigital GoodBoyDigital left a comment

Choose a reason for hiding this comment

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

nice man! WIll need to discuss with @SukantPal which of the two PRs should be merged in.

Currently i'm leaning towards this PR as there is less Code to get us MSAA.
But @SukantPal's PR seems more flexible.. my question would be is there anything other than MSAA we can achieve with blitting and renderBuffers?

* @param {number} samples number of samples
* @returns {number} recommended number of samples
*/
detectSamples(samples)
Copy link
Member

Choose a reason for hiding this comment

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

do we need this? Can we rather, just check values are PO2?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I really don't know what to put there. This thing works and is covered by a test. I don't know which values are available on different systems, I didn't research it.

Copy link
Member

Choose a reason for hiding this comment

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

I think we should just enforce the use of the consts?

export enum MSAA_QUALITY {
NONE = 0,
LOW = 0,
MEDIUM = 4,
HIGH = 8
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

image

nothing about pow2. I do not understand what do you want to put there. I made basic algorithm, it should work according to the test and specification. If user wants to specify 16 and some videocard actually allows it - fine. Btw, there's no guarantee about order and i use it. Maybe I should actually add sort() somewhere just to be sure.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

it looks like there's no 16: https://webglstats.com/webgl2/parameter/SAMPLES

Maybe its my stupid time - I don't know what to write with those IF's. There will be more code in that case.

@bigtimebuddy bigtimebuddy added this to the v5.3.0 milestone Jan 10, 2020
@ShukantPal
Copy link
Member

@bigtimebuddy @GoodBoyDigital I don't think we should really delay this any longer. If you want, we could finalize this pull request.

I just want you to consider whether we should require users to do a blit after rendering to a multisample render-texture. I think that'll be a big source of bugs.

We might also need to consider blend modes for multisample render-textures. Renderbuffer blits don't support "blending", and this will break some expected behaviors. Instead of blitting directly onto the "texture", we might need to blit into a secondary texture and then render that onto the actual render-texture (via a shader that will blend).

@ivanpopelyshev
Copy link
Collaborator Author

Instead of blitting directly onto the "texture", we might need to blit into a secondary texture and then render that onto the actual render-texture (via a shader that will blend).

This PR doesn't actually forbid a blitting with shader, it doesnt include it on low-level. I use extra filter for blitting in my fork, and I think it has to be part of high-level object, alongside with WebGL1 fallback and some other things.

@ShukantPal
Copy link
Member

@ivanpopelyshev I don't understand what you said. "This PR doesn't forbid blitting with a shader". How? First of all, blitting can't be done by a shader (by definition). It just copying the pixels from a render buffer onto a texture (no blending, direct copy).

"I use extra filter for blitting in my fork, and I think it has to be part of high-level object" - that doesn't make sense.

All my complaint is that we're going to have to add a line after rendering to use multisample in PixiJS -

app.renderer.render(circle, buf);
app.renderer.framebuffer.blit();

What is the problem if the blitting is handled as a part of the rendering pipeline. I don't think any user would expect to a blit after calling render. Do you have an example of a framework that uses these semantics? You said you wanted "users to know about the blit operation". Now @bigtimebuddy & @GoodBoyDigital will have to decide whether that reason is enough to separate blitting from the rendering process.

@ShukantPal
Copy link
Member

@ivanpopelyshev I still don't understand why your example uses 1/8th resolution on the textures. That just nullifies the effect of multisampling.

@ShukantPal ShukantPal self-requested a review January 12, 2020 19:18
@ivanpopelyshev
Copy link
Collaborator Author

ivanpopelyshev commented Jan 13, 2020

I still don't understand why your example uses 1/8th resolution on the textures. That just nullifies the effect of multisampling.

To actually see that it works on a 4k screen.

@ShukantPal
Copy link
Member

What do you see on a 4K screen? If you’re on a 4K screen, it will still just render as normal.

On my screen, it has jagged edges and doesn’t look like a circle. You’re supposed to use 1x resolution so the multisample makes the effective resolution 8. The whole point is to multisample each pixel 8 times, not multisample 8 pixels 8 times.

@ivanpopelyshev
Copy link
Collaborator Author

What do you see on a 4K screen? If you’re on a 4K screen, it will still just render as normal.

On my screen, it has jagged edges and doesn’t look like a circle. You’re supposed to use 1x resolution so the multisample makes the effective resolution 8. The whole point is to multisample each pixel 8 times, not multisample 8 pixels 8 times.

Pixels are half-red, that means AA is working :)

Copy link
Member

@bigtimebuddy bigtimebuddy left a comment

Choose a reason for hiding this comment

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

Couple of small documentation things. Otherwise looks good. Thanks for the demo in the description @ivanpopelyshev.

@@ -409,3 +409,22 @@ export enum MASK_TYPES {
STENCIL = 2,
SPRITE = 3,
}

/**
* Constants for multi-sampling antialiasing
Copy link
Member

Choose a reason for hiding this comment

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

I would like really more documentation about this feature being experimental and that there's a significant performance cost paid for using it. Also, it's not super obvious, but a code example usage setting renderer.framebuffer.multisample.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

linked it to Framebuffer#multisample. Don't want to ctrl+C everything.

packages/core/src/framebuffer/Framebuffer.ts Show resolved Hide resolved
packages/core/src/framebuffer/GLFramebuffer.ts Outdated Show resolved Hide resolved
packages/core/src/framebuffer/GLFramebuffer.ts Outdated Show resolved Hide resolved
@codecov-io
Copy link

codecov-io commented Feb 3, 2020

Codecov Report

Merging #6296 into dev will increase coverage by 2.42%.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##              dev   #6296      +/-   ##
=========================================
+ Coverage   74.27%   76.7%   +2.42%     
=========================================
  Files          85      76       -9     
  Lines        4615    4142     -473     
=========================================
- Hits         3428    3177     -251     
+ Misses       1187     965     -222

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 34f2401...4e536d2. Read the comment docs.

@ShukantPal
Copy link
Member

@ivanpopelyshev Should we have a fallback to higher resolution if multisampling is not supported on the device? When forcing WebGL 1, the half-red pixels do not show up.

@ShukantPal ShukantPal self-requested a review February 3, 2020 23:11
@ShukantPal
Copy link
Member

@bigtimebuddy @GoodBoyDigital I approved this - but I did have concerns about requiring a blit operation after render. There is also no documentation regarding this (is there?)

@ivanpopelyshev
Copy link
Collaborator Author

@SukantPal good catch! I put it in PIXI.Framebuffer#multisample and linked from PIXI.MSAA_QUALITY

@bigtimebuddy bigtimebuddy merged commit 8d53426 into dev Feb 4, 2020
@bigtimebuddy bigtimebuddy deleted the feature-multisampling branch February 4, 2020 21:45
@bigtimebuddy
Copy link
Member

Thanks everyone for getting this feature through!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants