MCP 3D Printer Server
by DMontgomery40
Verified
import { HalfFloatType, UnsignedByteType } from '../../../constants.js';
import { GPUPrimitiveTopology, GPUTextureFormat } from './WebGPUConstants.js';
/**
* A WebGPU backend utility module with common helpers.
*
* @private
*/
class WebGPUUtils {
/**
* Constructs a new utility object.
*
* @param {WebGPUBackend} backend - The WebGPU backend.
*/
constructor( backend ) {
/**
* A reference to the WebGPU backend.
*
* @type {WebGPUBackend}
*/
this.backend = backend;
}
/**
* Returns the depth/stencil GPU format for the given render context.
*
* @param {RenderContext} renderContext - The render context.
* @return {String} The depth/stencil GPU texture format.
*/
getCurrentDepthStencilFormat( renderContext ) {
let format;
if ( renderContext.depthTexture !== null ) {
format = this.getTextureFormatGPU( renderContext.depthTexture );
} else if ( renderContext.depth && renderContext.stencil ) {
format = GPUTextureFormat.Depth24PlusStencil8;
} else if ( renderContext.depth ) {
format = GPUTextureFormat.Depth24Plus;
}
return format;
}
/**
* Returns the GPU format for the given texture.
*
* @param {Texture} texture - The texture.
* @return {String} The GPU texture format.
*/
getTextureFormatGPU( texture ) {
return this.backend.get( texture ).format;
}
/**
* Returns an object that defines the multi-sampling state of the given texture.
*
* @param {Texture} texture - The texture.
* @return {Object} The multi-sampling state.
*/
getTextureSampleData( texture ) {
let samples;
if ( texture.isFramebufferTexture ) {
samples = 1;
} else if ( texture.isDepthTexture && ! texture.renderTarget ) {
const renderer = this.backend.renderer;
const renderTarget = renderer.getRenderTarget();
samples = renderTarget ? renderTarget.samples : renderer.samples;
} else if ( texture.renderTarget ) {
samples = texture.renderTarget.samples;
}
samples = samples || 1;
const isMSAA = samples > 1 && texture.renderTarget !== null && ( texture.isDepthTexture !== true && texture.isFramebufferTexture !== true );
const primarySamples = isMSAA ? 1 : samples;
return { samples, primarySamples, isMSAA };
}
/**
* Returns the default color attachment's GPU format of the current render context.
*
* @param {RenderContext} renderContext - The render context.
* @return {String} The GPU texture format of the default color attachment.
*/
getCurrentColorFormat( renderContext ) {
let format;
if ( renderContext.textures !== null ) {
format = this.getTextureFormatGPU( renderContext.textures[ 0 ] );
} else {
format = this.getPreferredCanvasFormat(); // default context format
}
return format;
}
/**
* Returns the output color space of the current render context.
*
* @param {RenderContext} renderContext - The render context.
* @return {String} The output color space.
*/
getCurrentColorSpace( renderContext ) {
if ( renderContext.textures !== null ) {
return renderContext.textures[ 0 ].colorSpace;
}
return this.backend.renderer.outputColorSpace;
}
/**
* Returns GPU primitive topology for the given object and material.
*
* @param {Object3D} object - The 3D object.
* @param {Material} material - The material.
* @return {String} The GPU primitive topology.
*/
getPrimitiveTopology( object, material ) {
if ( object.isPoints ) return GPUPrimitiveTopology.PointList;
else if ( object.isLineSegments || ( object.isMesh && material.wireframe === true ) ) return GPUPrimitiveTopology.LineList;
else if ( object.isLine ) return GPUPrimitiveTopology.LineStrip;
else if ( object.isMesh ) return GPUPrimitiveTopology.TriangleList;
}
/**
* Returns a modified sample count from the given sample count value.
*
* That is required since WebGPU does not support arbitrary sample counts.
*
* @param {Number} sampleCount - The input sample count.
* @return {Number} The (potentially updated) output sample count.
*/
getSampleCount( sampleCount ) {
let count = 1;
if ( sampleCount > 1 ) {
// WebGPU only supports power-of-two sample counts and 2 is not a valid value
count = Math.pow( 2, Math.floor( Math.log2( sampleCount ) ) );
if ( count === 2 ) {
count = 4;
}
}
return count;
}
/**
* Returns the sample count of the given render context.
*
* @param {RenderContext} renderContext - The render context.
* @return {Number} The sample count.
*/
getSampleCountRenderContext( renderContext ) {
if ( renderContext.textures !== null ) {
return this.getSampleCount( renderContext.sampleCount );
}
return this.getSampleCount( this.backend.renderer.samples );
}
/**
* Returns the preferred canvas format.
*
* There is a separate method for this so it's possible to
* honor edge cases for specific devices.
*
* @return {String} The GPU texture format of the canvas.
*/
getPreferredCanvasFormat() {
const outputType = this.backend.parameters.outputType;
if ( outputType === undefined ) {
return navigator.gpu.getPreferredCanvasFormat();
} else if ( outputType === UnsignedByteType ) {
return GPUTextureFormat.BGRA8Unorm;
} else if ( outputType === HalfFloatType ) {
return GPUTextureFormat.RGBA16Float;
} else {
throw new Error( 'Unsupported outputType' );
}
}
}
export default WebGPUUtils;