// Minimal end-to-end Dawn/WebGPU program: create instance/adapter/device
// as file-scope handles, compile a trivial WGSL compute shader, create a
// compute pipeline.  Handles are destroyed from static destructors after
// main returns.

#include <webgpu/webgpu_cpp.h>

#include <cstdio>
#include <cstdlib>
#include <utility>

wgpu::Instance instance;
wgpu::Adapter  adapter;
wgpu::Device   device;

static const char* kTrivialShader = R"(
@compute @workgroup_size(1)
fn main() {}
)";

int main() {
    static constexpr auto kTimedWaitAny = wgpu::InstanceFeatureName::TimedWaitAny;
    wgpu::InstanceDescriptor instanceDescriptor;
    instanceDescriptor.requiredFeatureCount = 1;
    instanceDescriptor.requiredFeatures     = &kTimedWaitAny;
    instance = wgpu::CreateInstance(&instanceDescriptor);

    wgpu::RequestAdapterOptions options = {};
    instance.WaitAny(
        instance.RequestAdapter(&options, wgpu::CallbackMode::WaitAnyOnly,
            [](wgpu::RequestAdapterStatus status, wgpu::Adapter a, wgpu::StringView message) {
                if (status != wgpu::RequestAdapterStatus::Success) {
                    std::fprintf(stderr, "RequestAdapter failed: %.*s\n",
                                 (int)message.length, message.data);
                    std::exit(1);
                }
                adapter = std::move(a);
            }),
        UINT64_MAX);

    wgpu::DeviceDescriptor deviceDescriptor = {};
    instance.WaitAny(
        adapter.RequestDevice(&deviceDescriptor, wgpu::CallbackMode::WaitAnyOnly,
            [](wgpu::RequestDeviceStatus status, wgpu::Device d, wgpu::StringView message) {
                if (status != wgpu::RequestDeviceStatus::Success) {
                    std::fprintf(stderr, "RequestDevice failed: %.*s\n",
                                 (int)message.length, message.data);
                    std::exit(1);
                }
                device = std::move(d);
            }),
        UINT64_MAX);

    wgpu::AdapterInfo info;
    adapter.GetInfo(&info);
    std::printf("Adapter: %.*s\n", (int)info.device.length, info.device.data);

    wgpu::ShaderSourceWGSL wgslSource;
    wgslSource.code = kTrivialShader;
    wgpu::ShaderModuleDescriptor shaderModuleDescriptor;
    shaderModuleDescriptor.nextInChain = &wgslSource;
    wgpu::ShaderModule shaderModule = device.CreateShaderModule(&shaderModuleDescriptor);

    wgpu::ComputePipelineDescriptor pipelineDescriptor;
    pipelineDescriptor.compute.module     = shaderModule;
    pipelineDescriptor.compute.entryPoint = "main";
    wgpu::ComputePipeline pipeline = device.CreateComputePipeline(&pipelineDescriptor);
    (void)pipeline;

    return 0;
}
