diff --git a/common/api/webgl-compatibility.api.md b/common/api/webgl-compatibility.api.md index f68be618472b..0a339af9e326 100644 --- a/common/api/webgl-compatibility.api.md +++ b/common/api/webgl-compatibility.api.md @@ -105,6 +105,7 @@ export enum DepthType { // @public export interface GraphicsDriverBugs { fragDepthDoesNotDisableEarlyZ?: true; + msaaWillHang?: true; } // @public diff --git a/common/changes/@itwin/webgl-compatibility/markschlosser-fix-msaa-hang-malig71-malig76_2022-04-08-13-29.json b/common/changes/@itwin/webgl-compatibility/markschlosser-fix-msaa-hang-malig71-malig76_2022-04-08-13-29.json new file mode 100644 index 000000000000..2d48565f0e67 --- /dev/null +++ b/common/changes/@itwin/webgl-compatibility/markschlosser-fix-msaa-hang-malig71-malig76_2022-04-08-13-29.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@itwin/webgl-compatibility", + "comment": "Do not allow buggy GPUs to render MSAA.", + "type": "none" + } + ], + "packageName": "@itwin/webgl-compatibility" +} \ No newline at end of file diff --git a/core/webgl-compatibility/src/Capabilities.ts b/core/webgl-compatibility/src/Capabilities.ts index 71c27725142a..33691cb386b0 100644 --- a/core/webgl-compatibility/src/Capabilities.ts +++ b/core/webgl-compatibility/src/Capabilities.ts @@ -73,6 +73,12 @@ const buggyIntelMatchers = [ /ANGLE \(Intel, Intel\(R\) (U)?HD Graphics 6(2|3)0 Direct3D11/, ]; +// Regexes to match Mali GPUs known to suffer from GraphicsDriverBugs.msaaWillHang. +const buggyMaliMatchers = [ + /Mali-G71/, + /Mali-G76/, +]; + // Regexes to match as many Intel integrated GPUs as possible. // https://en.wikipedia.org/wiki/List_of_Intel_graphics_processing_units const integratedIntelGpuMatchers = [ @@ -254,6 +260,16 @@ export class Capabilities { this._isMobile = ProcessDetector.isMobileBrowser; + const debugInfo = gl.getExtension("WEBGL_debug_renderer_info"); + const unmaskedRenderer = debugInfo !== null ? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) : undefined; + const unmaskedVendor = debugInfo !== null ? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) : undefined; + + this._driverBugs = {}; + if (unmaskedRenderer && buggyIntelMatchers.some((x) => x.test(unmaskedRenderer))) + this._driverBugs.fragDepthDoesNotDisableEarlyZ = true; + if (unmaskedRenderer && buggyMaliMatchers.some((x) => x.test(unmaskedRenderer))) + this._driverBugs.msaaWillHang = true; + this._maxTextureSize = gl.getParameter(gl.MAX_TEXTURE_SIZE); this._supportsCreateImageBitmap = typeof createImageBitmap === "function" && ProcessDetector.isChromium && !ProcessDetector.isIOSBrowser; this._maxTexSizeAllow = Math.min(this._maxTextureSize, maxTexSizeAllowed); @@ -263,7 +279,7 @@ export class Capabilities { this._maxVertUniformVectors = gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS); this._maxVaryingVectors = gl.getParameter(gl.MAX_VARYING_VECTORS); this._maxFragUniformVectors = gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS); - this._maxAntialiasSamples = (this._isWebGL2 && undefined !== gl2 ? gl.getParameter(gl2.MAX_SAMPLES) : 1); + this._maxAntialiasSamples = this._driverBugs.msaaWillHang ? 1 : (this._isWebGL2 && undefined !== gl2 ? gl.getParameter(gl2.MAX_SAMPLES) : 1); const extensions = gl.getSupportedExtensions(); // This just retrieves a list of available extensions (not necessarily enabled). if (extensions) { @@ -289,10 +305,6 @@ export class Capabilities { this._maxDrawBuffers = dbExt !== undefined ? gl.getParameter(dbExt.MAX_DRAW_BUFFERS_WEBGL) : 1; } - const debugInfo = gl.getExtension("WEBGL_debug_renderer_info"); - const unmaskedRenderer = debugInfo !== null ? gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL) : undefined; - const unmaskedVendor = debugInfo !== null ? gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL) : undefined; - // Determine the maximum color-renderable attachment type. const allowFloatRender = (undefined === disabledExtensions || -1 === disabledExtensions.indexOf("OES_texture_float")) @@ -323,10 +335,6 @@ export class Capabilities { const missingRequiredFeatures = this._findMissingFeatures(Capabilities.requiredFeatures); const missingOptionalFeatures = this._findMissingFeatures(Capabilities.optionalFeatures); - this._driverBugs = {}; - if (unmaskedRenderer && buggyIntelMatchers.some((x) => x.test(unmaskedRenderer))) - this._driverBugs.fragDepthDoesNotDisableEarlyZ = true; - return { status: this._getCompatibilityStatus(missingRequiredFeatures, missingOptionalFeatures), missingRequiredFeatures, diff --git a/core/webgl-compatibility/src/RenderCompatibility.ts b/core/webgl-compatibility/src/RenderCompatibility.ts index 612422f7e38d..1ca4b846dae4 100644 --- a/core/webgl-compatibility/src/RenderCompatibility.ts +++ b/core/webgl-compatibility/src/RenderCompatibility.ts @@ -89,6 +89,13 @@ export interface GraphicsDriverBugs { * The workaround for this bug has minimal impact on performance and no impact on visual fidelity. */ fragDepthDoesNotDisableEarlyZ?: true; + /** If true, the graphics driver will hang when applying MSAA to a viewport. + * + * Known to affect certain mobile Mali chipsets (G71 and G76). May affect more. + * + * The workaround for this bug means MSAA cannot be enabled on those devices. + */ + msaaWillHang?: true; } /** Describes the level of compatibility of a client device/browser with the iTwin.js rendering system. diff --git a/core/webgl-compatibility/src/test/Compatibility.test.ts b/core/webgl-compatibility/src/test/Compatibility.test.ts index 517915c426b3..a89b83fba373 100644 --- a/core/webgl-compatibility/src/test/Compatibility.test.ts +++ b/core/webgl-compatibility/src/test/Compatibility.test.ts @@ -240,4 +240,30 @@ describe("Render Compatibility", () => { expect(compatibility.usingIntegratedGraphics).to.equal(renderer[1]); } }); + + it("detects MSAA hang bug", () => { + const renderers = [ + [ "Mali-G71", true ], + [ "Mali-G76", true ], + [ "ANGLE (Intel HD Graphics 620 Direct3D11 vs_5_0 ps_5_0)", false ], + [ "Mali-G79", false ], + ]; + + for (const renderer of renderers) { + overriddenFunctions.overrideCreateContext((ctx: WebGLContext, pname: number) => { + const ext = ctx.getExtension("WEBGL_debug_renderer_info"); + if (ext && pname === ext.UNMASKED_RENDERER_WEBGL) + return renderer[0]; + + return undefined; + }); + + const context = makeTestContext(true); + const caps = new Capabilities(); + const compatibility = caps.init(context); + + const expected = renderer[1] ? true : undefined; + expect(compatibility.driverBugs.msaaWillHang).to.equal(expected); + } + }); });