/// <reference types="@webgpu/types" />
import EventEmitter from 'eventemitter3';
import { type GlBuffer } from '../../gl/buffer/GlBuffer';
import { type GpuBufferData } from '../../gpu/buffer/GpuBufferSystem';
import { type GPUDataOwner } from '../../types';
import { type GCable, type GCData } from '../GCSystem';
import { BufferUsage } from './const';
import type { BindResource } from '../../gpu/shader/BindResource';
/**
 * All the various typed arrays that exist in js
 * @category rendering
 * @advanced
 */
export type TypedArray = Int8Array | Uint8Array | Int16Array | Uint16Array | Int32Array | Uint32Array | Uint8ClampedArray | Float32Array | Float64Array;
/**
 * Options for creating a buffer
 *
 * This interface defines the options that can be passed to the Buffer constructor.
 * It includes the data to initialize the buffer with, the size of the buffer,
 * the usage of the buffer, a label for debugging, and whether the buffer should shrink to fit
 * when the data becomes smaller.
 * @category rendering
 * @advanced
 */
export interface BufferOptions {
    /**
     * the data to initialize the buffer with, this can be a typed array,
     * or a regular number array. If it is a number array, it will be converted to a Float32Array
     */
    data?: TypedArray | number[];
    /** the size of the buffer in bytes, if not supplied, it will be inferred from the data */
    size?: number;
    /** the usage of the buffer, see {@link BufferUsage} */
    usage: number;
    /** a label for the buffer, this is useful for debugging */
    label?: string;
    /**
     * should the GPU buffer be shrunk when the data becomes smaller?
     * changing this will cause the buffer to be destroyed and a new one created on the GPU
     * this can be expensive, especially if the buffer is already big enough!
     * setting this to false will prevent the buffer from being shrunk. This will yield better performance
     * if you are constantly setting data that is changing size often.
     * @default true
     */
    shrinkToFit?: boolean;
}
/** @internal */
export interface BufferDescriptor {
    label?: string;
    size: GPUSize64;
    usage: BufferUsage;
    mappedAtCreation?: boolean;
}
/**
 * A wrapper for a WebGPU/WebGL Buffer.
 * In PixiJS, the Buffer class is used to manage the data that is sent to the GPU rendering pipeline.
 * It abstracts away the underlying GPU buffer and provides an interface for uploading typed arrays or other data to the GPU,
 * They are used in the following places:
 * <br><br>
 * .1. {@link Geometry} as attribute data or index data for geometry
 * <br>
 * .2. {@link UniformGroup} as an underlying buffer for uniform data
 * <br>
 * .3. {@link BufferResource} as an underlying part of a buffer used directly by the GPU program
 * <br>
 *
 * It is important to note that you must provide a usage type when creating a buffer. This is because
 * the underlying GPU buffer needs to know how it will be used. For example, if you are creating a buffer
 * to hold vertex data, you would use `BufferUsage.VERTEX`. This will tell the GPU that this buffer will be
 * used as a vertex buffer. This is important because it will affect how you can use the buffer.
 *
 * Buffers are updated by calling the {@link Buffer.update} method. This immediately updates the buffer on the GPU.
 * Be mindful of calling this more often than you need to. It is recommended to update buffers only when needed.
 *
 * In WebGPU, a GPU buffer cannot resized. This limitation is abstracted away, but know that resizing a buffer means
 * creating a brand new one and destroying the old, so it is best to limit this if possible.
 * @example
 *
 * const buffer = new Buffer({
 *     data: new Float32Array([1, 2, 3, 4]),
 *     usage: BufferUsage.VERTEX,
 * });
 * @category rendering
 * @advanced
 */
export declare class Buffer extends EventEmitter<{
    change: BindResource;
    update: Buffer;
    destroy: Buffer;
    unload: Buffer;
}> implements BindResource, GPUDataOwner, GCable {
    /**
     * emits when the underlying buffer has changed shape (i.e. resized)
     * letting the renderer know that it needs to discard the old buffer on the GPU and create a new one
     * @event change
     */
    /**
     * emits when the underlying buffer data has been updated. letting the renderer know
     * that it needs to update the buffer on the GPU
     * @event update
     */
    /**
     * emits when the buffer is destroyed. letting the renderer know that it needs to destroy the buffer on the GPU
     * @event destroy
     */
    /** @internal */
    _gpuData: Record<number, GlBuffer | GpuBufferData>;
    /** @internal */
    _gcData?: GCData;
    /** @internal */
    _gcLastUsed: number;
    /** If set to true, the buffer will be garbage collected automatically when it is not used. */
    autoGarbageCollect: boolean;
    /** a unique id for this uniform group used through the renderer */
    readonly uid: number;
    /**
     * a resource type, used to identify how to handle it when its in a bind group / shader resource
     * @internal
     */
    readonly _resourceType = "buffer";
    /**
     * the resource id used internally by the renderer to build bind group keys
     * @internal
     */
    _resourceId: number;
    /**
     * used internally to know if a uniform group was used in the last render pass
     * @internal
     */
    _touched: number;
    /**
     * a description of the buffer and how it should be set up on the GPU
     * @internal
     */
    readonly descriptor: BufferDescriptor;
    /** @internal */
    _updateID: number;
    /** @internal */
    _updateSize: number;
    private _data;
    private _dataInt32;
    /**
     * should the GPU buffer be shrunk when the data becomes smaller?
     * changing this will cause the buffer to be destroyed and a new one created on the GPU
     * this can be expensive, especially if the buffer is already big enough!
     * setting this to false will prevent the buffer from being shrunk. This will yield better performance
     * if you are constantly setting data that is changing size often.
     * @default true
     */
    shrinkToFit: boolean;
    /**
     * Has the buffer been destroyed?
     * @readonly
     */
    destroyed: boolean;
    /**
     * Creates a new Buffer with the given options
     * @param options - the options for the buffer
     */
    constructor(options: BufferOptions);
    /** the data in the buffer */
    get data(): TypedArray;
    set data(value: TypedArray);
    get dataInt32(): Int32Array;
    /** whether the buffer is static or not */
    get static(): boolean;
    set static(value: boolean);
    /**
     * Sets the data in the buffer to the given value. This will immediately update the buffer on the GPU.
     * If you only want to update a subset of the buffer, you can pass in the size of the data.
     * @param value - the data to set
     * @param size - the size of the data in bytes
     * @param syncGPU - should the buffer be updated on the GPU immediately?
     */
    setDataWithSize(value: TypedArray, size: number, syncGPU: boolean): void;
    /**
     * updates the buffer on the GPU to reflect the data in the buffer.
     * By default it will update the entire buffer. If you only want to update a subset of the buffer,
     * you can pass in the size of the buffer to update.
     * @param sizeInBytes - the new size of the buffer in bytes
     */
    update(sizeInBytes?: number): void;
    /** Unloads the buffer from the GPU */
    unload(): void;
    /** Destroys the buffer */
    destroy(): void;
}
