<style>
  :root { background: #102030e0; color: #99ddbbcc; font-size: 15px; }
</style>
<script src="../../../resources/js-test-pre.js"></script>
<script id="shared">
const log = console.debug;

async function gc() {
  await 0;
  if (globalThis.GCController) {
    globalThis.GCController.collect();
  } else if (globalThis.$vm) {
    globalThis.$vm.gc();
  } else {
    log('no GC available');
  }
}

/**
 * @param {GPUDevice} device
 * @param {GPUComputePassEncoder} computePassEncoder
 */
function clearResourceUsages(device, computePassEncoder) {
  let code = `@compute @workgroup_size(1) fn c() {}`;
  let module = device.createShaderModule({code});
  computePassEncoder.setPipeline(device.createComputePipeline(
    {
      layout: 'auto',
      compute: {module},
    }));
  computePassEncoder.dispatchWorkgroups(1);
}

/**
 * @template {any} T
 * @param {GPUDevice} device
 * @param {string} label
 * @param {()=>T} payload
 * @returns {Promise<T>}
 */
async function validationWrapper(device, label, payload)  {
  device.pushErrorScope('internal');
  device.pushErrorScope('out-of-memory');
  device.pushErrorScope('validation');
  let result = payload();
  let validationError = await device.popErrorScope();
  let outOfMemoryError = await device.popErrorScope();
  let internalError = await device.popErrorScope();
  let error = validationError ?? outOfMemoryError ?? internalError;
  if (error) {
    log('*'.repeat(25));
    log(error[Symbol.toStringTag]);
    log(error.message);
    log(label);
    if (error.stack != `_`) {
      log(error.stack);
    }
    log(location);
    log('*'.repeat(25));
    throw error;
  }
  return result;
}

const videoUrls = [

];

/**
 * @param {number} index
 * @returns {Promise<HTMLVideoElement>}
 */
function videoWithData(index) {
  let video = document.createElement('video');
  video.src = videoUrls[index % videoUrls.length];
  return new Promise(resolve => {
    video.onloadeddata = () => {
      resolve(video);
    };
  });
}

/**
* @returns {Promise<string>}
*/
async function makeDataUrl(width, height, color0, color1) {
  let offscreenCanvas = new OffscreenCanvas(width, height);
  let ctx = offscreenCanvas.getContext('2d');
  let gradient = ctx.createLinearGradient(0, 0, width, height);
  gradient.addColorStop(0, color0);
  gradient.addColorStop(0.1, color1);
  gradient.addColorStop(0.3, color0);
  gradient.addColorStop(0.7, color1);
  gradient.addColorStop(0.9, color0);
  gradient.addColorStop(1, color1);
  ctx.fillStyle = gradient;
  ctx.fillRect(0, 0, width, height);
  let blob = await offscreenCanvas.convertToBlob();
  let fileReader = new FileReader();
  fileReader.readAsDataURL(blob);
  return new Promise(resolve => {
    fileReader.onload = () => {
      resolve(fileReader.result);
    };
  });
}

async function imageWithData(width, height, color0, color1) {
  let dataUrl = await makeDataUrl(width, height, color0, color1);
  let img = document.createElement('img');
  img.src = dataUrl;
  await img.decode();
  return img;
}

/**
 * @param {string} payload
 * @returns {string}
 */
function toBlobUrl(payload) {
  let blob = new Blob([payload], {type: 'text/javascript'});
  return URL.createObjectURL(blob);
}
</script>
<script>
globalThis.testRunner?.waitUntilDone();

async function window0() {
  let adapter0 = await navigator.gpu.requestAdapter();
  let device0 = await adapter0.requestDevice({
    defaultQueue: {},
    requiredLimits: {
      maxDynamicStorageBuffersPerPipelineLayout: 4,
      maxSampledTexturesPerShaderStage: 16,
      maxStorageBufferBindingSize: 156390041,
      maxStorageTexturesPerShaderStage: 4,
      maxUniformBufferBindingSize: 56686802,
      maxVertexBuffers: 8,
    },
  });
  let shaderModule0 = device0.createShaderModule({ code: `
requires readonly_and_readwrite_storage_textures;
struct VertexOutput0 {
  @builtin(position) position: vec4f,
}
@vertex fn vertex1() -> VertexOutput0 {
  var out: VertexOutput0;
  return out;
}
  `});
  let shaderModule2 = device0.createShaderModule({ code: `
requires packed_4x8_integer_dot_product;
fn unconst_u32(v: u32) -> u32 { return v; }
struct FragmentInput3 {
  @builtin(sample_index) sample_index: u32,
}
@group(0) @binding(187) var<storage, read_write> buffer24: array<array<f16, 34>>;
@fragment fn fragment3(a0: FragmentInput3) -> @location(200) vec4u {
  var out: vec4u;
  let ptr9: ptr<storage, array<array<f16, 34>>, read_write> = &(*&buffer24);
  let vf13: ptr<storage, array<array<f16, 34>>, read_write> = ptr9;
  if bool((*vf13)[unconst_u32(835703771)][33]) {
    var vf14: u32 = a0.sample_index;
    out = vec4u(vf14);
    discard;
  }
  return out;
}
  `});
  let pipeline3 = await device0.createRenderPipelineAsync({
      layout: 'auto',
      multisample: {
          count: 4
      },
      fragment: {
          module: shaderModule2,
          constants: {},
          targets: [{
              format: 'rg32uint'
          }]
      },
      vertex: {
          module: shaderModule0,
          entryPoint: 'vertex1',
          constants: {},
          buffers: [],
      },
  });
  await device0.queue.onSubmittedWorkDone();
}

onload = async () => {
  try {
  let sharedScript = document.querySelector('#shared').textContent;

  let workers = [

  ];
  let promises = [ window0() ];
  debug('promises created');
  let results = await Promise.allSettled(promises);
  for (let result of results) {
    if (result.status === 'rejected') { throw result.reason; }
  }
  debug('Pass');
  } catch (e) {
    log('error');
    log(e);
    log(e[Symbol.toStringTag]);
    log(e.stack);
    if (e instanceof GPUPipelineError) {
      log(`${e} - ${e.reason}`);
      
    } else if (e instanceof DOMException) {
      if (e.name === 'OperationError') {
      log(e.message);
      
      } else if (e.name === 'InvalidStateError') {
      } else {
        log(e);
        
      }
    } else if (e instanceof GPUValidationError) {
      
    } else if (e instanceof GPUOutOfMemoryError) {
      
    } else if (e instanceof TypeError) {
      log(e);
      
    } else {
      log('unexpected error type');
      log(e);
      
    }
  }
  globalThis.testRunner?.dumpAsText();
  globalThis.testRunner?.notifyDone();
};
</script>
