// sharedimage.js — SharedImage creation over the GpuChannel for the MojoJS
// port. Loaded after raster.js. Uses the DeferredSharedImageRequest path
// (route 0 = kSharedImageInterface) and hands back a SyncToken so the raster
// command-buffer can fence BeginRaster on it — SharedImageStub and the CB
// stub run on different scheduler sequences (gpu_channel.cc:382-397).
'use strict';

// gpu/command_buffer/common/shared_image_usage.h
const SI_USAGE_DISPLAY_READ = 1 << 2;
const SI_USAGE_RASTER_WRITE = 1 << 18;

// gpu/command_buffer/common/raster_cmd_enums.h:13
const MsaaMode = Object.freeze({ kNoMSAA: 0, kMSAA: 1, kDMSAA: 2 });

// gpu/command_buffer/common/constants.h:81
const CB_NS_GPU_IO = 0;

// ─── Mailbox ────────────────────────────────────────────────────────────────
// 16 random bytes; name[15] |= kLiveMailboxFlag(1). In !NDEBUG builds
// Mailbox::Verify XORs all bytes with seed 1 and expects 0; cheap to satisfy
// either way. Returned as Int8Array since gpu.mojom.Mailbox.name is int8[16].
function genMailbox() {
  const u = new Uint8Array(16);
  crypto.getRandomValues(u);
  u[15] |= 1;
  let x = 1; for (let i = 1; i < 16; ++i) x ^= u[i]; u[0] = x;
  return new Int8Array(u.buffer);
}
// BeginRasterCHROMIUMImmediate's trailing immediate is the raw 16 bytes.
function mailboxBytes(mb /* Int8Array[16] */) {
  return new Uint8Array(mb.buffer, mb.byteOffset, 16);
}

// ─── gfx::ColorSpace::CreateSRGB() ─────────────────────────────────────────
// ui/gfx/color_space.h:187 → {BT709, SRGB, RGB, FULL}. customPrimaryMatrix /
// transferParams are fixed-size non-nullable arrays, zero-filled when unused.
function colorSpaceSRGB() {
  return new gfx.mojom.ColorSpace({
    primaries: gfx.mojom.ColorSpacePrimaryID.BT709,
    transfer:  gfx.mojom.ColorSpaceTransferID.SRGB,
    matrix:    gfx.mojom.ColorSpaceMatrixID.RGB,
    range:     gfx.mojom.ColorSpaceRangeID.FULL,
    customPrimaryMatrix: new Array(9).fill(0),
    transferParams:      new Array(7).fill(0),
  });
}

// ─── SharedImageInterface façade ───────────────────────────────────────────
// One per channel. Mirrors SharedImageInterfaceProxy: each create bumps the
// SII release counter; the GPU side releases that count on the SII sequence
// (gpu_channel.cc:390 builds the SyncToken from the DeferredRequest's
// release_count). The returned token goes into AsyncFlushParams.syncTokenFences
// so the raster CB's scheduler sequence orders BeginRaster after the create.
class SII {
  constructor(chan, clientId) {
    this.chan = chan;
    // CommandBufferIdFromChannelAndRoute(client_id, kSharedImageInterface=0)
    // = (client_id << 32) | 0. client_id is small → exact as a JS number.
    this.cbId = clientId * 0x100000000;
    this.release = 0;
  }
  _token() {
    return new gpu.mojom.SyncToken({
      verifiedFlush: true,
      namespaceId:   CB_NS_GPU_IO,
      commandBufferId: this.cbId,
      releaseCount:  this.release,
    });
  }
  _send(siReq) {
    const req = new gpu.mojom.DeferredRequest({
      params: new gpu.mojom.DeferredRequestParams({sharedImageRequest: siReq}),
      syncTokenFences: [],
      releaseCount: ++this.release,
    });
    this.chan.flushDeferredRequests([req], ++__deferredId);
    return this._token();
  }
  // Returns {mailbox: Int8Array[16], token: gpu.mojom.SyncToken}.
  create(w, h, usage = SI_USAGE_DISPLAY_READ | SI_USAGE_RASTER_WRITE,
         label = 'mojojs-poc') {
    const mb = genMailbox();
    const meta = new gpu.mojom.SharedImageMetadata({
      format: new viz.mojom.SharedImageFormat({
        singleplanarFormat: viz.mojom.SingleplanarFormat.RGBA_8888,
      }),
      size: new gfx.mojom.Size({width: w, height: h}),
      colorSpace: colorSpaceSRGB(),
      surfaceOrigin: skia.mojom.SurfaceOrigin.kTopLeft,
      alphaType: skia.mojom.AlphaType.PREMUL,
      usage: usage >>> 0,
    });
    const params = new gpu.mojom.CreateSharedImageParams({
      mailbox: new gpu.mojom.Mailbox({name: Array.from(mb)}),
      siInfo: new gpu.mojom.SharedImageInfo({meta, debugLabel: label}),
      poolId: null,
    });
    const tok = this._send(
        new gpu.mojom.DeferredSharedImageRequest({createSharedImage: params}));
    return {mailbox: mb, token: tok};
  }
  destroy(mb) {
    return this._send(new gpu.mojom.DeferredSharedImageRequest({
      destroySharedImage: new gpu.mojom.Mailbox({name: Array.from(mb)}),
    }));
  }
}
