Skip to content

Commit

Permalink
New GraphicsDevice.getRenderableHdrFormat function (#5830)
Browse files Browse the repository at this point in the history
* GraphicsDevice.getRenderableHdrFormat function

* Update src/platform/graphics/graphics-device.js

Co-authored-by: Will Eastcott <[email protected]>

---------

Co-authored-by: Martin Valigursky <[email protected]>
Co-authored-by: Will Eastcott <[email protected]>
  • Loading branch information
3 people authored Nov 17, 2023
1 parent 4e2e659 commit af8e9ad
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 41 deletions.
4 changes: 2 additions & 2 deletions src/framework/components/camera/post-effect-queue.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST, PIXELFORMAT_RGBA8 } from '../../../platform/graphics/constants.js';
import { ADDRESS_CLAMP_TO_EDGE, FILTER_NEAREST, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F, PIXELFORMAT_RGBA8 } from '../../../platform/graphics/constants.js';
import { DebugGraphics } from '../../../platform/graphics/debug-graphics.js';
import { RenderTarget } from '../../../platform/graphics/render-target.js';
import { Texture } from '../../../platform/graphics/texture.js';
Expand Down Expand Up @@ -104,7 +104,7 @@ class PostEffectQueue {
_createOffscreenTarget(useDepth, hdr) {

const device = this.app.graphicsDevice;
const format = hdr && device.getHdrFormat(false, true, false, false) || PIXELFORMAT_RGBA8;
const format = hdr && device.getRenderableHdrFormat([PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F], true) || PIXELFORMAT_RGBA8;
const name = this.camera.entity.name + '-posteffect-' + this.effects.length;

const colorBuffer = this._allocateColorBuffer(format, name);
Expand Down
8 changes: 8 additions & 0 deletions src/platform/graphics/blend-state.js
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,14 @@ class BlendState {
* @readonly
*/
static ALPHABLEND = Object.freeze(new BlendState(true, BLENDEQUATION_ADD, BLENDMODE_SRC_ALPHA, BLENDMODE_ONE_MINUS_SRC_ALPHA));

/**
* A blend state that does simple additive blending.
*
* @type {BlendState}
* @readonly
*/
static ADDBLEND = Object.freeze(new BlendState(true, BLENDEQUATION_ADD, BLENDMODE_ONE, BLENDMODE_ONE));
}

export { BlendState };
53 changes: 51 additions & 2 deletions src/platform/graphics/graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
BUFFER_STATIC,
CULLFACE_BACK,
CLEARFLAG_COLOR, CLEARFLAG_DEPTH,
PRIMITIVE_POINTS, PRIMITIVE_TRIFAN, SEMANTIC_POSITION, TYPE_FLOAT32
PRIMITIVE_POINTS, PRIMITIVE_TRIFAN, SEMANTIC_POSITION, TYPE_FLOAT32, PIXELFORMAT_111110F, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F
} from './constants.js';
import { BlendState } from './blend-state.js';
import { DepthState } from './depth-state.js';
Expand Down Expand Up @@ -285,7 +285,15 @@ class GraphicsDevice extends EventHandler {
* @type {boolean}
* @readonly
*/
textureFloatFilterable = true;
textureFloatFilterable = false;

/**
* True if filtering can be applied when sampling 16-bit float textures.
*
* @type {boolean}
* @readonly
*/
textureHalfFloatFilterable = false;

/**
* A vertex buffer representing a quad.
Expand Down Expand Up @@ -809,6 +817,47 @@ class GraphicsDevice extends EventHandler {
*/
frameEnd() {
}

/**
* Get a renderable HDR pixel format supported by the graphics device.
*
* @param {number[]} [formats] - An array of pixel formats to check for support. Can contain:
*
* - {@link PIXELFORMAT_111110F}
* - {@link PIXELFORMAT_RGBA16F}
* - {@link PIXELFORMAT_RGBA32F}
*
* @param {boolean} [filterable] - If true, the format also needs to be filterable. Defaults to
* true.
* @returns {number|undefined} The first supported renderable HDR format or undefined if none is
* supported.
*/
getRenderableHdrFormat(formats = [PIXELFORMAT_111110F, PIXELFORMAT_RGBA16F, PIXELFORMAT_RGBA32F], filterable = true) {
for (let i = 0; i < formats.length; i++) {
const format = formats[i];
switch (format) {

case PIXELFORMAT_111110F: {
if (this.textureRG11B10Renderable)
return format;
break;
}

case PIXELFORMAT_RGBA16F:
if (this.textureHalfFloatRenderable && (!filterable || this.textureHalfFloatFilterable)) {
return format;
}
break;

case PIXELFORMAT_RGBA32F:
if (this.textureFloatRenderable && (!filterable || this.textureFloatFilterable)) {
return format;
}
break;
}
}
return undefined;
}
}

export { GraphicsDevice };
2 changes: 1 addition & 1 deletion src/platform/graphics/texture-utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class TextureUtils {
* @returns {number} The number of mip levels required for the texture.
*/
static calcMipLevelsCount(width, height, depth = 1) {
return 1 + Math.log2(Math.max(width, height, depth));
return 1 + Math.floor(Math.log2(Math.max(width, height, depth)));
}

/**
Expand Down
43 changes: 8 additions & 35 deletions src/platform/graphics/webgl/webgl-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -932,6 +932,7 @@ class WebglGraphicsDevice extends GraphicsDevice {
this.extStandardDerivatives = true;
this.extTextureFloat = true;
this.extTextureHalfFloat = true;
this.textureHalfFloatFilterable = true;
this.extTextureLod = true;
this.extUintElement = true;
this.extVertexArrayObject = true;
Expand All @@ -953,7 +954,6 @@ class WebglGraphicsDevice extends GraphicsDevice {

this.extStandardDerivatives = this.getExtension("OES_standard_derivatives");
this.extTextureFloat = this.getExtension("OES_texture_float");
this.extTextureHalfFloat = this.getExtension("OES_texture_half_float");
this.extTextureLod = this.getExtension('EXT_shader_texture_lod');
this.extUintElement = this.getExtension("OES_element_index_uint");
this.extVertexArrayObject = this.getExtension("OES_vertex_array_object");
Expand All @@ -967,11 +967,17 @@ class WebglGraphicsDevice extends GraphicsDevice {
}
this.extColorBufferFloat = null;
this.extDepthTexture = gl.getExtension('WEBGL_depth_texture');

this.extTextureHalfFloat = this.getExtension("OES_texture_half_float");
this.extTextureHalfFloatLinear = this.getExtension("OES_texture_half_float_linear");
this.textureHalfFloatFilterable = !!this.extTextureHalfFloatLinear;
}

this.extDebugRendererInfo = this.getExtension('WEBGL_debug_renderer_info');

this.extTextureFloatLinear = this.getExtension("OES_texture_float_linear");
this.extTextureHalfFloatLinear = this.getExtension("OES_texture_half_float_linear");
this.textureFloatFilterable = !!this.extTextureFloatLinear;

this.extFloatBlend = this.getExtension("EXT_float_blend");
this.extTextureFilterAnisotropic = this.getExtension('EXT_texture_filter_anisotropic', 'WEBKIT_EXT_texture_filter_anisotropic');
this.extCompressedTextureETC1 = this.getExtension('WEBGL_compressed_texture_etc1');
Expand Down Expand Up @@ -2650,39 +2656,6 @@ class WebglGraphicsDevice extends GraphicsDevice {
return true;
}

/**
* Get a supported HDR pixel format given a set of hardware support requirements.
*
* @param {boolean} preferLargest - If true, prefer the highest precision format. Otherwise prefer the lowest precision format.
* @param {boolean} renderable - If true, only include pixel formats that can be used as render targets.
* @param {boolean} updatable - If true, only include formats that can be updated by the CPU.
* @param {boolean} filterable - If true, only include formats that support texture filtering.
*
* @returns {number} The HDR pixel format or null if there are none.
* @ignore
*/
getHdrFormat(preferLargest, renderable, updatable, filterable) {
// Note that for WebGL2, PIXELFORMAT_RGB16F and PIXELFORMAT_RGB32F are not renderable according to this:
// https://developer.mozilla.org/en-US/docs/Web/API/EXT_color_buffer_float
// For WebGL1, only PIXELFORMAT_RGBA16F and PIXELFORMAT_RGBA32F are tested for being renderable.
const f16Valid = this.extTextureHalfFloat &&
(!renderable || this.textureHalfFloatRenderable) &&
(!updatable || this.textureHalfFloatUpdatable) &&
(!filterable || this.extTextureHalfFloatLinear);
const f32Valid = this.extTextureFloat &&
(!renderable || this.textureFloatRenderable) &&
(!filterable || this.extTextureFloatLinear);

if (f16Valid && f32Valid) {
return preferLargest ? PIXELFORMAT_RGBA32F : PIXELFORMAT_RGBA16F;
} else if (f16Valid) {
return PIXELFORMAT_RGBA16F;
} else if (f32Valid) {
return PIXELFORMAT_RGBA32F;
} /* else */
return null;
}

/**
* Frees memory from all vertex array objects ever allocated with this device.
*
Expand Down
1 change: 1 addition & 0 deletions src/platform/graphics/webgpu/webgpu-graphics-device.js
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ class WebgpuGraphicsDevice extends GraphicsDevice {
this.extUintElement = true;
this.extTextureFloat = true;
this.textureFloatRenderable = true;
this.textureHalfFloatFilterable = true;
this.extTextureHalfFloat = true;
this.textureHalfFloatRenderable = true;
this.textureHalfFloatUpdatable = true;
Expand Down
2 changes: 2 additions & 0 deletions src/platform/graphics/webgpu/webgpu-texture.js
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ class WebgpuTexture {
const wgpu = device.wgpu;
const mipLevelCount = texture.requiredMipLevels;

Debug.assert(texture.width > 0 && texture.height > 0, `Invalid texture dimensions ${texture.width}x${texture.height} for texture ${texture.name}`, texture);

this.descr = {
size: {
width: texture.width,
Expand Down
2 changes: 1 addition & 1 deletion src/scene/scene.js
Original file line number Diff line number Diff line change
Expand Up @@ -791,7 +791,7 @@ class Scene extends EventHandler {
* @type {number}
*/
get lightmapPixelFormat() {
return this.lightmapHDR && this.device.getHdrFormat(false, true, false, true) || PIXELFORMAT_RGBA8;
return this.lightmapHDR && this.device.getRenderableHdrFormat() || PIXELFORMAT_RGBA8;
}
}

Expand Down

0 comments on commit af8e9ad

Please sign in to comment.