Skip to content

Commit

Permalink
webgpu: implement compilation info
Browse files Browse the repository at this point in the history
Added getCompilationInfo() to shader object so that compilation errors
can be analysed.
  • Loading branch information
edevil committed Aug 9, 2023
1 parent 9f56120 commit d77ef95
Show file tree
Hide file tree
Showing 7 changed files with 110 additions and 12 deletions.
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ WhitespaceSensitiveMacros:
- JSG_STRUCT_TS_OVERRIDE
- JSG_STRUCT_TS_DEFINE
PointerAlignment: Left
ColumnLimit: 100
2 changes: 1 addition & 1 deletion src/workerd/api/gpu/gpu-device.c++
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ GPUDevice::createShaderModule(GPUShaderModuleDescriptor descriptor) {
wgsl_desc.code = descriptor.code.cStr();

auto shader = device_.CreateShaderModule(&desc);
return jsg::alloc<GPUShaderModule>(kj::mv(shader));
return jsg::alloc<GPUShaderModule>(kj::mv(shader), kj::addRef(*async_));
}

jsg::Ref<GPUPipelineLayout>
Expand Down
40 changes: 40 additions & 0 deletions src/workerd/api/gpu/gpu-shader-module.c++
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Copyright (c) 2017-2022 Cloudflare, Inc.
// Licensed under the Apache 2.0 license found in the LICENSE file or at:
// https://opensource.org/licenses/Apache-2.0

#include "gpu-shader-module.h"

namespace workerd::api::gpu {

jsg::Promise<jsg::Ref<GPUCompilationInfo>> GPUShaderModule::getCompilationInfo() {

struct Context {
kj::Own<kj::PromiseFulfiller<jsg::Ref<GPUCompilationInfo>>> fulfiller;
AsyncTask task;
};
auto paf = kj::newPromiseAndFulfiller<jsg::Ref<GPUCompilationInfo>>();
// This context object will hold information for the callback, including the
// fullfiller to signal the caller with the result, and an async task that
// will ensure the device's Tick() function is called periodically. It will be
// deallocated at the end of the callback function.
auto ctx = new Context{kj::mv(paf.fulfiller), AsyncTask(kj::addRef(*async_))};
shader_.GetCompilationInfo(
[](WGPUCompilationInfoRequestStatus status, WGPUCompilationInfo const* compilationInfo,
void* userdata) {
auto c = std::unique_ptr<Context>(static_cast<Context*>(userdata));

kj::Vector<jsg::Ref<GPUCompilationMessage>> messages(compilationInfo->messageCount);
for (uint32_t i = 0; i < compilationInfo->messageCount; i++) {
auto& msg = compilationInfo->messages[i];
messages.add(jsg::alloc<GPUCompilationMessage>(msg));
}

c->fulfiller->fulfill(jsg::alloc<GPUCompilationInfo>(kj::mv(messages)));
},
ctx);

auto& context = IoContext::current();
return context.awaitIo(kj::mv(paf.promise));
}

} // namespace workerd::api::gpu
58 changes: 55 additions & 3 deletions src/workerd/api/gpu/gpu-shader-module.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,72 @@

#pragma once

#include "gpu-async-runner.h"
#include "gpu-utils.h"
#include <webgpu/webgpu_cpp.h>
#include <workerd/jsg/jsg.h>

