// Copyright 2025 International Digital Economy Academy
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

///|
pub extern "C" fn null_pipeline_layout() -> PipelineLayout = "mbt_wgpu_null_ptr"

///|
pub extern "C" fn device_get_queue(device : Device) -> Queue = "wgpuDeviceGetQueue"

///|
pub fn device_create_command_encoder(device : Device) -> CommandEncoder {
  wgpuDeviceCreateCommandEncoder(device, null_command_encoder_descriptor_ptr())
}

///|
pub fn device_create_buffer(
  device : Device,
  size : UInt64,
  usage : UInt64,
  mapped_at_creation : Bool,
) -> Buffer {
  let desc = buffer_descriptor_new(size, usage, mapped_at_creation)
  let buffer = device_create_buffer_ptr_tracked(device, desc)
  buffer_descriptor_free(desc)
  buffer
}

///|
pub fn device_create_shader_module_wgsl(
  device : Device,
  code : Bytes,
  code_len : UInt64,
) -> ShaderModule {
  let desc = shader_module_descriptor_wgsl_new(code, code_len)
  let shader_module = wgpuDeviceCreateShaderModule(device, desc)
  shader_module_descriptor_free(desc)
  shader_module
}

///|
pub fn device_create_shader_module_glsl(
  device : Device,
  stage_u64 : UInt64,
  code : Bytes,
  code_len : UInt64,
) -> ShaderModule {
  let desc = shader_module_descriptor_glsl_new(stage_u64, code, code_len)
  let shader_module = wgpuDeviceCreateShaderModule(device, desc)
  shader_module_descriptor_free(desc)
  shader_module
}

///|
#borrow(source)
pub extern "C" fn device_create_shader_module_spirv(
  device : Device,
  source : Bytes,
  source_len : UInt64,
) -> ShaderModule = "mbt_wgpu_device_create_shader_module_spirv"

