wip webgpu interfaces
This commit is contained in:
parent
5e6b9c8fb1
commit
9a54bb90c9
13 changed files with 235 additions and 118 deletions
|
@ -2,7 +2,7 @@ import { LoadOp, StoreOp } from '../enum.js'
|
|||
import { CommandRecorderError } from '../utils/errors.js'
|
||||
import { SwapChain } from './swap-chain.js'
|
||||
|
||||
export class CommandRecorder {
|
||||
export class CommandEncoder implements GPUCommandEncoder {
|
||||
static _defaultClearValue = { r: 0, g: 0, b: 0, a: 1 }
|
||||
|
||||
_device: GPUDevice
|
||||
|
@ -29,24 +29,24 @@ export class CommandRecorder {
|
|||
|
||||
return [{
|
||||
view,
|
||||
clearValue: CommandRecorder._defaultClearValue,
|
||||
clearValue: CommandEncoder._defaultClearValue,
|
||||
loadOp: LoadOp.Clear,
|
||||
storeOp: StoreOp.Store
|
||||
}]
|
||||
}
|
||||
|
||||
beginRenderPass(colorAttachments?: GPURenderPassColorAttachment[], depthStencilAttachment?: GPURenderPassDepthStencilAttachment): GPURenderPassEncoder {
|
||||
beginRenderPass(descriptor: GPURenderPassDescriptor): GPURenderPassEncoder {
|
||||
if (this._passEncoder) {
|
||||
throw CommandRecorderError.activeRenderPass()
|
||||
}
|
||||
|
||||
const attachments = colorAttachments || this._defaultColorAttachment()
|
||||
|
||||
const descriptor = {
|
||||
label: this.label || 'RenderPass',
|
||||
colorAttachments: attachments,
|
||||
depthStencilAttachment
|
||||
}
|
||||
//const descriptor = {
|
||||
// label: this.label || 'RenderPass',
|
||||
// colorAttachments: attachments,
|
||||
// depthStencilAttachment
|
||||
//}
|
||||
|
||||
this._passEncoder = this._encoder.beginRenderPass(descriptor)
|
||||
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
import { SwapChain } from './swap-chain.js'
|
||||
import { Buffer, UniformBuffer } from '../resources/buffer.js'
|
||||
import { GraphicsDeviceError, WebGPUError, BufferError, WebGPUObjectError } from '../utils/errors.js'
|
||||
import { GraphicsDeviceInitialized, GraphicsDeviceLost } from '../utils/events.js'
|
||||
import { EventEmitter } from '../utils/index.js'
|
||||
import { EventEmitter, GraphicsDeviceInitialized, GraphicsDeviceLost } from '../utils/events.js'
|
||||
import { ShaderModule, ShaderPairDescriptor } from '../resources/shader-module.js'
|
||||
import { RenderPipeline } from '../rendering/render-pipeline.js'
|
||||
import { CommandRecorder } from './command-recorder.js'
|
||||
import { CommandEncoder } from './command-recorder.js'
|
||||
import { BindGroupLayout } from '../resources/bind-group-layout.js'
|
||||
import { BindGroup } from '../resources/bind-group.js'
|
||||
import { Texture } from '../resources/texture.js'
|
||||
|
@ -125,7 +124,9 @@ class DeviceHandler {
|
|||
}
|
||||
}
|
||||
|
||||
export class GraphicsDevice extends EventEmitter {
|
||||
export class GraphicsDevice extends EventEmitter implements GPUDevice {
|
||||
__brand: 'GPUDevice'
|
||||
|
||||
_canvas: HTMLCanvasElement
|
||||
_deviceHandler: DeviceHandler
|
||||
_swapChain: SwapChain
|
||||
|
@ -153,6 +154,34 @@ export class GraphicsDevice extends EventEmitter {
|
|||
return this._swapChain
|
||||
}
|
||||
|
||||
get features() {
|
||||
return this.device.features
|
||||
}
|
||||
|
||||
get limits() {
|
||||
return this.device.limits
|
||||
}
|
||||
|
||||
get adapterInfo() {
|
||||
return this.device.adapterInfo
|
||||
}
|
||||
|
||||
get lost() {
|
||||
return this.device.lost
|
||||
}
|
||||
|
||||
get onuncapturederror() {
|
||||
return this.device.onuncapturederror
|
||||
}
|
||||
|
||||
set onuncapturederror(value) {
|
||||
this.device.onuncapturederror = value
|
||||
}
|
||||
|
||||
get label() {
|
||||
return this.device.label
|
||||
}
|
||||
|
||||
constructor(canvas: HTMLCanvasElement, deviceHandler: DeviceHandler) {
|
||||
super()
|
||||
|
||||
|
@ -160,6 +189,34 @@ export class GraphicsDevice extends EventEmitter {
|
|||
this._deviceHandler = deviceHandler
|
||||
}
|
||||
|
||||
importExternalTexture(descriptor: GPUExternalTextureDescriptor): GPUExternalTexture {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createComputePipeline(descriptor: GPUComputePipelineDescriptor): GPUComputePipeline {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createComputePipelineAsync(descriptor: GPUComputePipelineDescriptor): Promise<GPUComputePipeline> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createRenderPipelineAsync(descriptor: GPURenderPipelineDescriptor): Promise<GPURenderPipeline> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createCommandEncoder(descriptor?: GPUCommandEncoderDescriptor): GPUCommandEncoder {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createRenderBundleEncoder(descriptor: GPURenderBundleEncoderDescriptor): GPURenderBundleEncoder {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
createQuerySet(descriptor: GPUQuerySetDescriptor): GPUQuerySet {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
pushErrorScope(filter: GPUErrorFilter): undefined {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
popErrorScope(): Promise<GPUError | null> {
|
||||
throw new Error('Method not implemented.')
|
||||
}
|
||||
|
||||
static build(canvas?: HTMLCanvasElement) {
|
||||
return new GraphicsDeviceBuilder(canvas)
|
||||
}
|
||||
|
@ -226,11 +283,11 @@ export class GraphicsDevice extends EventEmitter {
|
|||
return buffer
|
||||
}
|
||||
|
||||
createShaderModule(code: string, label: string): ShaderModule {
|
||||
createShaderModule(descriptor: GPUShaderModuleDescriptor): ShaderModule {
|
||||
if (!this._isInitialized) { throw GraphicsDeviceError.uninitialized() }
|
||||
|
||||
try {
|
||||
return ShaderModule.create(this.device, { code, label })
|
||||
return ShaderModule.create(this.device, descriptor)
|
||||
} catch (err) {
|
||||
throw WebGPUObjectError.from(err, ShaderModule)
|
||||
}
|
||||
|
@ -257,19 +314,16 @@ export class GraphicsDevice extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
createCommandRecorder(label?: string): CommandRecorder {
|
||||
createCommandRecorder(label?: string): CommandEncoder {
|
||||
if (!this._isInitialized) { throw GraphicsDeviceError.uninitialized() }
|
||||
|
||||
return new CommandRecorder(this.device, this._swapChain, label)
|
||||
return new CommandEncoder(this.device, this._swapChain, label)
|
||||
}
|
||||
|
||||
createBindGroupLayout(entries: GPUBindGroupLayoutEntry[], label: string) {
|
||||
createBindGroupLayout(descriptor: GPUBindGroupLayoutDescriptor) {
|
||||
if (!this._isInitialized) { throw GraphicsDeviceError.uninitialized() }
|
||||
|
||||
return BindGroupLayout.create(this.device, {
|
||||
label,
|
||||
entries
|
||||
})
|
||||
return BindGroupLayout.create(this.device, descriptor)
|
||||
}
|
||||
|
||||
_getBindingResource(binding: BindGroupEntry): GPUBindingResource {
|
||||
|
@ -303,31 +357,24 @@ export class GraphicsDevice extends EventEmitter {
|
|||
}
|
||||
}
|
||||
|
||||
createBindGroup(layout: BindGroupLayout, bindings: BindGroupEntry[], label?: string) {
|
||||
createBindGroup(descriptor: GPUBindGroupDescriptor) {
|
||||
if (!this._isInitialized) { throw GraphicsDeviceError.uninitialized() }
|
||||
|
||||
|
||||
const entries = bindings.map(def => ({
|
||||
binding: def.binding,
|
||||
resource: this._getBindingResource(def)
|
||||
}))
|
||||
//const entries = bindings.map(def => ({
|
||||
// binding: def.binding,
|
||||
// resource: this._getBindingResource(def)
|
||||
//}))
|
||||
|
||||
return BindGroup.create(this.device, {
|
||||
layout: layout.handle,
|
||||
entries,
|
||||
label
|
||||
})
|
||||
return BindGroup.create(this.device, descriptor)
|
||||
}
|
||||
|
||||
createPipelineLayout(layouts: Array<BindGroupLayout>, label?: string) {
|
||||
createPipelineLayout(descriptor: GPUPipelineLayoutDescriptor) {
|
||||
if (!this._isInitialized) { throw GraphicsDeviceError.uninitialized() }
|
||||
|
||||
const bindGroupLayouts = layouts.map(layout => layout.handle)
|
||||
//const bindGroupLayouts = layouts.map(layout => layout.handle)
|
||||
|
||||
return this.device.createPipelineLayout({
|
||||
label,
|
||||
bindGroupLayouts
|
||||
})
|
||||
return this.device.createPipelineLayout(descriptor)
|
||||
}
|
||||
|
||||
createSampler(descriptor?: GPUSamplerDescriptor) {
|
||||
|
@ -389,10 +436,7 @@ export class GraphicsDevice extends EventEmitter {
|
|||
this.queue.submit(commandBuffers)
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleans up GPU resources. Call when the application exits.
|
||||
*/
|
||||
destroy() {
|
||||
destroy(): undefined {
|
||||
if (this.device) {
|
||||
this.device.destroy()
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
export class RenderPipeline {
|
||||
export class RenderPipeline implements GPURenderPipeline {
|
||||
__brand: 'GPURenderPipeline'
|
||||
|
||||
_handle: GPURenderPipeline
|
||||
_label: string
|
||||
|
||||
|
@ -14,5 +16,9 @@ export class RenderPipeline {
|
|||
this._handle = pipeline
|
||||
this._label = label
|
||||
}
|
||||
|
||||
getBindGroupLayout(index: number): GPUBindGroupLayout {
|
||||
return this.getBindGroupLayout(index)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { WebGPUObjectError } from '../utils/errors.js'
|
||||
|
||||
export class BindGroupLayout {
|
||||
export class BindGroupLayout implements GPUBindGroupLayout {
|
||||
__brand: 'GPUBindGroupLayout'
|
||||
|
||||
_device: GPUDevice
|
||||
_handle: GPUBindGroupLayout
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
import { WebGPUObjectError } from '../utils/errors.js'
|
||||
|
||||
export class BindGroup {
|
||||
export class BindGroup implements GPUBindGroup {
|
||||
__brand: 'GPUBindGroup'
|
||||
|
||||
_device: GPUDevice
|
||||
_handle: GPUBindGroup
|
||||
|
||||
|
@ -8,6 +10,10 @@ export class BindGroup {
|
|||
return this._handle
|
||||
}
|
||||
|
||||
get label() {
|
||||
return this._handle.label
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GPUDevice} device
|
||||
* @param {GPUBindGroup} bindGroup
|
||||
|
|
|
@ -5,7 +5,9 @@ import { ResourceType } from '../utils/internal-enums.js'
|
|||
type SmallTypedArray = Exclude<TypedArray, BigInt64Array | BigUint64Array>
|
||||
type SmallTypedArrayConstructor = Exclude<TypedArrayConstructor, BigInt64ArrayConstructor | BigUint64ArrayConstructor>
|
||||
|
||||
export class Buffer {
|
||||
export class Buffer implements GPUBuffer {
|
||||
__brand: 'GPUBuffer'
|
||||
|
||||
_device: GPUDevice
|
||||
_handle: GPUBuffer
|
||||
|
||||
|
@ -25,6 +27,14 @@ export class Buffer {
|
|||
return this._handle.usage
|
||||
}
|
||||
|
||||
get mapState() {
|
||||
return this._handle.mapState
|
||||
}
|
||||
|
||||
get label() {
|
||||
return this._handle.label
|
||||
}
|
||||
|
||||
get resourceType() {
|
||||
return ResourceType.Buffer
|
||||
}
|
||||
|
@ -33,7 +43,6 @@ export class Buffer {
|
|||
this._device = device
|
||||
this._handle = texture
|
||||
}
|
||||
|
||||
static create(device: GPUDevice, descriptor: GPUBufferDescriptor) {
|
||||
try {
|
||||
return new Buffer(
|
||||
|
@ -153,7 +162,20 @@ export class Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
destroy() {
|
||||
mapAsync(mode: GPUMapModeFlags, offset?: GPUSize64, size?: GPUSize64): Promise<undefined> {
|
||||
return this._handle.mapAsync(mode, offset, size)
|
||||
}
|
||||
|
||||
getMappedRange(offset?: GPUSize64, size?: GPUSize64): ArrayBuffer {
|
||||
return this._handle.getMappedRange(offset, size)
|
||||
}
|
||||
|
||||
unmap(): undefined {
|
||||
this._handle.unmap()
|
||||
}
|
||||
|
||||
|
||||
destroy(): undefined {
|
||||
this._handle?.destroy()
|
||||
this._handle = null
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { WebGPUObjectError } from '../utils/errors.js'
|
||||
import { ResourceType } from '../utils/internal-enums.js'
|
||||
|
||||
/** @import { BindGroupEntry } from '../core/graphics-device.js' */
|
||||
export class Sampler implements GPUSampler {
|
||||
__brand: 'GPUSampler'
|
||||
|
||||
export class Sampler {
|
||||
_device: GPUDevice
|
||||
_handle: GPUSampler
|
||||
|
||||
|
|
|
@ -13,9 +13,8 @@ import {
|
|||
} from '../utils/wgsl-to-wgpu.js'
|
||||
import { BufferBindingType } from '../enum.js'
|
||||
|
||||
/** @import { WGSLAccess, WGSLSamplerType } from '../utils/wgsl-to-wgpu.js' */
|
||||
|
||||
export class ShaderModule {
|
||||
export class ShaderModule implements GPUShaderModule {
|
||||
__brand: 'GPUShaderModule'
|
||||
_handle: GPUShaderModule
|
||||
_code: string
|
||||
|
||||
|
@ -44,14 +43,17 @@ export class ShaderModule {
|
|||
}
|
||||
|
||||
reflect() {
|
||||
if (this._reflection == null) {
|
||||
if (!this._reflection) {
|
||||
this._reflection = new WgslReflect(this._code)
|
||||
// no longer needed allow the GC to collect it
|
||||
this._code = undefined
|
||||
}
|
||||
|
||||
return this._reflection
|
||||
}
|
||||
|
||||
getCompilationInfo(): Promise<GPUCompilationInfo> {
|
||||
return this._handle.getCompilationInfo()
|
||||
}
|
||||
}
|
||||
|
||||
export interface FragmentStateDescriptor {
|
||||
|
@ -83,7 +85,7 @@ export class ReflectedShader {
|
|||
}
|
||||
|
||||
|
||||
constructor(shader: ShaderModule) {
|
||||
constructor(shader: ShaderModule, reflection: WgslReflect) {
|
||||
this._module = shader
|
||||
}
|
||||
|
||||
|
|
|
@ -3,18 +3,19 @@ import { WebGPUObjectError } from '../utils/errors.js'
|
|||
import { ResourceType } from '../utils/internal-enums.js'
|
||||
import { textureToImageDimension } from '../utils/wgsl-to-wgpu.js'
|
||||
|
||||
/** @import { BindGroupEntry } from '../core/graphics-device.js' */
|
||||
interface UploadTextureInfo {
|
||||
destination: GPUTexelCopyTextureInfo
|
||||
dataLayout: GPUTexelCopyBufferLayout
|
||||
size: GPUExtent3DStrict
|
||||
}
|
||||
|
||||
export class Texture {
|
||||
export class Texture implements GPUTexture {
|
||||
static _defaultUsage = GPUTextureUsage.TEXTURE_BINDING
|
||||
| GPUTextureUsage.COPY_DST
|
||||
| GPUTextureUsage.RENDER_ATTACHMENT
|
||||
|
||||
__brand: 'GPUTexture'
|
||||
|
||||
_device: GPUDevice
|
||||
_handle: GPUTexture
|
||||
|
||||
|
@ -48,6 +49,10 @@ export class Texture {
|
|||
return this._handle.dimension
|
||||
}
|
||||
|
||||
get sampleCount() {
|
||||
return this._handle.sampleCount
|
||||
}
|
||||
|
||||
get mipLevelCount() {
|
||||
return this._handle.mipLevelCount
|
||||
}
|
||||
|
@ -81,7 +86,6 @@ export class Texture {
|
|||
return 1 + Math.log2(max) | 0
|
||||
}
|
||||
|
||||
|
||||
static async fromUrl(device: GPUDevice, url: string | URL, descriptor: GPUTextureDescriptor) {
|
||||
try {
|
||||
const response = await fetch(url)
|
||||
|
@ -127,7 +131,6 @@ export class Texture {
|
|||
})
|
||||
}
|
||||
|
||||
|
||||
upload(source: GPUAllowSharedBufferSource, options?: UploadTextureInfo) {
|
||||
const mipLevel = options.destination.mipLevel || 0
|
||||
const size = options.size || [
|
||||
|
@ -148,8 +151,8 @@ export class Texture {
|
|||
}
|
||||
}
|
||||
|
||||
generateMipmaps(_commandEncoder: GPUCommandEncoder) {
|
||||
// TODO: use MipGenerator
|
||||
createView(descriptor?: GPUTextureViewDescriptor) {
|
||||
return this._handle.createView(descriptor)
|
||||
}
|
||||
|
||||
createDefaultView(descriptor?: GPUTextureViewDescriptor) {
|
||||
|
@ -178,7 +181,7 @@ export class Texture {
|
|||
return this.getView()
|
||||
}
|
||||
|
||||
destroy() {
|
||||
destroy(): undefined {
|
||||
this._handle?.destroy()
|
||||
this._handle = undefined
|
||||
this._defaultView = undefined
|
||||
|
|
|
@ -1,5 +1,54 @@
|
|||
import { GraphicsDevice } from '../core/graphics-device.js'
|
||||
|
||||
interface Listener {
|
||||
(...args: any): void
|
||||
}
|
||||
|
||||
export class EventEmitter {
|
||||
_listeners = {}
|
||||
|
||||
addEventListener(type: PropertyKey, listener: Listener, options?: object): void {
|
||||
this.on(type, listener, options)
|
||||
}
|
||||
|
||||
removeEventListener(type: PropertyKey, listener: Listener, options?: object): void {
|
||||
this.off(type, listener, options)
|
||||
}
|
||||
|
||||
dispatchEvent(event: Event): boolean {
|
||||
const details = 'detail' in event ? event.detail : undefined
|
||||
return this.emit(event.type, ...Object.values(details))
|
||||
}
|
||||
|
||||
on(event: PropertyKey, callback: Listener, _options?: object) {
|
||||
this._listeners[event] = this._listeners[event] || []
|
||||
this._listeners[event].push(callback)
|
||||
}
|
||||
|
||||
emit(event: PropertyKey, ...args: any[]) {
|
||||
const listeners = this._listeners[event]
|
||||
|
||||
if (listeners) {
|
||||
listeners.forEach(
|
||||
(cb: Listener) => cb(...args)
|
||||
)
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
off(event: PropertyKey, callback: Listener, _options?: object) {
|
||||
const listeners = this._listeners[event]
|
||||
|
||||
if (listeners) {
|
||||
this._listeners[event] = listeners.filter(
|
||||
(cb: Listener) => cb !== callback
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class GraphicsDeviceInitialized {
|
||||
static EventName = 'graphics-device:initialized'
|
||||
graphicsDevice: GraphicsDevice
|
||||
|
|
|
@ -88,38 +88,6 @@ export const FlagEnum = <const T extends string, const A extends T[]>(...values:
|
|||
) as FlagEnum<T, A>
|
||||
|
||||
|
||||
interface Listener {
|
||||
(...args: any): void
|
||||
}
|
||||
export class EventEmitter {
|
||||
_listeners = {}
|
||||
|
||||
on(event: PropertyKey, callback: Listener) {
|
||||
this._listeners[event] = this._listeners[event] || []
|
||||
this._listeners[event].push(callback)
|
||||
}
|
||||
|
||||
emit(event: PropertyKey, ...args: any[]) {
|
||||
const listeners = this._listeners[event]
|
||||
|
||||
if (listeners) {
|
||||
listeners.forEach(
|
||||
(cb: Listener) => cb(...args)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
off(event: PropertyKey, callback: Listener) {
|
||||
const listeners = this._listeners[event]
|
||||
|
||||
if (listeners) {
|
||||
this._listeners[event] = listeners.filter(
|
||||
(cb: Listener) => cb !== callback
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const pick = <T extends object, K extends keyof T>(obj: T, ...keys: K[]): Pick<T, K> => (Object.fromEntries(
|
||||
keys
|
||||
.filter(key => key in obj)
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// taken from PixiJS
|
||||
// https://pixijs.download/v8.0.0-rc.2/docs/rendering_renderers_gpu_texture_utils_GpuMipmapGenerator.ts.html
|
||||
|
||||
import code from './mip-shader.wgsl'
|
||||
|
||||
const mip = (n: number) => Math.max(1, n >>> 1)
|
||||
|
@ -81,33 +84,37 @@ export class MipGenerator {
|
|||
return pipeline
|
||||
}
|
||||
|
||||
generateMipmap(texture: GPUTexture, descriptor: GPUTextureDescriptor) {
|
||||
const pipeline = this.getPipeline(descriptor.format)
|
||||
generateMipmap(texture: GPUTexture, commandEncoder?: GPUCommandEncoder): GPUTexture {
|
||||
const pipeline = this.getPipeline(texture.format)
|
||||
|
||||
if (descriptor.dimension !== '2d') {
|
||||
const { dimension, format, mipLevelCount, width, height, depthOrArrayLayers } = texture
|
||||
|
||||
const encoder = commandEncoder || this._device.createCommandEncoder()
|
||||
|
||||
if (texture.dimension !== '2d') {
|
||||
throw new Error('Generating mipmaps for anything except 2d is unsupported.')
|
||||
}
|
||||
|
||||
let mipTexture = texture
|
||||
const { width, height, depthOrArrayLayers } = descriptor.size as GPUExtent3DDict
|
||||
let tempTexture = texture
|
||||
|
||||
const renderToSource = descriptor.usage & GPUTextureUsage.RENDER_ATTACHMENT
|
||||
|
||||
const renderToSource = texture.usage & GPUTextureUsage.RENDER_ATTACHMENT
|
||||
|
||||
if (!renderToSource) {
|
||||
mipTexture = this._device.createTexture({
|
||||
tempTexture = this._device.createTexture({
|
||||
size: {
|
||||
width: mip(width),
|
||||
height: mip(height),
|
||||
depthOrArrayLayers
|
||||
},
|
||||
format: descriptor.format,
|
||||
format,
|
||||
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT,
|
||||
mipLevelCount: descriptor.mipLevelCount - 1
|
||||
mipLevelCount: mipLevelCount - 1,
|
||||
dimension,
|
||||
sampleCount: 1
|
||||
})
|
||||
}
|
||||
|
||||
const encoder = this._device.createCommandEncoder({})
|
||||
|
||||
for (let layer = 0; layer < depthOrArrayLayers; ++layer) {
|
||||
let srcView = texture.createView({
|
||||
baseMipLevel: 0,
|
||||
|
@ -117,10 +124,9 @@ export class MipGenerator {
|
|||
arrayLayerCount: 1
|
||||
})
|
||||
|
||||
let dstMipLevel = renderToSource ? 1 : 0
|
||||
for (let i = 1; i < descriptor.mipLevelCount; ++i) {
|
||||
const dstView = mipTexture.createView({
|
||||
baseMipLevel: dstMipLevel++,
|
||||
for (let i = 1; i < mipLevelCount; ++i) {
|
||||
const dstView = tempTexture.createView({
|
||||
baseMipLevel: i - (renderToSource ? 0 : 1),
|
||||
mipLevelCount: 1,
|
||||
dimension: '2d',
|
||||
baseArrayLayer: layer,
|
||||
|
@ -156,33 +162,42 @@ export class MipGenerator {
|
|||
}
|
||||
|
||||
if (!renderToSource) {
|
||||
const mipLevelSize = {
|
||||
const mipSize = {
|
||||
width: mip(width),
|
||||
height: mip(height),
|
||||
depthOrArrayLayers
|
||||
}
|
||||
|
||||
for (let i = 1; i < descriptor.mipLevelCount; ++i) {
|
||||
for (let i = 1; i < texture.mipLevelCount; ++i) {
|
||||
encoder.copyTextureToTexture({
|
||||
texture: mipTexture,
|
||||
texture: tempTexture,
|
||||
mipLevel: i - 1
|
||||
}, {
|
||||
texture,
|
||||
mipLevel: i,
|
||||
}, mipLevelSize)
|
||||
}, mipSize)
|
||||
|
||||
mipLevelSize.width = mip(mipLevelSize.width)
|
||||
mipLevelSize.height = mip(mipLevelSize.height)
|
||||
mipSize.width = mip(mipSize.width)
|
||||
mipSize.height = mip(mipSize.height)
|
||||
}
|
||||
}
|
||||
|
||||
this._device.queue.submit([encoder.finish()])
|
||||
|
||||
if (!renderToSource) {
|
||||
mipTexture.destroy()
|
||||
tempTexture.destroy()
|
||||
}
|
||||
|
||||
return texture
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this._device = undefined
|
||||
this._sampler = undefined
|
||||
this._shader = undefined
|
||||
this._pipelines = undefined
|
||||
this._bindGroupLayout = undefined
|
||||
this._pipelineLayout = undefined
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ struct VertexOutput {
|
|||
};
|
||||
|
||||
@vertex
|
||||
fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
|
||||
fn vs_main(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
|
||||
var output : VertexOutput;
|
||||
output.texCoord = pos[vertexIndex] * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
|
||||
output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
|
||||
|
@ -18,6 +18,6 @@ fn vertexMain(@builtin(vertex_index) vertexIndex : u32) -> VertexOutput {
|
|||
@group(0) @binding(1) var img : texture_2d<f32>;
|
||||
|
||||
@fragment
|
||||
fn fragmentMain(@location(0) texCoord : vec2<f32>) -> @location(0) vec4<f32> {
|
||||
fn fs_main(@location(0) texCoord : vec2<f32>) -> @location(0) vec4<f32> {
|
||||
return textureSample(img, imgSampler, texCoord);
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue