123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559 |
- // Copyright 2020 Brandon Jones
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to deal
- // in the Software without restriction, including without limitation the rights
- // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- // copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- // SOFTWARE.
- import * as WebGPUConstants from './webgpuConstants';
- import { Scalar } from '../../Maths/math.scalar';
- import { WebGPUBufferManager } from './webgpuBufferManager';
- import { Constants } from '../constants';
- import { Nullable } from '../../types';
- // TODO WEBGPU improve mipmap generation by not using the OutputAttachment flag
- // see https://github.com/toji/web-texture-tool/tree/main/src
- const mipmapVertexSource = `
- #version 450
- const vec2 pos[4] = vec2[4](vec2(-1.0f, 1.0f), vec2(1.0f, 1.0f), vec2(-1.0f, -1.0f), vec2(1.0f, -1.0f));
- const vec2 tex[4] = vec2[4](vec2(0.0f, 0.0f), vec2(1.0f, 0.0f), vec2(0.0f, 1.0f), vec2(1.0f, 1.0f));
- layout(location = 0) out vec2 vTex;
- void main() {
- vTex = tex[gl_VertexIndex];
- gl_Position = vec4(pos[gl_VertexIndex], 0.0, 1.0);
- }
- `;
- const mipmapFragmentSource = `
- #version 450
- layout(set = 0, binding = 0) uniform sampler imgSampler;
- layout(set = 0, binding = 1) uniform texture2D img;
- layout(location = 0) in vec2 vTex;
- layout(location = 0) out vec4 outColor;
- void main() {
- outColor = texture(sampler2D(img, imgSampler), vTex);
- }
- `;
- export class WebGPUTextureHelper {
- private _device: GPUDevice;
- private _glslang: any;
- private _bufferManager: WebGPUBufferManager;
- private _mipmapSampler: GPUSampler;
- private _mipmapPipelines: { [format: string]: GPURenderPipeline } = {};
- public static computeNumMipmapLevels(width: number, height: number) {
- return Scalar.ILog2(Math.max(width, height)) + 1;
- }
- constructor(device: GPUDevice, glslang: any, bufferManager: WebGPUBufferManager) {
- this._device = device;
- this._glslang = glslang;
- this._bufferManager = bufferManager;
- this._mipmapSampler = device.createSampler({ minFilter: WebGPUConstants.FilterMode.Linear });
- this._getPipeline(WebGPUConstants.TextureFormat.RGBA8Unorm);
- }
- private _getPipeline(format: GPUTextureFormat): GPURenderPipeline {
- let pipeline = this._mipmapPipelines[format];
- if (!pipeline) {
- pipeline = this._mipmapPipelines[format] = this._device.createRenderPipeline({
- vertexStage: {
- module: this._device.createShaderModule({
- code: this._glslang.compileGLSL(mipmapVertexSource, 'vertex')
- }),
- entryPoint: 'main'
- },
- fragmentStage: {
- module: this._device.createShaderModule({
- code: this._glslang.compileGLSL(mipmapFragmentSource, 'fragment')
- }),
- entryPoint: 'main'
- },
- primitiveTopology: WebGPUConstants.PrimitiveTopology.TriangleStrip,
- vertexState: {
- indexFormat: WebGPUConstants.IndexFormat.Uint16
- },
- colorStates: [{
- format: format,
- }]
- });
- }
- return pipeline;
- }
- public isImageBitmap(imageBitmap: ImageBitmap | { width: number, height: number }): imageBitmap is ImageBitmap {
- return (imageBitmap as ImageBitmap).close !== undefined;
- }
- public isImageBitmapArray(imageBitmap: ImageBitmap[] | { width: number, height: number }): imageBitmap is ImageBitmap[] {
- return Array.isArray(imageBitmap as ImageBitmap[]) && (imageBitmap as ImageBitmap[])[0].close !== undefined;
- }
- public isCompressedFormat(format: GPUTextureFormat): boolean {
- switch (format) {
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC6HRGBSFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- return true;
- }
- return false;
- }
- public createTexture(imageBitmap: ImageBitmap | { width: number, height: number }, hasMipmaps = false, generateMipmaps = false, invertY = false, premultiplyAlpha = false, format: GPUTextureFormat = WebGPUConstants.TextureFormat.RGBA8Unorm,
- sampleCount = 1, commandEncoder?: GPUCommandEncoder, usage = -1): GPUTexture
- {
- let textureSize = {
- width: imageBitmap.width,
- height: imageBitmap.height,
- depth: 1,
- };
- const mipLevelCount = hasMipmaps ? WebGPUTextureHelper.computeNumMipmapLevels(imageBitmap.width, imageBitmap.height) : 1;
- const usages = usage >= 0 ? usage : WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.CopyDst | WebGPUConstants.TextureUsage.Sampled;
- const additionalUsages = hasMipmaps && !this.isCompressedFormat(format) ? WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment : 0;
- const gpuTexture = this._device.createTexture({
- size: textureSize,
- dimension: WebGPUConstants.TextureDimension.E2d,
- format,
- usage: usages | additionalUsages,
- sampleCount,
- mipLevelCount
- });
- if (this.isImageBitmap(imageBitmap)) {
- this.updateTexture(imageBitmap, gpuTexture, imageBitmap.width, imageBitmap.height, format, 0, 0, invertY, premultiplyAlpha, 0, 0, commandEncoder);
- if (hasMipmaps && generateMipmaps) {
- this.generateMipmaps(gpuTexture, format, mipLevelCount, 0, commandEncoder);
- }
- }
- return gpuTexture;
- }
- public createCubeTexture(imageBitmaps: ImageBitmap[] | { width: number, height: number }, hasMipmaps = false, generateMipmaps = false, invertY = false, premultiplyAlpha = false, format: GPUTextureFormat = WebGPUConstants.TextureFormat.RGBA8Unorm,
- sampleCount = 1, commandEncoder?: GPUCommandEncoder, usage = -1): GPUTexture
- {
- const width = this.isImageBitmapArray(imageBitmaps) ? imageBitmaps[0].width : imageBitmaps.width;
- const height = this.isImageBitmapArray(imageBitmaps) ? imageBitmaps[0].height : imageBitmaps.height;
- const mipLevelCount = hasMipmaps ? WebGPUTextureHelper.computeNumMipmapLevels(width, height) : 1;
- const usages = usage >= 0 ? usage : WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.CopyDst | WebGPUConstants.TextureUsage.Sampled;
- const additionalUsages = hasMipmaps && !this.isCompressedFormat(format) ? WebGPUConstants.TextureUsage.CopySrc | WebGPUConstants.TextureUsage.OutputAttachment : 0;
- const gpuTexture = this._device.createTexture({
- size: {
- width,
- height,
- depth: 6,
- },
- dimension: WebGPUConstants.TextureDimension.E2d,
- format,
- usage: usages | additionalUsages,
- sampleCount,
- mipLevelCount
- });
- if (this.isImageBitmapArray(imageBitmaps)) {
- this.updateCubeTextures(imageBitmaps, gpuTexture, width, height, format, invertY, premultiplyAlpha, 0, 0, commandEncoder);
- if (hasMipmaps && generateMipmaps) {
- this.generateCubeMipmaps(gpuTexture, format, mipLevelCount, commandEncoder);
- }
- }
- return gpuTexture;
- }
- public generateCubeMipmaps(gpuTexture: GPUTexture, format: GPUTextureFormat, mipLevelCount: number, commandEncoder?: GPUCommandEncoder): void {
- for (let f = 0; f < 6; ++f) {
- this.generateMipmaps(gpuTexture, format, mipLevelCount, f, commandEncoder);
- }
- }
- public generateMipmaps(gpuTexture: GPUTexture, format: GPUTextureFormat, mipLevelCount: number, faceIndex= 0, commandEncoder?: GPUCommandEncoder): void {
- const useOwnCommandEncoder = commandEncoder === undefined;
- const pipeline = this._getPipeline(format);
- const bindGroupLayout = pipeline.getBindGroupLayout(0);
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- commandEncoder!.pushDebugGroup("start create mipmaps");
- for (let i = 1; i < mipLevelCount; ++i) {
- const passEncoder = commandEncoder!.beginRenderPass({
- colorAttachments: [{
- attachment: gpuTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: i,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: faceIndex,
- }),
- loadValue: { r: 0.0, g: 0.0, b: 0.0, a: 0.0 },
- }],
- });
- const bindGroup = this._device.createBindGroup({
- layout: bindGroupLayout,
- entries: [{
- binding: 0,
- resource: this._mipmapSampler,
- }, {
- binding: 1,
- resource: gpuTexture.createView({
- dimension: WebGPUConstants.TextureViewDimension.E2d,
- baseMipLevel: i - 1,
- mipLevelCount: 1,
- arrayLayerCount: 1,
- baseArrayLayer: faceIndex,
- }),
- }],
- });
- passEncoder.setPipeline(pipeline);
- passEncoder.setBindGroup(0, bindGroup);
- passEncoder.draw(4, 1, 0, 0);
- passEncoder.endPass();
- }
- commandEncoder!.popDebugGroup();
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- }
- private _getTextureTypeFromFormat(format: GPUTextureFormat): number {
- switch (format) {
- // One Component = 8 bits
- case WebGPUConstants.TextureFormat.R8Unorm:
- case WebGPUConstants.TextureFormat.R8Snorm:
- case WebGPUConstants.TextureFormat.R8Uint:
- case WebGPUConstants.TextureFormat.R8Sint:
- case WebGPUConstants.TextureFormat.RG8Unorm:
- case WebGPUConstants.TextureFormat.RG8Snorm:
- case WebGPUConstants.TextureFormat.RG8Uint:
- case WebGPUConstants.TextureFormat.RG8Sint:
- case WebGPUConstants.TextureFormat.RGBA8Unorm:
- case WebGPUConstants.TextureFormat.RGBA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGBA8Snorm:
- case WebGPUConstants.TextureFormat.RGBA8Uint:
- case WebGPUConstants.TextureFormat.RGBA8Sint:
- case WebGPUConstants.TextureFormat.BGRA8Unorm:
- case WebGPUConstants.TextureFormat.BGRA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGB10A2Unorm: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.RGB9E5UFloat: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.RG11B10UFloat: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.Depth24UnormStencil8: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.Depth32FloatStencil8: // composite format - let's say it's byte...
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBSFloat:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- return Constants.TEXTURETYPE_UNSIGNED_BYTE;
- // One component = 16 bits
- case WebGPUConstants.TextureFormat.R16Uint:
- case WebGPUConstants.TextureFormat.R16Sint:
- case WebGPUConstants.TextureFormat.RG16Uint:
- case WebGPUConstants.TextureFormat.RG16Sint:
- case WebGPUConstants.TextureFormat.RGBA16Uint:
- case WebGPUConstants.TextureFormat.RGBA16Sint:
- case WebGPUConstants.TextureFormat.Depth16Unorm:
- return Constants.TEXTURETYPE_UNSIGNED_SHORT;
- case WebGPUConstants.TextureFormat.R16Float:
- case WebGPUConstants.TextureFormat.RG16Float:
- case WebGPUConstants.TextureFormat.RGBA16Float:
- return Constants.TEXTURETYPE_HALF_FLOAT;
- // One component = 32 bits
- case WebGPUConstants.TextureFormat.R32Uint:
- case WebGPUConstants.TextureFormat.R32Sint:
- case WebGPUConstants.TextureFormat.RG32Uint:
- case WebGPUConstants.TextureFormat.RG32Sint:
- case WebGPUConstants.TextureFormat.RGBA32Uint:
- case WebGPUConstants.TextureFormat.RGBA32Sint:
- return Constants.TEXTURETYPE_UNSIGNED_INTEGER;
- case WebGPUConstants.TextureFormat.R32Float:
- case WebGPUConstants.TextureFormat.RG32Float:
- case WebGPUConstants.TextureFormat.RGBA32Float:
- case WebGPUConstants.TextureFormat.Depth32Float:
- return Constants.TEXTURETYPE_FLOAT;
- case WebGPUConstants.TextureFormat.Stencil8:
- throw "No fixed size for Stencil8 format!";
- case WebGPUConstants.TextureFormat.Depth24Plus:
- throw "No fixed size for Depth24Plus format!";
- case WebGPUConstants.TextureFormat.Depth24PlusStencil8:
- throw "No fixed size for Depth24PlusStencil8 format!";
- }
- return Constants.TEXTURETYPE_UNSIGNED_BYTE;
- }
- private _getBlockInformationFromFormat(format: GPUTextureFormat): { width: number, height: number, length: number } {
- switch (format) {
- // 8 bits formats
- case WebGPUConstants.TextureFormat.R8Unorm:
- case WebGPUConstants.TextureFormat.R8Snorm:
- case WebGPUConstants.TextureFormat.R8Uint:
- case WebGPUConstants.TextureFormat.R8Sint:
- return { width: 1, height: 1, length: 1 };
- // 16 bits formats
- case WebGPUConstants.TextureFormat.R16Uint:
- case WebGPUConstants.TextureFormat.R16Sint:
- case WebGPUConstants.TextureFormat.R16Float:
- case WebGPUConstants.TextureFormat.RG8Unorm:
- case WebGPUConstants.TextureFormat.RG8Snorm:
- case WebGPUConstants.TextureFormat.RG8Uint:
- case WebGPUConstants.TextureFormat.RG8Sint:
- return { width: 1, height: 1, length: 2 };
- // 32 bits formats
- case WebGPUConstants.TextureFormat.R32Uint:
- case WebGPUConstants.TextureFormat.R32Sint:
- case WebGPUConstants.TextureFormat.R32Float:
- case WebGPUConstants.TextureFormat.RG16Uint:
- case WebGPUConstants.TextureFormat.RG16Sint:
- case WebGPUConstants.TextureFormat.RG16Float:
- case WebGPUConstants.TextureFormat.RGBA8Unorm:
- case WebGPUConstants.TextureFormat.RGBA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGBA8Snorm:
- case WebGPUConstants.TextureFormat.RGBA8Uint:
- case WebGPUConstants.TextureFormat.RGBA8Sint:
- case WebGPUConstants.TextureFormat.BGRA8Unorm:
- case WebGPUConstants.TextureFormat.BGRA8UnormSRGB:
- case WebGPUConstants.TextureFormat.RGB9E5UFloat:
- case WebGPUConstants.TextureFormat.RGB10A2Unorm:
- case WebGPUConstants.TextureFormat.RG11B10UFloat:
- return { width: 1, height: 1, length: 4 };
- // 64 bits formats
- case WebGPUConstants.TextureFormat.RG32Uint:
- case WebGPUConstants.TextureFormat.RG32Sint:
- case WebGPUConstants.TextureFormat.RG32Float:
- case WebGPUConstants.TextureFormat.RGBA16Uint:
- case WebGPUConstants.TextureFormat.RGBA16Sint:
- case WebGPUConstants.TextureFormat.RGBA16Float:
- return { width: 1, height: 1, length: 8 };
- // 128 bits formats
- case WebGPUConstants.TextureFormat.RGBA32Uint:
- case WebGPUConstants.TextureFormat.RGBA32Sint:
- case WebGPUConstants.TextureFormat.RGBA32Float:
- return { width: 1, height: 1, length: 16 };
- // Depth and stencil formats
- case WebGPUConstants.TextureFormat.Stencil8:
- throw "No fixed size for Stencil8 format!";
- case WebGPUConstants.TextureFormat.Depth16Unorm:
- return { width: 1, height: 1, length: 2 };
- case WebGPUConstants.TextureFormat.Depth24Plus:
- throw "No fixed size for Depth24Plus format!";
- case WebGPUConstants.TextureFormat.Depth24PlusStencil8:
- throw "No fixed size for Depth24PlusStencil8 format!";
- case WebGPUConstants.TextureFormat.Depth32Float:
- return { width: 1, height: 1, length: 4 };
- case WebGPUConstants.TextureFormat.Depth24UnormStencil8:
- return { width: 1, height: 1, length: 4 };
- case WebGPUConstants.TextureFormat.Depth32FloatStencil8:
- return { width: 1, height: 1, length: 5 };
- // BC compressed formats usable if "texture-compression-bc" is both
- // supported by the device/user agent and enabled in requestDevice.
- case WebGPUConstants.TextureFormat.BC7RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC7RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC6HRGBUFloat:
- case WebGPUConstants.TextureFormat.BC6HRGBSFloat:
- case WebGPUConstants.TextureFormat.BC5RGUnorm:
- case WebGPUConstants.TextureFormat.BC5RGSnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC3RGBAUnormSRGB:
- case WebGPUConstants.TextureFormat.BC2RGBAUnorm:
- case WebGPUConstants.TextureFormat.BC2RGBAUnormSRGB:
- return { width: 4, height: 4, length: 16 };
- case WebGPUConstants.TextureFormat.BC4RUnorm:
- case WebGPUConstants.TextureFormat.BC4RSnorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUNorm:
- case WebGPUConstants.TextureFormat.BC1RGBAUnormSRGB:
- return { width: 4, height: 4, length: 8 };
- }
- return { width: 1, height: 1, length: 4 };
- }
- public updateCubeTextures(imageBitmaps: ImageBitmap[] | Uint8Array[], gpuTexture: GPUTexture, width: number, height: number, format: GPUTextureFormat, invertY = false, premultiplyAlpha = false, offsetX = 0, offsetY = 0,
- commandEncoder?: GPUCommandEncoder): void {
- const faces = [0, 3, 1, 4, 2, 5];
- for (let f = 0; f < faces.length; ++f) {
- let imageBitmap = imageBitmaps[faces[f]];
- this.updateTexture(imageBitmap, gpuTexture, width, height, format, f, 0, invertY, premultiplyAlpha, offsetX, offsetY, commandEncoder);
- }
- }
- public updateTexture(imageBitmap: ImageBitmap | Uint8Array, gpuTexture: GPUTexture, width: number, height: number, format: GPUTextureFormat, faceIndex: number = 0, mipLevel: number = 0, invertY = false, premultiplyAlpha = false, offsetX = 0, offsetY = 0,
- commandEncoder?: GPUCommandEncoder): void
- {
- const useOwnCommandEncoder = commandEncoder === undefined;
- if (useOwnCommandEncoder) {
- commandEncoder = this._device.createCommandEncoder({});
- }
- const blockInformation = this._getBlockInformationFromFormat(format);
- const textureCopyView: GPUTextureCopyView = {
- texture: gpuTexture,
- origin: {
- x: offsetX,
- y: offsetY,
- z: Math.max(faceIndex, 0)
- },
- mipLevel: mipLevel
- };
- const textureExtent = {
- width: Math.ceil(width / blockInformation.width) * blockInformation.width,
- height: Math.ceil(height / blockInformation.height) * blockInformation.height,
- depth: 1
- };
- if ((imageBitmap as Uint8Array).byteLength !== undefined) {
- // Note that we can't honor the invertY / premultiplyAlpha flags as we don't know the format of the array
- imageBitmap = imageBitmap as Uint8Array;
- const bytesPerRow = Math.ceil(width / blockInformation.width) * blockInformation.length;
- const aligned = Math.ceil(bytesPerRow / 256) * 256 === bytesPerRow;
- if (aligned) {
- const buffer = this._bufferManager.createRawBuffer(imageBitmap.byteLength, GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC, true);
- const arrayBuffer = buffer.getMappedRange();
- new Uint8Array(arrayBuffer).set(imageBitmap);
- buffer.unmap();
- commandEncoder!.copyBufferToTexture({
- buffer: buffer,
- offset: 0,
- bytesPerRow
- }, textureCopyView, textureExtent);
- if (useOwnCommandEncoder) {
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- commandEncoder = null as any;
- }
- this._bufferManager.releaseBuffer(buffer);
- } else {
- this._device.defaultQueue.writeTexture(textureCopyView, imageBitmap, {
- offset: 0,
- bytesPerRow
- }, textureExtent);
- }
- } else {
- imageBitmap = imageBitmap as ImageBitmap;
- if (invertY || premultiplyAlpha) {
- createImageBitmap(imageBitmap, { imageOrientation: invertY ? "flipY" : "none", premultiplyAlpha: premultiplyAlpha ? "premultiply" : "none" }).then((imageBitmap) => {
- this._device.defaultQueue.copyImageBitmapToTexture({ imageBitmap }, textureCopyView, textureExtent);
- });
- } else {
- this._device.defaultQueue.copyImageBitmapToTexture({ imageBitmap }, textureCopyView, textureExtent);
- }
- }
- }
- public readPixels(texture: GPUTexture, x: number, y: number, width: number, height: number, format: GPUTextureFormat, faceIndex: number = 0, mipLevel: number = 0, buffer: Nullable<ArrayBufferView> = null): Promise<ArrayBufferView> {
- const blockInformation = this._getBlockInformationFromFormat(format);
- const bytesPerRow = Math.ceil(width / blockInformation.width) * blockInformation.length;
- const size = bytesPerRow * height;
- const gpuBuffer = this._bufferManager.createRawBuffer(size, GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST);
- const commandEncoder = this._device.createCommandEncoder({});
- commandEncoder.copyTextureToBuffer({
- texture,
- mipLevel,
- origin: {
- x,
- y,
- z: Math.max(faceIndex, 0)
- }
- }, {
- buffer: gpuBuffer,
- offset: 0,
- bytesPerRow
- }, {
- width,
- height,
- depth: 1
- });
- this._device.defaultQueue.submit([commandEncoder!.finish()]);
- const type = this._getTextureTypeFromFormat(format);
- const floatFormat = type === Constants.TEXTURETYPE_FLOAT ? 2 : type === Constants.TEXTURETYPE_HALF_FLOAT ? 1 : 0;
- return this._bufferManager.readDataFromBuffer(gpuBuffer, size, width, height, floatFormat, 0, buffer);
- }
- }
|