diff --git a/packages/core/src/shader/Program.js b/packages/core/src/shader/Program.js index 8a889b6..f318112 100644 --- a/packages/core/src/shader/Program.js +++ b/packages/core/src/shader/Program.js @@ -4,11 +4,13 @@ compileProgram, mapSize, mapType, - getTestContext } from './utils'; + getTestContext, + getMaxFragmentPrecision } from './utils'; import { ProgramCache } from '@pixi/utils'; import defaultFragment from './defaultProgram.frag'; import defaultVertex from './defaultProgram.vert'; import { settings } from '@pixi/settings'; +import { PRECISION } from '@pixi/constants'; let UID = 0; @@ -65,8 +67,8 @@ this.vertexSrc = `#define SHADER_NAME ${name}\n${this.vertexSrc}`; this.fragmentSrc = `#define SHADER_NAME ${name}\n${this.fragmentSrc}`; - this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX); - this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT); + this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH); + this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision()); } // currently this does not extract structs only default types diff --git a/packages/core/src/shader/Program.js b/packages/core/src/shader/Program.js index 8a889b6..f318112 100644 --- a/packages/core/src/shader/Program.js +++ b/packages/core/src/shader/Program.js @@ -4,11 +4,13 @@ compileProgram, mapSize, mapType, - getTestContext } from './utils'; + getTestContext, + getMaxFragmentPrecision } from './utils'; import { ProgramCache } from '@pixi/utils'; import defaultFragment from './defaultProgram.frag'; import defaultVertex from './defaultProgram.vert'; import { settings } from '@pixi/settings'; +import { PRECISION } from '@pixi/constants'; let UID = 0; @@ -65,8 +67,8 @@ this.vertexSrc = `#define SHADER_NAME ${name}\n${this.vertexSrc}`; this.fragmentSrc = `#define SHADER_NAME ${name}\n${this.fragmentSrc}`; - this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX); - this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT); + this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH); + this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision()); } // currently this does not extract structs only default types diff --git a/packages/core/src/shader/utils/getMaxFragmentPrecision.js b/packages/core/src/shader/utils/getMaxFragmentPrecision.js new file mode 100644 index 0000000..df58c77 --- /dev/null +++ b/packages/core/src/shader/utils/getMaxFragmentPrecision.js @@ -0,0 +1,25 @@ +import getTestContext from './getTestContext'; +import { PRECISION } from '@pixi/constants'; + +let maxFragmentPrecision; + +export default function getMaxFragmentPrecision() +{ + if (!maxFragmentPrecision) + { + maxFragmentPrecision = PRECISION.MEDIUM; + const gl = getTestContext(); + + if (gl) + { + if (gl.getShaderPrecisionFormat) + { + const shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT); + + maxFragmentPrecision = shaderFragment.precision ? PRECISION.HIGH : PRECISION.MEDIUM; + } + } + } + + return maxFragmentPrecision; +} diff --git a/packages/core/src/shader/Program.js b/packages/core/src/shader/Program.js index 8a889b6..f318112 100644 --- a/packages/core/src/shader/Program.js +++ b/packages/core/src/shader/Program.js @@ -4,11 +4,13 @@ compileProgram, mapSize, mapType, - getTestContext } from './utils'; + getTestContext, + getMaxFragmentPrecision } from './utils'; import { ProgramCache } from '@pixi/utils'; import defaultFragment from './defaultProgram.frag'; import defaultVertex from './defaultProgram.vert'; import { settings } from '@pixi/settings'; +import { PRECISION } from '@pixi/constants'; let UID = 0; @@ -65,8 +67,8 @@ this.vertexSrc = `#define SHADER_NAME ${name}\n${this.vertexSrc}`; this.fragmentSrc = `#define SHADER_NAME ${name}\n${this.fragmentSrc}`; - this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX); - this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT); + this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH); + this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision()); } // currently this does not extract structs only default types diff --git a/packages/core/src/shader/utils/getMaxFragmentPrecision.js b/packages/core/src/shader/utils/getMaxFragmentPrecision.js new file mode 100644 index 0000000..df58c77 --- /dev/null +++ b/packages/core/src/shader/utils/getMaxFragmentPrecision.js @@ -0,0 +1,25 @@ +import getTestContext from './getTestContext'; +import { PRECISION } from '@pixi/constants'; + +let maxFragmentPrecision; + +export default function getMaxFragmentPrecision() +{ + if (!maxFragmentPrecision) + { + maxFragmentPrecision = PRECISION.MEDIUM; + const gl = getTestContext(); + + if (gl) + { + if (gl.getShaderPrecisionFormat) + { + const shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT); + + maxFragmentPrecision = shaderFragment.precision ? PRECISION.HIGH : PRECISION.MEDIUM; + } + } + } + + return maxFragmentPrecision; +} diff --git a/packages/core/src/shader/utils/index.js b/packages/core/src/shader/utils/index.js index 047897d..b5c4827 100644 --- a/packages/core/src/shader/utils/index.js +++ b/packages/core/src/shader/utils/index.js @@ -1,5 +1,6 @@ export { default as compileProgram } from './compileProgram'; export { default as defaultValue } from './defaultValue'; +export { default as getMaxFragmentPrecision } from './getMaxFragmentPrecision'; export { default as setPrecision } from './setPrecision'; export { default as mapSize } from './mapSize'; export { default as mapType } from './mapType'; diff --git a/packages/core/src/shader/Program.js b/packages/core/src/shader/Program.js index 8a889b6..f318112 100644 --- a/packages/core/src/shader/Program.js +++ b/packages/core/src/shader/Program.js @@ -4,11 +4,13 @@ compileProgram, mapSize, mapType, - getTestContext } from './utils'; + getTestContext, + getMaxFragmentPrecision } from './utils'; import { ProgramCache } from '@pixi/utils'; import defaultFragment from './defaultProgram.frag'; import defaultVertex from './defaultProgram.vert'; import { settings } from '@pixi/settings'; +import { PRECISION } from '@pixi/constants'; let UID = 0; @@ -65,8 +67,8 @@ this.vertexSrc = `#define SHADER_NAME ${name}\n${this.vertexSrc}`; this.fragmentSrc = `#define SHADER_NAME ${name}\n${this.fragmentSrc}`; - this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX); - this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT); + this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH); + this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision()); } // currently this does not extract structs only default types diff --git a/packages/core/src/shader/utils/getMaxFragmentPrecision.js b/packages/core/src/shader/utils/getMaxFragmentPrecision.js new file mode 100644 index 0000000..df58c77 --- /dev/null +++ b/packages/core/src/shader/utils/getMaxFragmentPrecision.js @@ -0,0 +1,25 @@ +import getTestContext from './getTestContext'; +import { PRECISION } from '@pixi/constants'; + +let maxFragmentPrecision; + +export default function getMaxFragmentPrecision() +{ + if (!maxFragmentPrecision) + { + maxFragmentPrecision = PRECISION.MEDIUM; + const gl = getTestContext(); + + if (gl) + { + if (gl.getShaderPrecisionFormat) + { + const shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT); + + maxFragmentPrecision = shaderFragment.precision ? PRECISION.HIGH : PRECISION.MEDIUM; + } + } + } + + return maxFragmentPrecision; +} diff --git a/packages/core/src/shader/utils/index.js b/packages/core/src/shader/utils/index.js index 047897d..b5c4827 100644 --- a/packages/core/src/shader/utils/index.js +++ b/packages/core/src/shader/utils/index.js @@ -1,5 +1,6 @@ export { default as compileProgram } from './compileProgram'; export { default as defaultValue } from './defaultValue'; +export { default as getMaxFragmentPrecision } from './getMaxFragmentPrecision'; export { default as setPrecision } from './setPrecision'; export { default as mapSize } from './mapSize'; export { default as mapType } from './mapType'; diff --git a/packages/core/src/shader/utils/setPrecision.js b/packages/core/src/shader/utils/setPrecision.js index c88ede5..bc13eca 100644 --- a/packages/core/src/shader/utils/setPrecision.js +++ b/packages/core/src/shader/utils/setPrecision.js @@ -1,17 +1,36 @@ +import { PRECISION } from '@pixi/constants'; + /** - * Sets the float precision on the shader. If the precision is already present this function will do nothing + * Sets the float precision on the shader, ensuring the device supports the request precision. + * If the precision is already present, it just ensures that the device is able to handle it. + * * @private - * @param {string} src the shader source - * @param {string} precision The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * @param {string} src - The shader source + * @param {string} requestedPrecision - The request float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * @param {string} maxSupportedPrecision - The maximum precision the shader supports. * * @return {string} modified shader source */ -export default function setPrecision(src, precision) +export default function setPrecision(src, requestedPrecision, maxSupportedPrecision) { - if (src.substring(0, 9) !== 'precision')// && src.substring(0, 1) !== '#') + if (src.substring(0, 9) !== 'precision') { + // no precision supplied, so PixiJS will add the requested level. + let precision = requestedPrecision; + + // If highp is requested but not supported, downgrade precision to a level all devices support. + if (requestedPrecision === PRECISION.HIGH && maxSupportedPrecision !== PRECISION.HIGH) + { + precision = PRECISION.MEDIUM; + } + return `precision ${precision} float;\n${src}`; } + else if (maxSupportedPrecision !== PRECISION.HIGH && src.substring(0, 15) === 'precision highp') + { + // precision was supplied, but at a level this device does not support, so downgrading to mediump. + return src.replace('precision highp', 'precision mediump'); + } return src; } diff --git a/packages/core/src/shader/Program.js b/packages/core/src/shader/Program.js index 8a889b6..f318112 100644 --- a/packages/core/src/shader/Program.js +++ b/packages/core/src/shader/Program.js @@ -4,11 +4,13 @@ compileProgram, mapSize, mapType, - getTestContext } from './utils'; + getTestContext, + getMaxFragmentPrecision } from './utils'; import { ProgramCache } from '@pixi/utils'; import defaultFragment from './defaultProgram.frag'; import defaultVertex from './defaultProgram.vert'; import { settings } from '@pixi/settings'; +import { PRECISION } from '@pixi/constants'; let UID = 0; @@ -65,8 +67,8 @@ this.vertexSrc = `#define SHADER_NAME ${name}\n${this.vertexSrc}`; this.fragmentSrc = `#define SHADER_NAME ${name}\n${this.fragmentSrc}`; - this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX); - this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT); + this.vertexSrc = setPrecision(this.vertexSrc, settings.PRECISION_VERTEX, PRECISION.HIGH); + this.fragmentSrc = setPrecision(this.fragmentSrc, settings.PRECISION_FRAGMENT, getMaxFragmentPrecision()); } // currently this does not extract structs only default types diff --git a/packages/core/src/shader/utils/getMaxFragmentPrecision.js b/packages/core/src/shader/utils/getMaxFragmentPrecision.js new file mode 100644 index 0000000..df58c77 --- /dev/null +++ b/packages/core/src/shader/utils/getMaxFragmentPrecision.js @@ -0,0 +1,25 @@ +import getTestContext from './getTestContext'; +import { PRECISION } from '@pixi/constants'; + +let maxFragmentPrecision; + +export default function getMaxFragmentPrecision() +{ + if (!maxFragmentPrecision) + { + maxFragmentPrecision = PRECISION.MEDIUM; + const gl = getTestContext(); + + if (gl) + { + if (gl.getShaderPrecisionFormat) + { + const shaderFragment = gl.getShaderPrecisionFormat(gl.FRAGMENT_SHADER, gl.HIGH_FLOAT); + + maxFragmentPrecision = shaderFragment.precision ? PRECISION.HIGH : PRECISION.MEDIUM; + } + } + } + + return maxFragmentPrecision; +} diff --git a/packages/core/src/shader/utils/index.js b/packages/core/src/shader/utils/index.js index 047897d..b5c4827 100644 --- a/packages/core/src/shader/utils/index.js +++ b/packages/core/src/shader/utils/index.js @@ -1,5 +1,6 @@ export { default as compileProgram } from './compileProgram'; export { default as defaultValue } from './defaultValue'; +export { default as getMaxFragmentPrecision } from './getMaxFragmentPrecision'; export { default as setPrecision } from './setPrecision'; export { default as mapSize } from './mapSize'; export { default as mapType } from './mapType'; diff --git a/packages/core/src/shader/utils/setPrecision.js b/packages/core/src/shader/utils/setPrecision.js index c88ede5..bc13eca 100644 --- a/packages/core/src/shader/utils/setPrecision.js +++ b/packages/core/src/shader/utils/setPrecision.js @@ -1,17 +1,36 @@ +import { PRECISION } from '@pixi/constants'; + /** - * Sets the float precision on the shader. If the precision is already present this function will do nothing + * Sets the float precision on the shader, ensuring the device supports the request precision. + * If the precision is already present, it just ensures that the device is able to handle it. + * * @private - * @param {string} src the shader source - * @param {string} precision The float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * @param {string} src - The shader source + * @param {string} requestedPrecision - The request float precision of the shader. Options are 'lowp', 'mediump' or 'highp'. + * @param {string} maxSupportedPrecision - The maximum precision the shader supports. * * @return {string} modified shader source */ -export default function setPrecision(src, precision) +export default function setPrecision(src, requestedPrecision, maxSupportedPrecision) { - if (src.substring(0, 9) !== 'precision')// && src.substring(0, 1) !== '#') + if (src.substring(0, 9) !== 'precision') { + // no precision supplied, so PixiJS will add the requested level. + let precision = requestedPrecision; + + // If highp is requested but not supported, downgrade precision to a level all devices support. + if (requestedPrecision === PRECISION.HIGH && maxSupportedPrecision !== PRECISION.HIGH) + { + precision = PRECISION.MEDIUM; + } + return `precision ${precision} float;\n${src}`; } + else if (maxSupportedPrecision !== PRECISION.HIGH && src.substring(0, 15) === 'precision highp') + { + // precision was supplied, but at a level this device does not support, so downgrading to mediump. + return src.replace('precision highp', 'precision mediump'); + } return src; } diff --git a/packages/settings/src/settings.js b/packages/settings/src/settings.js index 89e8c5f..57ed219 100644 --- a/packages/settings/src/settings.js +++ b/packages/settings/src/settings.js @@ -180,6 +180,7 @@ /** * Default specify float precision in fragment shader. + * iOS is best set at highp due to https://github.com/pixijs/pixi.js/issues/3742 * * @static * @name PRECISION_FRAGMENT