The end() method of the GPURenderPassEncoder interface completes recording of the current render pass command sequence. 
 
The following criteria must be met when calling end(), otherwise a GPUValidationError is generated and the GPURenderPassEncoder becomes invalid:
  - The 
GPURenderPassEncoder is open (i.e. not already ended via an end() call).  - There is no occlusion query (i.e. started via 
beginOcclusionQuery()) active on the current render pass.  - The debug stack for the current render pass is empty (i.e. no render pass debug group is currently open, as opened by 
pushDebugGroup()).  - The number of draw commands encoded in this render pass is less than or equal to the 
maxDrawCount property set in the GPUCommandEncoder.beginRenderPass() descriptor.  
 
In our basic render demo, several commands are recorded via a GPUCommandEncoder. Most of these commands originate from the GPURenderPassEncoder created via GPUCommandEncoder.beginRenderPass(). end() is called in an appropriate place to end the render pass.
 
const renderPipeline = device.createRenderPipeline(pipelineDescriptor);
const commandEncoder = device.createCommandEncoder();
const renderPassDescriptor = {
  colorAttachments: [
    {
      clearValue: clearColor,
      loadOp: "clear",
      storeOp: "store",
      view: context.getCurrentTexture().createView(),
    },
  ],
};
const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
passEncoder.setPipeline(renderPipeline);
passEncoder.setVertexBuffer(0, vertexBuffer);
passEncoder.draw(3);
passEncoder.end();
device.queue.submit([commandEncoder.finish()]);