import { ExtensionType } from '../../../extensions/Extensions.mjs';
import { Buffer } from '../shared/buffer/Buffer.mjs';
import { BufferResource } from '../shared/buffer/BufferResource.mjs';
import { BufferUsage } from '../shared/buffer/const.mjs';
import { UniformBufferBatch } from './buffer/UniformBufferBatch.mjs';
import { BindGroup } from './shader/BindGroup.mjs';

const minUniformOffsetAlignment = 128;
class GpuUniformBatchPipe {
  constructor(renderer) {
    this._bindGroupHash = /* @__PURE__ */ Object.create(null);
    // number of buffers..
    this._buffers = [];
    this._bindGroups = [];
    this._bufferResources = [];
    this._renderer = renderer;
    this._batchBuffer = new UniformBufferBatch({ minUniformOffsetAlignment });
    const totalBuffers = 256 / minUniformOffsetAlignment;
    for (let i = 0; i < totalBuffers; i++) {
      let usage = BufferUsage.UNIFORM | BufferUsage.COPY_DST;
      if (i === 0)
        usage |= BufferUsage.COPY_SRC;
      this._buffers.push(new Buffer({
        data: this._batchBuffer.data,
        usage
      }));
    }
  }
  renderEnd() {
    this._uploadBindGroups();
    this._resetBindGroups();
  }
  _resetBindGroups() {
    for (const i in this._bindGroupHash) {
      this._bindGroupHash[i] = null;
    }
    this._batchBuffer.clear();
  }
  // just works for single bind groups for now
  getUniformBindGroup(group, duplicate) {
    if (!duplicate && this._bindGroupHash[group.uid]) {
      return this._bindGroupHash[group.uid];
    }
    this._renderer.uniformBuffer.ensureUniformGroup(group);
    const data = group.buffer.data;
    const offset = this._batchBuffer.addEmptyGroup(data.length);
    this._renderer.uniformBuffer.syncUniformGroup(group, this._batchBuffer.data, offset / 4);
    this._bindGroupHash[group.uid] = this._getBindGroup(offset / minUniformOffsetAlignment);
    return this._bindGroupHash[group.uid];
  }
  getUniformBufferResource(group) {
    this._renderer.uniformBuffer.updateUniformGroup(group);
    const data = group.buffer.data;
    const offset = this._batchBuffer.addGroup(data);
    return this._getBufferResource(offset / minUniformOffsetAlignment);
  }
  getArrayBindGroup(data) {
    const offset = this._batchBuffer.addGroup(data);
    return this._getBindGroup(offset / minUniformOffsetAlignment);
  }
  getArrayBufferResource(data) {
    const offset = this._batchBuffer.addGroup(data);
    const index = offset / minUniformOffsetAlignment;
    return this._getBufferResource(index);
  }
  _getBufferResource(index) {
    if (!this._bufferResources[index]) {
      const buffer = this._buffers[index % 2];
      this._bufferResources[index] = new BufferResource({
        buffer,
        offset: (index / 2 | 0) * 256,
        size: minUniformOffsetAlignment
      });
    }
    return this._bufferResources[index];
  }
  _getBindGroup(index) {
    if (!this._bindGroups[index]) {
      const bindGroup = new BindGroup({
        0: this._getBufferResource(index)
      });
      this._bindGroups[index] = bindGroup;
    }
    return this._bindGroups[index];
  }
  _uploadBindGroups() {
    const bufferSystem = this._renderer.buffer;
    const firstBuffer = this._buffers[0];
    firstBuffer.update(this._batchBuffer.byteIndex);
    bufferSystem.updateBuffer(firstBuffer);
    const commandEncoder = this._renderer.gpu.device.createCommandEncoder();
    for (let i = 1; i < this._buffers.length; i++) {
      const buffer = this._buffers[i];
      commandEncoder.copyBufferToBuffer(
        bufferSystem.getGPUBuffer(firstBuffer),
        minUniformOffsetAlignment,
        bufferSystem.getGPUBuffer(buffer),
        0,
        this._batchBuffer.byteIndex
      );
    }
    this._renderer.gpu.device.queue.submit([commandEncoder.finish()]);
  }
  destroy() {
    for (let i = 0; i < this._bindGroups.length; i++) {
      this._bindGroups[i].destroy();
    }
    this._bindGroups = null;
    this._bindGroupHash = null;
    for (let i = 0; i < this._buffers.length; i++) {
      this._buffers[i].destroy();
    }
    this._buffers = null;
    for (let i = 0; i < this._bufferResources.length; i++) {
      this._bufferResources[i].destroy();
    }
    this._bufferResources = null;
    this._batchBuffer.destroy();
    this._bindGroupHash = null;
    this._renderer = null;
  }
}
/** @ignore */
GpuUniformBatchPipe.extension = {
  type: [
    ExtensionType.WebGPUPipes
  ],
  name: "uniformBatch"
};

export { GpuUniformBatchPipe };
//# sourceMappingURL=GpuUniformBatchPipe.mjs.map