///|
pub fn device_create_compute_pipeline(
  device : Device,
  shader_module : ShaderModule,
) -> ComputePipeline {
  let desc = compute_pipeline_descriptor_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateComputePipeline(device, desc)
  compute_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_texture_rgba8_2d(
  device : Device,
  width : UInt,
  height : UInt,
) -> Texture {
  let desc = texture_descriptor_rgba8_2d_default_new(width, height)
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn device_create_texture_rgba8_2d_with_usage(
  device : Device,
  width : UInt,
  height : UInt,
  usage : UInt64,
) -> Texture {
  let desc = texture_descriptor_rgba8_2d_with_usage_new(width, height, usage)
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn device_create_texture_rgba8_2d_array_with_usage(
  device : Device,
  width : UInt,
  height : UInt,
  layers : UInt,
  mip_level_count : UInt,
  usage : UInt64,
) -> Texture {
  let desc = texture_descriptor_rgba8_2d_array_with_usage_new(
    width, height, layers, mip_level_count, usage,
  )
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn device_create_texture_depth24plus_2d(
  device : Device,
  width : UInt,
  height : UInt,
) -> Texture {
  let desc = texture_descriptor_depth24plus_2d_new(width, height)
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn device_create_texture_u32(
  device : Device,
  width : UInt,
  height : UInt,
  depth_or_array_layers : UInt,
  usage : UInt64,
  dimension_u32 : UInt,
  format_u32 : UInt,
  mip_level_count : UInt,
  sample_count : UInt,
) -> Texture {
  let desc = texture_descriptor_u32_new(
    usage, dimension_u32, width, height, depth_or_array_layers, format_u32, mip_level_count,
    sample_count,
  )
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn device_create_texture_view_formats_u32(
  device : Device,
  width : UInt,
  height : UInt,
  depth_or_array_layers : UInt,
  usage : UInt64,
  dimension_u32 : UInt,
  format_u32 : UInt,
  mip_level_count : UInt,
  sample_count : UInt,
  view_format_count : UInt64,
  view_formats : FixedArray[UInt],
) -> Texture {
  let desc = texture_descriptor_u32_with_view_formats_new(
    usage, dimension_u32, width, height, depth_or_array_layers, format_u32, mip_level_count,
    sample_count, view_format_count, view_formats,
  )
  let tex = wgpuDeviceCreateTexture(device, desc)
  texture_descriptor_free(desc)
  tex
}

///|
pub fn texture_create_view(texture : Texture) -> TextureView {
  wgpuTextureCreateView(texture, null_texture_view_descriptor_ptr())
}

///|
pub fn texture_create_view_u32(
  texture : Texture,
  format_u32 : UInt,
  view_dimension_u32 : UInt,
  aspect_u32 : UInt,
  base_array_layer : UInt,
  array_layer_count : UInt,
  base_mip_level : UInt,
  mip_level_count : UInt,
) -> TextureView {
  let desc = texture_view_descriptor_u32_new(
    format_u32, view_dimension_u32, aspect_u32, base_array_layer, array_layer_count,
    base_mip_level, mip_level_count,
  )
  let view = wgpuTextureCreateView(texture, desc)
  texture_view_descriptor_free(desc)
  view
}

///|
pub fn texture_create_view_2d(
  texture : Texture,
  base_mip_level : UInt,
  mip_level_count : UInt,
) -> TextureView {
  let desc = texture_view_descriptor_2d_new(base_mip_level, mip_level_count)
  let view = wgpuTextureCreateView(texture, desc)
  texture_view_descriptor_free(desc)
  view
}

///|
pub fn texture_create_view_2d_array(
  texture : Texture,
  base_array_layer : UInt,
  array_layer_count : UInt,
  base_mip_level : UInt,
  mip_level_count : UInt,
) -> TextureView {
  let desc = texture_view_descriptor_2d_array_new(
    base_array_layer, array_layer_count, base_mip_level, mip_level_count,
  )
  let view = wgpuTextureCreateView(texture, desc)
  texture_view_descriptor_free(desc)
  view
}

///|
pub fn device_create_render_pipeline_rgba8(
  device : Device,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_color_format(
  device : Device,
  shader_module : ShaderModule,
  format : UInt,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_color_format_new(
    null_pipeline_layout(),
    shader_module,
    format,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_color_format_alpha_blend(
  device : Device,
  shader_module : ShaderModule,
  format : UInt,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_color_format_alpha_blend_new(
    null_pipeline_layout(),
    shader_module,
    format,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_alpha_blend(
  device : Device,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_alpha_blend_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_depth(
  device : Device,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_depth_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_with_layout(
  device : Device,
  layout : PipelineLayout,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_new(layout, shader_module)
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_pos2(
  device : Device,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_pos2_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_mrt2(
  device : Device,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_mrt2_new(
    null_pipeline_layout(),
    shader_module,
  )
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_render_pipeline_rgba8_pos2_with_layout(
  device : Device,
  layout : PipelineLayout,
  shader_module : ShaderModule,
) -> RenderPipeline {
  let desc = render_pipeline_descriptor_rgba8_pos2_new(layout, shader_module)
  let pipeline = wgpuDeviceCreateRenderPipeline(device, desc)
  render_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn device_create_bind_group_layout_empty(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_empty_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_layout_uniform_buffer(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_uniform_buffer_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_layout_uniform_buffer_dynamic(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_uniform_buffer_dynamic_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_uniform_buffer(
  device : Device,
  bind_group_layout : BindGroupLayout,
  buffer : Buffer,
) -> BindGroup {
  let desc = bind_group_descriptor_uniform_buffer_new(bind_group_layout, buffer)
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_bind_group_uniform_buffer_16(
  device : Device,
  bind_group_layout : BindGroupLayout,
  buffer : Buffer,
) -> BindGroup {
  let desc = bind_group_descriptor_uniform_buffer_16_new(
    bind_group_layout, buffer,
  )
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_bind_group_layout_storage_buffer(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_storage_buffer_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_layout_storage_texture_rgba8_writeonly(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_storage_texture_rgba8_writeonly_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_sampler_nearest_clamp(device : Device) -> Sampler {
  let desc = sampler_descriptor_nearest_clamp_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_linear_clamp(device : Device) -> Sampler {
  let desc = sampler_descriptor_linear_clamp_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_nearest_repeat(device : Device) -> Sampler {
  let desc = sampler_descriptor_nearest_repeat_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_linear_repeat(device : Device) -> Sampler {
  let desc = sampler_descriptor_linear_repeat_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_nearest_mirror_repeat(device : Device) -> Sampler {
  let desc = sampler_descriptor_nearest_mirror_repeat_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_linear_mirror_repeat(device : Device) -> Sampler {
  let desc = sampler_descriptor_linear_mirror_repeat_new()
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_sampler_u32(
  device : Device,
  address_mode_u_u32 : UInt,
  address_mode_v_u32 : UInt,
  address_mode_w_u32 : UInt,
  mag_filter_u32 : UInt,
  min_filter_u32 : UInt,
  mipmap_filter_u32 : UInt,
  lod_min_clamp_f32 : Float,
  lod_max_clamp_f32 : Float,
  compare_u32 : UInt,
  max_anisotropy_u32 : UInt,
) -> Sampler {
  let desc = sampler_descriptor_u32_new(
    address_mode_u_u32, address_mode_v_u32, address_mode_w_u32, mag_filter_u32, min_filter_u32,
    mipmap_filter_u32, lod_min_clamp_f32, lod_max_clamp_f32, compare_u32, max_anisotropy_u32,
  )
  let sampler = wgpuDeviceCreateSampler(device, desc)
  sampler_descriptor_free(desc)
  sampler
}

///|
pub fn device_create_bind_group_layout_sampler_texture_2d(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_sampler_texture_2d_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_layout_sampler_filtering(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_sampler_filtering_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_layout_texture_2d_float(
  device : Device,
) -> BindGroupLayout {
  let desc = bind_group_layout_descriptor_texture_2d_float_new()
  let bgl = wgpuDeviceCreateBindGroupLayout(device, desc)
  bind_group_layout_descriptor_free(desc)
  bgl
}

///|
pub fn device_create_bind_group_sampler_texture_2d(
  device : Device,
  bind_group_layout : BindGroupLayout,
  sampler : Sampler,
  view : TextureView,
) -> BindGroup {
  let desc = bind_group_descriptor_sampler_texture_2d_new(
    bind_group_layout, sampler, view,
  )
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_bind_group_sampler(
  device : Device,
  bind_group_layout : BindGroupLayout,
  sampler : Sampler,
) -> BindGroup {
  let desc = bind_group_descriptor_sampler_new(bind_group_layout, sampler)
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_bind_group_texture_2d(
  device : Device,
  bind_group_layout : BindGroupLayout,
  view : TextureView,
) -> BindGroup {
  let desc = bind_group_descriptor_texture_2d_new(bind_group_layout, view)
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_pipeline_layout_1(
  device : Device,
  bind_group_layout : BindGroupLayout,
) -> PipelineLayout {
  let desc = pipeline_layout_descriptor_1_new(bind_group_layout)
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_pipeline_layout_2(
  device : Device,
  bind_group_layout0 : BindGroupLayout,
  bind_group_layout1 : BindGroupLayout,
) -> PipelineLayout {
  let desc = pipeline_layout_descriptor_2_new(
    bind_group_layout0, bind_group_layout1,
  )
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_pipeline_layout_many(
  device : Device,
  bind_group_layouts : Array[BindGroupLayout],
) -> PipelineLayout {
  let count = bind_group_layouts.length()
  let desc = if count == 0 {
    pipeline_layout_descriptor_empty_new()
  } else {
    let fixed = FixedArray::from_array(bind_group_layouts[:])
    pipeline_layout_descriptor_many_new(count.to_uint64(), fixed)
  }
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_pipeline_layout_immediates(
  device : Device,
  stages : UInt64,
  start : UInt,
  end : UInt,
) -> PipelineLayout {
  let desc = pipeline_layout_descriptor_immediates_new(stages, start, end)
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_pipeline_layout_immediates_many(
  device : Device,
  first_stages : UInt64,
  first_start : UInt,
  first_end : UInt,
  other_ranges : Array[(UInt64, UInt, UInt)],
) -> PipelineLayout {
  let stages_all : Array[UInt64] = [first_stages]
  let starts_all : Array[UInt] = [first_start]
  let ends_all : Array[UInt] = [first_end]
  for i = 0; i < other_ranges.length(); i = i + 1 {
    let (stages, start, end) = other_ranges[i]
    stages_all.push(stages)
    starts_all.push(start)
    ends_all.push(end)
  }
  let range_count = stages_all.length().to_uint64()
  let stages_fixed = FixedArray::from_array(stages_all[:])
  let starts_fixed = FixedArray::from_array(starts_all[:])
  let ends_fixed = FixedArray::from_array(ends_all[:])
  let desc = pipeline_layout_descriptor_immediates_many_new(
    range_count, stages_fixed, starts_fixed, ends_fixed,
  )
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_pipeline_layout_with_immediates(
  device : Device,
  bind_group_layouts : Array[BindGroupLayout],
  ranges : Array[(UInt64, UInt, UInt)],
) -> PipelineLayout {
  if ranges.length() == 0 {
    return device_create_pipeline_layout_many(device, bind_group_layouts)
  }
  let stages_all : Array[UInt64] = []
  let starts_all : Array[UInt] = []
  let ends_all : Array[UInt] = []
  for i = 0; i < ranges.length(); i = i + 1 {
    let (stages, start, end) = ranges[i]
    stages_all.push(stages)
    starts_all.push(start)
    ends_all.push(end)
  }
  let layout_count = bind_group_layouts.length().to_uint64()
  let range_count = ranges.length().to_uint64()
  let layouts_fixed = FixedArray::from_array(bind_group_layouts[:])
  let stages_fixed = FixedArray::from_array(stages_all[:])
  let starts_fixed = FixedArray::from_array(starts_all[:])
  let ends_fixed = FixedArray::from_array(ends_all[:])
  let desc = pipeline_layout_descriptor_with_immediates_many_new(
    layout_count, layouts_fixed, range_count, stages_fixed, starts_fixed, ends_fixed,
  )
  let layout = wgpuDeviceCreatePipelineLayout(device, desc)
  pipeline_layout_descriptor_free(desc)
  layout
}

///|
pub fn device_create_render_bundle_encoder_rgba8(
  device : Device,
) -> WGPURenderBundleEncoder {
  let desc = render_bundle_encoder_descriptor_rgba8_new()
  let encoder = wgpuDeviceCreateRenderBundleEncoder(device, desc)
  render_bundle_encoder_descriptor_free(desc)
  encoder
}

///|
pub extern "C" fn render_bundle_encoder_set_pipeline(
  encoder : WGPURenderBundleEncoder,
  pipeline : RenderPipeline,
) -> Unit = "wgpuRenderBundleEncoderSetPipeline"

///|
pub extern "C" fn render_bundle_encoder_draw(
  encoder : WGPURenderBundleEncoder,
  vertex_count : UInt,
  instance_count : UInt,
  first_vertex : UInt,
  first_instance : UInt,
) -> Unit = "wgpuRenderBundleEncoderDraw"

///|
pub fn render_bundle_encoder_set_bind_group0(
  encoder : WGPURenderBundleEncoder,
  group : BindGroup,
) -> Unit {
  wgpuRenderBundleEncoderSetBindGroup(encoder, 0U, group, 0UL, null_uint_ptr())
}

///|
#borrow(offsets)
pub extern "C" fn wgpuRenderBundleEncoderSetBindGroup_offsets(
  encoder : WGPURenderBundleEncoder,
  group_index : UInt,
  group : BindGroup,
  dynamic_offset_count : UInt64,
  offsets : FixedArray[UInt],
) -> Unit = "wgpuRenderBundleEncoderSetBindGroup"

///|
pub fn render_bundle_encoder_set_bind_group(
  encoder : WGPURenderBundleEncoder,
  index : UInt,
  group : BindGroup,
  dynamic_offsets : Array[UInt],
) -> Unit {
  let n = dynamic_offsets.length()
  if n == 0 {
    wgpuRenderBundleEncoderSetBindGroup(
      encoder,
      index,
      group,
      0UL,
      null_uint_ptr(),
    )
    return
  }
  let offsets : FixedArray[UInt] = FixedArray::make(n, 0U)
  for i in 0.. WGPURenderBundle {
  let desc = render_bundle_descriptor_default_new()
  let bundle = wgpuRenderBundleEncoderFinish(encoder, desc)
  render_bundle_descriptor_free(desc)
  bundle
}

///|
pub extern "C" fn render_bundle_encoder_release(
  encoder : WGPURenderBundleEncoder,
) -> Unit = "wgpuRenderBundleEncoderRelease"

///|
pub extern "C" fn render_bundle_release(bundle : WGPURenderBundle) -> Unit = "wgpuRenderBundleRelease"

///|
pub fn device_create_bind_group_storage_buffer(
  device : Device,
  bind_group_layout : BindGroupLayout,
  buffer : Buffer,
) -> BindGroup {
  let desc = bind_group_descriptor_storage_buffer_new(bind_group_layout, buffer)
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_bind_group_storage_texture_2d(
  device : Device,
  bind_group_layout : BindGroupLayout,
  view : TextureView,
) -> BindGroup {
  let desc = bind_group_descriptor_storage_texture_2d_new(
    bind_group_layout, view,
  )
  let bg = wgpuDeviceCreateBindGroup(device, desc)
  bind_group_descriptor_free(desc)
  bg
}

///|
pub fn device_create_compute_pipeline_with_layout(
  device : Device,
  layout : PipelineLayout,
  shader_module : ShaderModule,
) -> ComputePipeline {
  let desc = compute_pipeline_descriptor_new(layout, shader_module)
  let pipeline = wgpuDeviceCreateComputePipeline(device, desc)
  compute_pipeline_descriptor_free(desc)
  pipeline
}

///|
pub fn command_encoder_begin_compute_pass(
  encoder : CommandEncoder,
) -> ComputePassEncoder {
  let desc = compute_pass_descriptor_default_new()
  let pass = wgpuCommandEncoderBeginComputePass(encoder, desc)
  compute_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color(
  encoder : CommandEncoder,
  view : TextureView,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_clear_default_new(view)
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color2(
  encoder : CommandEncoder,
  view0 : TextureView,
  view1 : TextureView,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color2_clear_default_new(view0, view1)
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color2_depth(
  encoder : CommandEncoder,
  color0_view : TextureView,
  color1_view : TextureView,
  depth_view : TextureView,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color2_depth_new(
    color0_view, color1_view, depth_view,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color2_depth_u32(
  encoder : CommandEncoder,
  color0_view : TextureView,
  color1_view : TextureView,
  depth_view : TextureView,
  color0_load_op_u32 : UInt,
  color0_store_op_u32 : UInt,
  color0_clear_r_f32 : Float,
  color0_clear_g_f32 : Float,
  color0_clear_b_f32 : Float,
  color0_clear_a_f32 : Float,
  color1_load_op_u32 : UInt,
  color1_store_op_u32 : UInt,
  color1_clear_r_f32 : Float,
  color1_clear_g_f32 : Float,
  color1_clear_b_f32 : Float,
  color1_clear_a_f32 : Float,
  depth_load_op_u32 : UInt,
  depth_store_op_u32 : UInt,
  depth_clear_value_f32 : Float,
  stencil_load_op_u32 : UInt,
  stencil_store_op_u32 : UInt,
  stencil_clear_value_u32 : UInt,
  depth_read_only : Bool,
  stencil_read_only : Bool,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color2_depth_u32_new(
    color0_view, color0_load_op_u32, color0_store_op_u32, color0_clear_r_f32, color0_clear_g_f32,
    color0_clear_b_f32, color0_clear_a_f32, color1_view, color1_load_op_u32, color1_store_op_u32,
    color1_clear_r_f32, color1_clear_g_f32, color1_clear_b_f32, color1_clear_a_f32,
    depth_view, depth_load_op_u32, depth_store_op_u32, depth_clear_value_f32, stencil_load_op_u32,
    stencil_store_op_u32, stencil_clear_value_u32, depth_read_only, stencil_read_only,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color2_depth_sparse_u32(
  encoder : CommandEncoder,
  color0_view : TextureView,
  color1_view : TextureView,
  depth_view : TextureView,
  color0_load_op_u32 : UInt,
  color0_store_op_u32 : UInt,
  color0_clear_r_f32 : Float,
  color0_clear_g_f32 : Float,
  color0_clear_b_f32 : Float,
  color0_clear_a_f32 : Float,
  color1_load_op_u32 : UInt,
  color1_store_op_u32 : UInt,
  color1_clear_r_f32 : Float,
  color1_clear_g_f32 : Float,
  color1_clear_b_f32 : Float,
  color1_clear_a_f32 : Float,
  depth_load_op_u32 : UInt,
  depth_store_op_u32 : UInt,
  depth_clear_value_f32 : Float,
  stencil_load_op_u32 : UInt,
  stencil_store_op_u32 : UInt,
  stencil_clear_value_u32 : UInt,
  depth_read_only : Bool,
  stencil_read_only : Bool,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color2_depth_sparse_u32_new(
    color0_view, color0_load_op_u32, color0_store_op_u32, color0_clear_r_f32, color0_clear_g_f32,
    color0_clear_b_f32, color0_clear_a_f32, color1_view, color1_load_op_u32, color1_store_op_u32,
    color1_clear_r_f32, color1_clear_g_f32, color1_clear_b_f32, color1_clear_a_f32,
    depth_view, depth_load_op_u32, depth_store_op_u32, depth_clear_value_f32, stencil_load_op_u32,
    stencil_store_op_u32, stencil_clear_value_u32, depth_read_only, stencil_read_only,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_depth_u32(
  encoder : CommandEncoder,
  depth_view : TextureView,
  depth_load_op_u32 : UInt,
  depth_store_op_u32 : UInt,
  depth_clear_value_f32 : Float,
  stencil_load_op_u32 : UInt,
  stencil_store_op_u32 : UInt,
  stencil_clear_value_u32 : UInt,
  depth_read_only : Bool,
  stencil_read_only : Bool,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_depth_u32_new(
    depth_view, depth_load_op_u32, depth_store_op_u32, depth_clear_value_f32, stencil_load_op_u32,
    stencil_store_op_u32, stencil_clear_value_u32, depth_read_only, stencil_read_only,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color_occlusion(
  encoder : CommandEncoder,
  view : TextureView,
  query_set : QuerySet,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_clear_default_occlusion_new(
    view, query_set,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color_load(
  encoder : CommandEncoder,
  view : TextureView,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_load_new(view)
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color_clear(
  encoder : CommandEncoder,
  view : TextureView,
  r : Float,
  g : Float,
  b : Float,
  a : Float,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_clear_new(view, r, g, b, a)
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color_depth(
  encoder : CommandEncoder,
  color_view : TextureView,
  depth_view : TextureView,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_depth_new(color_view, depth_view)
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub fn command_encoder_begin_render_pass_color_depth_u32(
  encoder : CommandEncoder,
  color_view : TextureView,
  color_load_op_u32 : UInt,
  color_store_op_u32 : UInt,
  color_clear_r_f32 : Float,
  color_clear_g_f32 : Float,
  color_clear_b_f32 : Float,
  color_clear_a_f32 : Float,
  depth_view : TextureView,
  depth_load_op_u32 : UInt,
  depth_store_op_u32 : UInt,
  depth_clear_value_f32 : Float,
  stencil_load_op_u32 : UInt,
  stencil_store_op_u32 : UInt,
  stencil_clear_value_u32 : UInt,
  depth_read_only : Bool,
  stencil_read_only : Bool,
) -> RenderPassEncoder {
  let desc = render_pass_descriptor_color_depth_u32_new(
    color_view, color_load_op_u32, color_store_op_u32, color_clear_r_f32, color_clear_g_f32,
    color_clear_b_f32, color_clear_a_f32, depth_view, depth_load_op_u32, depth_store_op_u32,
    depth_clear_value_f32, stencil_load_op_u32, stencil_store_op_u32, stencil_clear_value_u32,
    depth_read_only, stencil_read_only,
  )
  let pass = wgpuCommandEncoderBeginRenderPass(encoder, desc)
  render_pass_descriptor_free(desc)
  pass
}

///|
pub extern "C" fn render_pass_set_pipeline(
  pass : RenderPassEncoder,
  pipeline : RenderPipeline,
) -> Unit = "wgpuRenderPassEncoderSetPipeline"

///|
#borrow(bundles)
pub extern "C" fn wgpuRenderPassEncoderExecuteBundles_bundles(
  pass : RenderPassEncoder,
  bundle_count : UInt64,
  bundles : FixedArray[WGPURenderBundle],
) -> Unit = "wgpuRenderPassEncoderExecuteBundles"

///|
pub fn render_pass_execute_bundles(
  pass : RenderPassEncoder,
  bundles : Array[WGPURenderBundle],
) -> Unit {
  let n = bundles.length()
  if n == 0 {
    return
  }
  let raw : FixedArray[WGPURenderBundle] = FixedArray::make(n, bundles[0])
  for i in 0.. Unit {
  wgpuRenderPassEncoderSetBindGroup(pass, 0U, group, 0UL, null_uint_ptr())
}

///|
#borrow(offsets)
pub extern "C" fn wgpuRenderPassEncoderSetBindGroup_offsets(
  pass : RenderPassEncoder,
  group_index : UInt,
  group : BindGroup,
  dynamic_offset_count : UInt64,
  offsets : FixedArray[UInt],
) -> Unit = "wgpuRenderPassEncoderSetBindGroup"

///|
pub fn render_pass_set_bind_group(
  pass : RenderPassEncoder,
  index : UInt,
  group : BindGroup,
  dynamic_offsets : Array[UInt],
) -> Unit {
  let n = dynamic_offsets.length()
  if n == 0 {
    wgpuRenderPassEncoderSetBindGroup(pass, index, group, 0UL, null_uint_ptr())
    return
  }
  let offsets : FixedArray[UInt] = FixedArray::make(n, 0U)
  for i in 0.. Unit = "wgpuRenderPassEncoderSetVertexBuffer"

///|
pub extern "C" fn render_pass_set_viewport(
  pass : RenderPassEncoder,
  x : Float,
  y : Float,
  width : Float,
  height : Float,
  min_depth : Float,
  max_depth : Float,
) -> Unit = "wgpuRenderPassEncoderSetViewport"

///|
pub extern "C" fn render_pass_set_scissor_rect(
  pass : RenderPassEncoder,
  x : UInt,
  y : UInt,
  width : UInt,
  height : UInt,
) -> Unit = "wgpuRenderPassEncoderSetScissorRect"

///|
pub extern "C" fn index_format_uint16() -> WGPUIndexFormat = "mbt_wgpu_index_format_uint16"

///|
pub extern "C" fn index_format_uint32() -> WGPUIndexFormat = "mbt_wgpu_index_format_uint32"

///|
pub fn render_pass_set_index_buffer_u16(
  pass : RenderPassEncoder,
  buffer : Buffer,
  offset : UInt64,
  size : UInt64,
) -> Unit {
  wgpuRenderPassEncoderSetIndexBuffer(
    pass,
    buffer,
    index_format_uint16(),
    offset,
    size,
  )
}

///|
pub fn render_pass_set_index_buffer_u32(
  pass : RenderPassEncoder,
  buffer : Buffer,
  offset : UInt64,
  size : UInt64,
) -> Unit {
  wgpuRenderPassEncoderSetIndexBuffer(
    pass,
    buffer,
    index_format_uint32(),
    offset,
    size,
  )
}

///|
pub extern "C" fn render_pass_draw(
  pass : RenderPassEncoder,
  vertex_count : UInt,
  instance_count : UInt,
  first_vertex : UInt,
  first_instance : UInt,
) -> Unit = "wgpuRenderPassEncoderDraw"

///|
pub extern "C" fn render_pass_draw_indexed(
  pass : RenderPassEncoder,
  index_count : UInt,
  instance_count : UInt,
  first_index : UInt,
  base_vertex : Int,
  first_instance : UInt,
) -> Unit = "wgpuRenderPassEncoderDrawIndexed"

///|
pub extern "C" fn render_pass_end(pass : RenderPassEncoder) -> Unit = "wgpuRenderPassEncoderEnd"

///|
pub extern "C" fn render_pass_release(pass : RenderPassEncoder) -> Unit = "wgpuRenderPassEncoderRelease"

///|
pub extern "C" fn compute_pass_set_pipeline(
  pass : ComputePassEncoder,
  pipeline : ComputePipeline,
) -> Unit = "wgpuComputePassEncoderSetPipeline"

///|
pub extern "C" fn compute_pass_dispatch_workgroups(
  pass : ComputePassEncoder,
  x : UInt,
  y : UInt,
  z : UInt,
) -> Unit = "wgpuComputePassEncoderDispatchWorkgroups"

///|
pub fn compute_pass_set_bind_group0(
  pass : ComputePassEncoder,
  group : BindGroup,
) -> Unit {
  wgpuComputePassEncoderSetBindGroup(pass, 0U, group, 0UL, null_uint_ptr())
}

///|
#borrow(offsets)
pub extern "C" fn wgpuComputePassEncoderSetBindGroup_offsets(
  pass : ComputePassEncoder,
  group_index : UInt,
  group : BindGroup,
  dynamic_offset_count : UInt64,
  offsets : FixedArray[UInt],
) -> Unit = "wgpuComputePassEncoderSetBindGroup"

///|
pub fn compute_pass_set_bind_group(
  pass : ComputePassEncoder,
  index : UInt,
  group : BindGroup,
  dynamic_offsets : Array[UInt],
) -> Unit {
  let n = dynamic_offsets.length()
  if n == 0 {
    wgpuComputePassEncoderSetBindGroup(pass, index, group, 0UL, null_uint_ptr())
    return
  }
  let offsets : FixedArray[UInt] = FixedArray::make(n, 0U)
  for i in 0.. Unit = "wgpuComputePassEncoderEnd"

///|
pub extern "C" fn compute_pass_release(pass : ComputePassEncoder) -> Unit = "wgpuComputePassEncoderRelease"

///|
#borrow(label)
pub extern "C" fn compute_pass_set_label_utf8(
  pass : ComputePassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_compute_pass_set_label_utf8"

///|
#borrow(label)
pub extern "C" fn compute_pass_insert_debug_marker_utf8(
  pass : ComputePassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_compute_pass_insert_debug_marker_utf8"

///|
#borrow(label)
pub extern "C" fn compute_pass_push_debug_group_utf8(
  pass : ComputePassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_compute_pass_push_debug_group_utf8"

///|
pub extern "C" fn compute_pass_pop_debug_group(
  pass : ComputePassEncoder,
) -> Unit = "mbt_wgpu_compute_pass_pop_debug_group"

///|
#borrow(label)
pub extern "C" fn render_pass_set_label_utf8(
  pass : RenderPassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_render_pass_set_label_utf8"

///|
#borrow(label)
pub extern "C" fn render_pass_insert_debug_marker_utf8(
  pass : RenderPassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_render_pass_insert_debug_marker_utf8"

///|
#borrow(label)
pub extern "C" fn render_pass_push_debug_group_utf8(
  pass : RenderPassEncoder,
  label : Bytes,
  label_len : UInt64,
) -> Unit = "mbt_wgpu_render_pass_push_debug_group_utf8"

///|
pub extern "C" fn render_pass_pop_debug_group(pass : RenderPassEncoder) -> Unit = "mbt_wgpu_render_pass_pop_debug_group"

///|
pub extern "C" fn render_pass_set_blend_constant_rgba(
  pass : RenderPassEncoder,
  r : Double,
  g : Double,
  b : Double,
  a : Double,
) -> Unit = "mbt_wgpu_render_pass_set_blend_constant_rgba"

///|
pub fn command_encoder_finish(encoder : CommandEncoder) -> CommandBuffer {
  wgpuCommandEncoderFinish(encoder, null_command_buffer_descriptor_ptr())
}

///|
pub extern "C" fn command_encoder_clear_buffer(
  encoder : CommandEncoder,
  buffer : Buffer,
  offset : UInt64,
  size : UInt64,
) -> Unit = "wgpuCommandEncoderClearBuffer"

///|
pub extern "C" fn command_encoder_copy_buffer_to_buffer(
  encoder : CommandEncoder,
  source : Buffer,
  source_offset : UInt64,
  destination : Buffer,
  destination_offset : UInt64,
  size : UInt64,
) -> Unit = "wgpuCommandEncoderCopyBufferToBuffer"

///|
pub fn command_encoder_copy_texture_to_buffer_rgba8(
  encoder : CommandEncoder,
  texture : Texture,
  buffer : Buffer,
  width : UInt,
  height : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let src = texel_copy_texture_info_default_new(texture)
  let dst = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToBuffer(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_buffer_info_free(dst)
  texel_copy_texture_info_free(src)
}

///|
pub fn command_encoder_copy_texture_to_buffer_rgba8_mip_layer(
  encoder : CommandEncoder,
  texture : Texture,
  mip_level : UInt,
  array_layer : UInt,
  buffer : Buffer,
  width : UInt,
  height : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let src = texel_copy_texture_info_new(texture, mip_level, 0U, 0U, array_layer)
  let dst = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToBuffer(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_buffer_info_free(dst)
  texel_copy_texture_info_free(src)
}

///|
pub fn command_encoder_copy_texture_to_buffer_bytes_per_pixel(
  encoder : CommandEncoder,
  texture : Texture,
  buffer : Buffer,
  width : UInt,
  height : UInt,
  bytes_per_pixel : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * bytes_per_pixel, 256U)
  let src = texel_copy_texture_info_default_new(texture)
  let dst = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToBuffer(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_buffer_info_free(dst)
  texel_copy_texture_info_free(src)
}

///|
pub fn command_encoder_copy_texture_to_buffer_bytes_per_pixel_mip_layer(
  encoder : CommandEncoder,
  texture : Texture,
  mip_level : UInt,
  array_layer : UInt,
  buffer : Buffer,
  width : UInt,
  height : UInt,
  bytes_per_pixel : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * bytes_per_pixel, 256U)
  let src = texel_copy_texture_info_new(texture, mip_level, 0U, 0U, array_layer)
  let dst = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToBuffer(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_buffer_info_free(dst)
  texel_copy_texture_info_free(src)
}

///|
pub fn command_encoder_copy_buffer_to_texture_rgba8(
  encoder : CommandEncoder,
  buffer : Buffer,
  texture : Texture,
  width : UInt,
  height : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let src = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let dst = texel_copy_texture_info_default_new(texture)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyBufferToTexture(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_texture_info_free(dst)
  texel_copy_buffer_info_free(src)
}

///|
pub fn command_encoder_copy_buffer_to_texture_rgba8_mip_layer(
  encoder : CommandEncoder,
  buffer : Buffer,
  texture : Texture,
  mip_level : UInt,
  array_layer : UInt,
  width : UInt,
  height : UInt,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let src = texel_copy_buffer_info_new(buffer, 0UL, bytes_per_row, height)
  let dst = texel_copy_texture_info_new(texture, mip_level, 0U, 0U, array_layer)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyBufferToTexture(encoder, src, dst, extent)
  extent3d_free(extent)
  texel_copy_texture_info_free(dst)
  texel_copy_buffer_info_free(src)
}

///|
pub fn command_encoder_copy_texture_to_texture_rgba8(
  encoder : CommandEncoder,
  src : Texture,
  dst : Texture,
  width : UInt,
  height : UInt,
) -> Unit {
  let src_info = texel_copy_texture_info_default_new(src)
  let dst_info = texel_copy_texture_info_default_new(dst)
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToTexture(encoder, src_info, dst_info, extent)
  extent3d_free(extent)
  texel_copy_texture_info_free(dst_info)
  texel_copy_texture_info_free(src_info)
}

///|
pub fn command_encoder_copy_texture_to_texture_rgba8_mip_layer(
  encoder : CommandEncoder,
  src : Texture,
  src_mip_level : UInt,
  src_array_layer : UInt,
  dst : Texture,
  dst_mip_level : UInt,
  dst_array_layer : UInt,
  width : UInt,
  height : UInt,
) -> Unit {
  let src_info = texel_copy_texture_info_new(
    src, src_mip_level, 0U, 0U, src_array_layer,
  )
  let dst_info = texel_copy_texture_info_new(
    dst, dst_mip_level, 0U, 0U, dst_array_layer,
  )
  let extent = extent3d_new(width, height, 1U)
  wgpuCommandEncoderCopyTextureToTexture(encoder, src_info, dst_info, extent)
  extent3d_free(extent)
  texel_copy_texture_info_free(dst_info)
  texel_copy_texture_info_free(src_info)
}

///|
#borrow(commands)
pub extern "C" fn queue_submit(
  queue : Queue,
  command_count : UInt64,
  commands : FixedArray[CommandBuffer],
) -> Unit = "wgpuQueueSubmit"

///|
#borrow(commands)
pub extern "C" fn queue_submit_for_index(
  queue : Queue,
  command_count : UInt64,
  commands : FixedArray[CommandBuffer],
) -> UInt64 = "wgpuQueueSubmitForIndex"

///|
pub extern "C" fn queue_get_timestamp_period(queue : Queue) -> Float = "wgpuQueueGetTimestampPeriod"

///|
pub extern "C" fn device_poll(
  device : Device,
  wait : Bool,
  submission_index : WGPUSubmissionIndexPtr,
) -> Bool = "wgpuDevicePoll"

///|
#borrow(data)
pub extern "C" fn render_pass_set_immediates_bytes(
  encoder : RenderPassEncoder,
  stages : UInt64,
  offset : UInt,
  data : Bytes,
  data_len : UInt64,
) -> Unit = "mbt_wgpu_render_pass_set_immediates_bytes"

///|
#borrow(data)
pub extern "C" fn compute_pass_set_immediates_bytes(
  encoder : ComputePassEncoder,
  offset : UInt,
  data : Bytes,
  data_len : UInt64,
) -> Unit = "mbt_wgpu_compute_pass_set_immediates_bytes"

///|
#borrow(data)
pub extern "C" fn render_bundle_encoder_set_immediates_bytes(
  encoder : WGPURenderBundleEncoder,
  stages : UInt64,
  offset : UInt,
  data : Bytes,
  data_len : UInt64,
) -> Unit = "mbt_wgpu_render_bundle_encoder_set_immediates_bytes"

///|
#borrow(data)
pub extern "C" fn queue_write_buffer(
  queue : Queue,
  buffer : Buffer,
  buffer_offset : UInt64,
  data : Bytes,
  size : UInt64,
) -> Unit = "wgpuQueueWriteBuffer"

///|
pub fn queue_write_texture_rgba8_2d(
  queue : Queue,
  texture : Texture,
  width : UInt,
  height : UInt,
  data : Bytes,
  size : UInt64,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let dst = texel_copy_texture_info_default_new(texture)
  let layout = texel_copy_buffer_layout_new(0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  // NOTE: We intentionally declare our own binding taking `Bytes` instead of
  // `UnitPtr`, so MoonBit can pass a borrowed data pointer.
  wgpuQueueWriteTexture_bytes(queue, dst, data, size, layout, extent)
  extent3d_free(extent)
  texel_copy_buffer_layout_free(layout)
  texel_copy_texture_info_free(dst)
}

///|
pub fn queue_write_texture_rgba8_2d_mip_layer(
  queue : Queue,
  texture : Texture,
  mip_level : UInt,
  array_layer : UInt,
  width : UInt,
  height : UInt,
  data : Bytes,
  size : UInt64,
) -> Unit {
  let bytes_per_row = align_up_u32(width * 4U, 256U)
  let dst = texel_copy_texture_info_new(texture, mip_level, 0U, 0U, array_layer)
  let layout = texel_copy_buffer_layout_new(0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuQueueWriteTexture_bytes(queue, dst, data, size, layout, extent)
  extent3d_free(extent)
  texel_copy_buffer_layout_free(layout)
  texel_copy_texture_info_free(dst)
}

///|
pub fn queue_write_texture_2d_bytes_per_pixel(
  queue : Queue,
  texture : Texture,
  width : UInt,
  height : UInt,
  bytes_per_pixel : UInt,
  data : Bytes,
  size : UInt64,
) -> Unit {
  let bytes_per_row = align_up_u32(width * bytes_per_pixel, 256U)
  let dst = texel_copy_texture_info_default_new(texture)
  let layout = texel_copy_buffer_layout_new(0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuQueueWriteTexture_bytes(queue, dst, data, size, layout, extent)
  extent3d_free(extent)
  texel_copy_buffer_layout_free(layout)
  texel_copy_texture_info_free(dst)
}

///|
pub fn queue_write_texture_2d_bytes_per_pixel_mip_layer(
  queue : Queue,
  texture : Texture,
  mip_level : UInt,
  array_layer : UInt,
  width : UInt,
  height : UInt,
  bytes_per_pixel : UInt,
  data : Bytes,
  size : UInt64,
) -> Unit {
  let bytes_per_row = align_up_u32(width * bytes_per_pixel, 256U)
  let dst = texel_copy_texture_info_new(texture, mip_level, 0U, 0U, array_layer)
  let layout = texel_copy_buffer_layout_new(0UL, bytes_per_row, height)
  let extent = extent3d_new(width, height, 1U)
  wgpuQueueWriteTexture_bytes(queue, dst, data, size, layout, extent)
  extent3d_free(extent)
  texel_copy_buffer_layout_free(layout)
  texel_copy_texture_info_free(dst)
}

///|
#borrow(data)
pub extern "C" fn wgpuQueueWriteTexture_bytes(
  queue : Queue,
  destination : WGPUTexelCopyTextureInfoPtr,
  data : Bytes,
  data_size : UInt64,
  data_layout : WGPUTexelCopyBufferLayoutPtr,
  write_size : WGPUExtent3DPtr,
) -> Unit = "wgpuQueueWriteTexture"

///|
pub extern "C" fn command_buffer_release(
  command_buffer : CommandBuffer,
) -> Unit = "wgpuCommandBufferRelease"

///|
pub extern "C" fn command_encoder_release(
  command_encoder : CommandEncoder,
) -> Unit = "wgpuCommandEncoderRelease"

///|
pub extern "C" fn device_create_buffer_ptr_tracked(
  device : Device,
  descriptor : WGPUBufferDescriptorPtr,
) -> Buffer = "mbt_wgpu_device_create_buffer_ptr_tracked"

///|
pub extern "C" fn buffer_add_ref_tracked(buffer : Buffer) -> Unit = "mbt_wgpu_buffer_add_ref_tracked"

///|
pub extern "C" fn buffer_get_size(buffer : Buffer) -> UInt64 = "wgpuBufferGetSize"

///|
pub extern "C" fn buffer_get_map_state_tracked(
  buffer : Buffer,
) -> WGPUBufferMapState = "mbt_wgpu_buffer_get_map_state_tracked"

///|
pub extern "C" fn buffer_destroy(buffer : Buffer) -> Unit = "mbt_wgpu_buffer_destroy_tracked"

///|
pub extern "C" fn buffer_release(buffer : Buffer) -> Unit = "mbt_wgpu_buffer_release_tracked"

///|
#borrow(out)
pub extern "C" fn buffer_map_read_sync(
  instance : Instance,
  buffer : Buffer,
  offset : UInt64,
  size : UInt64,
  out : Bytes,
  out_len : UInt64,
) -> Bool = "mbt_wgpu_buffer_map_read_sync"

///|
#borrow(data)
pub extern "C" fn buffer_map_write_sync(
  instance : Instance,
  buffer : Buffer,
  offset : UInt64,
  data : Bytes,
  data_len : UInt64,
) -> Bool = "mbt_wgpu_buffer_map_write_sync"

///|
pub extern "C" fn buffer_unmap(buffer : Buffer) -> Unit = "mbt_wgpu_buffer_unmap_tracked"

///|
#borrow(out)
pub extern "C" fn buffer_readback_sync(
  instance : Instance,
  buffer : Buffer,
  offset : UInt64,
  size : UInt64,
  out : Bytes,
  out_len : UInt64,
) -> Bool = "mbt_wgpu_buffer_readback_sync"

///|
pub extern "C" fn shader_module_release(shader_module : ShaderModule) -> Unit = "wgpuShaderModuleRelease"

///|
pub extern "C" fn render_pipeline_release(pipeline : RenderPipeline) -> Unit = "wgpuRenderPipelineRelease"

///|
pub extern "C" fn texture_destroy(texture : Texture) -> Unit = "wgpuTextureDestroy"

///|
pub extern "C" fn texture_get_width_u32(texture : Texture) -> UInt = "wgpuTextureGetWidth"

///|
pub extern "C" fn texture_get_height_u32(texture : Texture) -> UInt = "wgpuTextureGetHeight"

///|
pub extern "C" fn texture_get_depth_or_array_layers_u32(
  texture : Texture,
) -> UInt = "wgpuTextureGetDepthOrArrayLayers"

///|
pub extern "C" fn texture_get_mip_level_count_u32(texture : Texture) -> UInt = "wgpuTextureGetMipLevelCount"

///|
pub extern "C" fn texture_get_sample_count_u32(texture : Texture) -> UInt = "wgpuTextureGetSampleCount"

///|
pub extern "C" fn texture_get_dimension_u32(texture : Texture) -> UInt = "wgpuTextureGetDimension"

///|
pub extern "C" fn texture_get_format_u32(texture : Texture) -> UInt = "wgpuTextureGetFormat"

///|
pub extern "C" fn texture_get_usage_u64(texture : Texture) -> UInt64 = "wgpuTextureGetUsage"

///|
pub extern "C" fn texture_add_ref(texture : Texture) -> Unit = "wgpuTextureAddRef"

///|
pub extern "C" fn texture_release(texture : Texture) -> Unit = "wgpuTextureRelease"

///|
pub extern "C" fn texture_view_add_ref(view : TextureView) -> Unit = "wgpuTextureViewAddRef"

///|
pub extern "C" fn texture_view_release(view : TextureView) -> Unit = "wgpuTextureViewRelease"

///|
pub extern "C" fn surface_add_ref(surface : WGPUSurface) -> Unit = "wgpuSurfaceAddRef"

///|
pub extern "C" fn bind_group_layout_add_ref(
  bind_group_layout : BindGroupLayout,
) -> Unit = "wgpuBindGroupLayoutAddRef"

///|
pub extern "C" fn bind_group_add_ref(bind_group : BindGroup) -> Unit = "wgpuBindGroupAddRef"

///|
pub extern "C" fn bind_group_layout_release(
  bind_group_layout : BindGroupLayout,
) -> Unit = "wgpuBindGroupLayoutRelease"

///|
pub extern "C" fn bind_group_release(bind_group : BindGroup) -> Unit = "wgpuBindGroupRelease"

///|
pub extern "C" fn pipeline_layout_release(
  pipeline_layout : PipelineLayout,
) -> Unit = "wgpuPipelineLayoutRelease"

///|
pub extern "C" fn sampler_release(sampler : Sampler) -> Unit = "wgpuSamplerRelease"

///|
pub extern "C" fn compute_pipeline_release(pipeline : ComputePipeline) -> Unit = "wgpuComputePipelineRelease"

///|
pub extern "C" fn queue_release(queue : Queue) -> Unit = "wgpuQueueRelease"

///|
pub extern "C" fn device_destroy(device : Device) -> Unit = "wgpuDeviceDestroy"

///|
pub extern "C" fn device_destroy_record_lost(device : Device) -> Unit = "mbt_wgpu_device_destroy_record_lost"

///|
pub extern "C" fn device_release(device : Device) -> Unit = "wgpuDeviceRelease"

///|
pub extern "C" fn adapter_release(adapter : Adapter) -> Unit = "wgpuAdapterRelease"

///|
pub extern "C" fn instance_release(instance : Instance) -> Unit = "wgpuInstanceRelease"

///|
pub extern "C" fn device_create_query_set(
  device : Device,
  descriptor : WGPUQuerySetDescriptorPtr,
) -> QuerySet = "wgpuDeviceCreateQuerySet"

///|
pub fn device_create_query_set_occlusion(
  device : Device,
  count : UInt,
) -> QuerySet {
  let desc = query_set_descriptor_new(query_type_occlusion(), count)
  let qs = device_create_query_set(device, desc)
  query_set_descriptor_free(desc)
  qs
}

///|
pub fn device_create_query_set_timestamp(
  device : Device,
  count : UInt,
) -> QuerySet {
  let desc = query_set_descriptor_new(query_type_timestamp(), count)
  let qs = device_create_query_set(device, desc)
  query_set_descriptor_free(desc)
  qs
}

///|
pub fn device_create_query_set_pipeline_statistics(
  device : Device,
  count : UInt,
  statistic_name : UInt,
) -> QuerySet {
  let desc = query_set_descriptor_pipeline_statistics_new(count, statistic_name)
  let qs = device_create_query_set(device, desc)
  query_set_descriptor_free(desc)
  qs
}

///|
pub fn device_create_query_set_pipeline_statistics_many(
  device : Device,
  count : UInt,
  first_statistic_name_u32 : UInt,
  other_statistic_names_u32 : Array[UInt],
) -> QuerySet {
  let all_stats : Array[UInt] = [first_statistic_name_u32]
  for i = 0; i < other_statistic_names_u32.length(); i = i + 1 {
    all_stats.push(other_statistic_names_u32[i])
  }
  let fixed = FixedArray::from_array(all_stats[:])
  let desc = query_set_descriptor_pipeline_statistics_many_new(
    count,
    all_stats.length().to_uint64(),
    fixed,
  )
  let qs = device_create_query_set(device, desc)
  query_set_descriptor_free(desc)
  qs
}

///|
pub extern "C" fn query_set_release(query_set : QuerySet) -> Unit = "wgpuQuerySetRelease"

///|
pub extern "C" fn command_encoder_resolve_query_set(
  encoder : CommandEncoder,
  query_set : QuerySet,
  first_query : UInt,
  query_count : UInt,
  destination : Buffer,
  destination_offset : UInt64,
) -> Unit = "wgpuCommandEncoderResolveQuerySet"

///|
pub extern "C" fn command_encoder_write_timestamp(
  encoder : CommandEncoder,
  query_set : QuerySet,
  query_index : UInt,
) -> Unit = "wgpuCommandEncoderWriteTimestamp"

///|
pub extern "C" fn render_pass_write_timestamp(
  pass : RenderPassEncoder,
  query_set : QuerySet,
  query_index : UInt,
) -> Unit = "wgpuRenderPassEncoderWriteTimestamp"

///|
pub extern "C" fn compute_pass_write_timestamp(
  pass : ComputePassEncoder,
  query_set : QuerySet,
  query_index : UInt,
) -> Unit = "wgpuComputePassEncoderWriteTimestamp"

///|
pub extern "C" fn compute_pass_begin_pipeline_statistics_query(
  pass : ComputePassEncoder,
  query_set : QuerySet,
  query_index : UInt,
) -> Unit = "wgpuComputePassEncoderBeginPipelineStatisticsQuery"

///|
pub extern "C" fn compute_pass_end_pipeline_statistics_query(
  pass : ComputePassEncoder,
) -> Unit = "wgpuComputePassEncoderEndPipelineStatisticsQuery"

///|
pub extern "C" fn render_pass_begin_pipeline_statistics_query(
  pass : RenderPassEncoder,
  query_set : QuerySet,
  query_index : UInt,
) -> Unit = "wgpuRenderPassEncoderBeginPipelineStatisticsQuery"

///|
pub extern "C" fn render_pass_end_pipeline_statistics_query(
  pass : RenderPassEncoder,
) -> Unit = "wgpuRenderPassEncoderEndPipelineStatisticsQuery"

///|
pub extern "C" fn render_pass_begin_occlusion_query(
  pass : RenderPassEncoder,
  query_index : UInt,
) -> Unit = "wgpuRenderPassEncoderBeginOcclusionQuery"

///|
pub extern "C" fn render_pass_end_occlusion_query(
  pass : RenderPassEncoder,
) -> Unit = "wgpuRenderPassEncoderEndOcclusionQuery"

///|
pub extern "C" fn render_pass_set_stencil_reference(
  pass : RenderPassEncoder,
  reference : UInt,
) -> Unit = "wgpuRenderPassEncoderSetStencilReference"

///|
pub extern "C" fn render_pass_draw_indirect(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
) -> Unit = "wgpuRenderPassEncoderDrawIndirect"

///|
pub extern "C" fn render_pass_draw_indexed_indirect(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
) -> Unit = "wgpuRenderPassEncoderDrawIndexedIndirect"

///|
pub extern "C" fn render_pass_multi_draw_indirect(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
  count : UInt,
) -> Unit = "wgpuRenderPassEncoderMultiDrawIndirect"

///|
pub extern "C" fn render_pass_multi_draw_indexed_indirect(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
  count : UInt,
) -> Unit = "wgpuRenderPassEncoderMultiDrawIndexedIndirect"

///|
pub extern "C" fn render_pass_multi_draw_indirect_count(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
  count_buffer : Buffer,
  count_buffer_offset : UInt64,
  max_count : UInt,
) -> Unit = "wgpuRenderPassEncoderMultiDrawIndirectCount"

///|
pub extern "C" fn render_pass_multi_draw_indexed_indirect_count(
  pass : RenderPassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
  count_buffer : Buffer,
  count_buffer_offset : UInt64,
  max_count : UInt,
) -> Unit = "wgpuRenderPassEncoderMultiDrawIndexedIndirectCount"

///|
pub extern "C" fn compute_pass_dispatch_workgroups_indirect(
  pass : ComputePassEncoder,
  indirect_buffer : Buffer,
  indirect_offset : UInt64,
) -> Unit = "wgpuComputePassEncoderDispatchWorkgroupsIndirect"