namespace workerd::api::gpu {

class GPUCompilationMessage : public jsg::Object {
public:
explicit GPUCompilationMessage(const WGPUCompilationMessage& m) : message(m) {}

JSG_RESOURCE_TYPE(GPUCompilationMessage) {
JSG_READONLY_PROTOTYPE_PROPERTY(message, getMessage);
JSG_READONLY_PROTOTYPE_PROPERTY(type, getType);
JSG_READONLY_PROTOTYPE_PROPERTY(lineNum, getLineNum);
JSG_READONLY_PROTOTYPE_PROPERTY(linePos, getLinePos);
JSG_READONLY_PROTOTYPE_PROPERTY(offset, getOffset);
JSG_READONLY_PROTOTYPE_PROPERTY(length, getLength);
}

private:
WGPUCompilationMessage message;

kj::StringPtr getMessage() { return message.message; }
GPUCompilationMessageType getType() {
switch (message.type) {
case WGPUCompilationMessageType_Error:
return kj::str("error");
case WGPUCompilationMessageType_Warning:
return kj::str("warning");
case WGPUCompilationMessageType_Info:
return kj::str("info");
default:
KJ_UNREACHABLE
}
}
uint64_t getLineNum() { return message.lineNum; }
uint64_t getLinePos() { return message.linePos; }
uint64_t getOffset() { return message.offset; }
uint64_t getLength() { return message.length; }
};

class GPUCompilationInfo : public jsg::Object {
public:
explicit GPUCompilationInfo(kj::Vector<jsg::Ref<GPUCompilationMessage>> messages)
: messages_(kj::mv(messages)){};
JSG_RESOURCE_TYPE(GPUCompilationInfo) { JSG_READONLY_PROTOTYPE_PROPERTY(messages, getMessages); }

private:
kj::Vector<jsg::Ref<GPUCompilationMessage>> messages_;
kj::ArrayPtr<jsg::Ref<GPUCompilationMessage>> getMessages() { return messages_.asPtr(); };
void visitForGc(jsg::GcVisitor& visitor) { visitor.visitAll(messages_); }
};

class GPUShaderModule : public jsg::Object {
public:
// Implicit cast operator to Dawn GPU object
inline operator const wgpu::ShaderModule &() const { return shader_; }
explicit GPUShaderModule(wgpu::ShaderModule s) : shader_(kj::mv(s)){};
JSG_RESOURCE_TYPE(GPUShaderModule) {}
inline operator const wgpu::ShaderModule&() const { return shader_; }
explicit GPUShaderModule(wgpu::ShaderModule s, kj::Own<AsyncRunner> async)
: shader_(kj::mv(s)), async_(kj::mv(async)){};
JSG_RESOURCE_TYPE(GPUShaderModule) { JSG_METHOD(getCompilationInfo); }

private:
wgpu::ShaderModule shader_;
kj::Own<AsyncRunner> async_;
jsg::Promise<jsg::Ref<GPUCompilationInfo>> getCompilationInfo();
};

struct GPUShaderModuleDescriptor {
Expand Down
5 changes: 3 additions & 2 deletions src/workerd/api/gpu/gpu-utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ using GPUBufferDynamicOffset = uint32_t;
using GPUPowerPreference = kj::String;
using GPUErrorFilter = kj::String;
using GPUDeviceLostReason = kj::String;
using GPUCompilationMessageType = kj::String;

struct GPUMapMode : public jsg::Object {
static constexpr GPUFlagsConstant READ = 0x0001;
Expand Down Expand Up @@ -79,7 +80,7 @@ struct GPUBufferUsage : public jsg::Object {
};
};

wgpu::FeatureName parseFeatureName(GPUFeatureName &);
kj::Maybe<GPUFeatureName> getFeatureName(wgpu::FeatureName &feature);
wgpu::FeatureName parseFeatureName(GPUFeatureName&);
kj::Maybe<GPUFeatureName> getFeatureName(wgpu::FeatureName& feature);

} // namespace workerd::api::gpu
5 changes: 3 additions & 2 deletions src/workerd/api/gpu/gpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class GPU : public jsg::Object {

private:
jsg::Promise<kj::Maybe<jsg::Ref<GPUAdapter>>>
requestAdapter(jsg::Lock &, jsg::Optional<GPURequestAdapterOptions>);
requestAdapter(jsg::Lock&, jsg::Optional<GPURequestAdapterOptions>);
dawn::native::Instance instance_;
};

Expand Down Expand Up @@ -73,6 +73,7 @@ class GPU : public jsg::Object {
api::gpu::GPURequestAdapterOptions, api::gpu::GPUAdapterInfo, \
api::gpu::GPUSupportedFeatures, api::gpu::GPUSupportedLimits, \
api::gpu::GPUError, api::gpu::GPUOOMError, api::gpu::GPUValidationError, \
api::gpu::GPUDeviceLostInfo
api::gpu::GPUDeviceLostInfo, api::gpu::GPUCompilationMessage, \
api::gpu::GPUCompilationInfo

}; // namespace workerd::api::gpu
11 changes: 7 additions & 4 deletions src/workerd/api/gpu/webgpu-compute-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ export const read_sync_stack = {
ok(adapter.features.has("depth-clip-control"));

ok(adapter.limits);
ok(adapter.limits.maxBufferSize)
ok(adapter.limits.maxBufferSize);

const requiredFeatures = [];
requiredFeatures.push("texture-compression-astc");
Expand All @@ -40,8 +40,8 @@ export const read_sync_stack = {
2 /* rows */, 4 /* columns */, 1, 2, 3, 4, 5, 6, 7, 8,
]);

device.pushErrorScope('out-of-memory');
device.pushErrorScope('validation');
device.pushErrorScope("out-of-memory");
device.pushErrorScope("validation");

const gpuBufferFirstMatrix = device.createBuffer({
mappedAtCreation: true,
Expand All @@ -50,7 +50,7 @@ export const read_sync_stack = {
});
ok(gpuBufferFirstMatrix);

ok(await device.popErrorScope() === null);
ok((await device.popErrorScope()) === null);

const arrayBufferFirstMatrix = gpuBufferFirstMatrix.getMappedRange();
ok(arrayBufferFirstMatrix);
Expand Down Expand Up @@ -174,6 +174,9 @@ export const read_sync_stack = {
});
ok(shaderModule);

const compilationInfo = await shaderModule.getCompilationInfo();
ok(compilationInfo.messages.length == 0);

// Pipeline setup
const computePipeline = device.createComputePipeline({
layout: device.createPipelineLayout({
Expand Down

0 comments on commit d77ef95

Please sign in to comment.