playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
163 lines (162 loc) • 5.23 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { PRIMITIVE_TRIANGLES, SEMANTIC_POSITION } from "../constants.js";
import { BlendState } from "../blend-state.js";
import { DepthState } from "../depth-state.js";
import { RenderTarget } from "../render-target.js";
import { Shader } from "../shader.js";
import { ShaderDefinitionUtils } from "../shader-definition-utils.js";
import { Texture } from "../texture.js";
const _quadPrimitive = {
type: PRIMITIVE_TRIANGLES,
base: 0,
count: 6,
indexed: true
};
const vsSrc = (
/* glsl */
`
attribute vec2 vertex_position;
varying vec2 pcTexCoord;
void main() {
gl_Position = vec4(vertex_position, 0.0, 1.0);
pcTexCoord = vertex_position * 0.5 + 0.5;
}
`
);
const fsSrc = (
/* glsl */
`
uniform sampler2D pcSource;
varying vec2 pcTexCoord;
void main() {
gl_FragColor = texture2D(pcSource, pcTexCoord);
}
`
);
class WebglXrMsaaCopy {
/**
* @param {WebglGraphicsDevice} device - The WebGL graphics device.
*/
constructor(device) {
/**
* @type {WebglGraphicsDevice}
* @private
*/
__publicField(this, "_device");
/**
* @type {Shader|null}
* @private
*/
__publicField(this, "_shader", null);
/**
* @type {Texture|null}
* @private
*/
__publicField(this, "_scratchTex", null);
/**
* @type {RenderTarget|null}
* @private
*/
__publicField(this, "_scratchRt", null);
/**
* @type {import('../../../platform/graphics/scope-id.js').ScopeId|null}
* @private
*/
__publicField(this, "_sourceId", null);
this._device = device;
}
/**
* Returns the copy shader, creating it on first call.
*
* @returns {Shader} The shader.
* @private
*/
_getShader() {
if (!this._shader) {
const device = this._device;
this._shader = new Shader(device, ShaderDefinitionUtils.createDefinition(device, {
name: "XrMsaaCopy",
attributes: { vertex_position: SEMANTIC_POSITION },
vertexCode: vsSrc,
fragmentCode: fsSrc
}));
this._sourceId = device.scope.resolve("pcSource");
}
return this._shader;
}
/**
* Ensure the scratch single-sample texture and its render target exist and match the given
* dimensions. Reallocates if the size has changed (rare: only when XR layer resolution
* changes).
*
* @param {number} width - Full SBS framebuffer width in pixels.
* @param {number} height - Framebuffer height in pixels.
* @private
*/
_ensureScratch(width, height) {
const device = this._device;
if (this._scratchTex && (this._scratchTex.width !== width || this._scratchTex.height !== height)) {
this._scratchRt.destroy();
this._scratchRt = null;
this._scratchTex.destroy();
this._scratchTex = null;
}
if (!this._scratchTex) {
this._scratchTex = Texture.createDataTexture2D(device, "XrMsaaScratch", width, height, device.backBufferFormat);
this._scratchRt = new RenderTarget({
colorBuffer: this._scratchTex,
depth: false,
stencil: false
});
}
if (!this._scratchRt.impl.initialized) {
this._scratchRt.impl.init(device, this._scratchRt);
}
}
/**
* Resolve MSAA color into the XR session framebuffer via a scratch texture and a fullscreen quad.
*
* @param {WebGLFramebuffer} msaaReadFbo - Multisampled source framebuffer.
* @param {WebGLFramebuffer} xrDrawFbo - XR base layer framebuffer.
* @param {number} width - Full SBS framebuffer width in pixels.
* @param {number} height - Framebuffer height in pixels.
*/
copy(msaaReadFbo, xrDrawFbo, width, height) {
this._ensureScratch(width, height);
const device = this._device;
const gl = device.gl;
gl.bindFramebuffer(gl.READ_FRAMEBUFFER, msaaReadFbo);
gl.bindFramebuffer(gl.DRAW_FRAMEBUFFER, this._scratchRt.impl._glFrameBuffer);
gl.blitFramebuffer(0, 0, width, height, 0, 0, width, height, gl.COLOR_BUFFER_BIT, gl.NEAREST);
device.setDrawStates(BlendState.NOBLEND, DepthState.NODEPTH);
device.setFramebuffer(xrDrawFbo);
device.setShader(this._getShader());
device.clearVertexBuffer();
device.setVertexBuffer(device.quadVertexBuffer);
this._sourceId.setValue(this._scratchTex);
const { vx, vy, vw, vh, sx, sy, sw, sh } = device;
device.setViewport(0, 0, width, height);
device.setScissor(0, 0, width, height);
device.draw(_quadPrimitive, device.quadIndexBuffer);
device.setViewport(vx, vy, vw, vh);
device.setScissor(sx, sy, sw, sh);
device.setFramebuffer(msaaReadFbo);
}
/**
* Destroy all GPU resources owned by this instance.
*/
destroy() {
this._shader?.destroy();
this._shader = null;
this._scratchRt?.destroy();
this._scratchRt = null;
this._scratchTex?.destroy();
this._scratchTex = null;
this._sourceId = null;
}
}
export {
WebglXrMsaaCopy
};