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

New GraphicsDevice.getRenderableHdrFormat function #5830

Merged
merged 2 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
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 aso needs to be filterable. Defaults to
mvaligursky marked this conversation as resolved.
Show resolved Hide resolved
* 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) {
Copy link
Contributor

Choose a reason for hiding this comment

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

Just wondering whether for API simplicity whether it's better to just have:

const supported = device.isRenderable(PIXELFORMAT_111110F);

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These are optional parameters, and typically the user would not pass any, to get any format from smallest size to largest.

It's similar to the device creation where we specify GL1, GL2 and GPU array in any other. Simple to call without having to implement logic on the user side.

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 already call this function twice in this code, and one more time in follow up PR .. and it's convenient to not have to implement format logic at each place.

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