Diff
Modified: trunk/Source/WebGPU/ChangeLog (291371 => 291372)
--- trunk/Source/WebGPU/ChangeLog 2022-03-16 21:58:52 UTC (rev 291371)
+++ trunk/Source/WebGPU/ChangeLog 2022-03-16 22:13:40 UTC (rev 291372)
@@ -1,5 +1,32 @@
2022-03-16 Myles C. Maxfield <[email protected]>
+ [WebGPU] Implement first draft of buffer copying according to the spec
+ https://bugs.webkit.org/show_bug.cgi?id=237871
+
+ Reviewed by Kimmo Kinnunen.
+
+ Implement CommandEncoder::copyBufferToBuffer() and CommandEncoder::finish(),
+ according to the algorithms in the spec. There are a few things which the spec
+ lists which we can't do yet (like reporting validation errors), so those things
+ are left with FIXMEs. Every step is listed with links to the spec where
+ appropriate, and with quotes to the spec describing what is being implemented.
+
+ * WebGPU.xcodeproj/project.pbxproj:
+ * WebGPU/CommandEncoder.h:
+ * WebGPU/CommandEncoder.mm:
+ (WebGPU::Device::createCommandEncoder):
+ (WebGPU::CommandEncoder::ensureBlitCommandEncoder):
+ (WebGPU::CommandEncoder::finalizeBlitCommandEncoder):
+ (WebGPU::validateCopyBufferToBuffer):
+ (WebGPU::CommandEncoder::copyBufferToBuffer):
+ (WebGPU::CommandEncoder::validateFinish const):
+ (WebGPU::CommandEncoder::finish):
+ * WebGPU/CommandsMixin.h: Added.
+ * WebGPU/CommandsMixin.mm: Added.
+ (WebGPU::CommandsMixin::prepareTheEncoderState const):
+
+2022-03-16 Myles C. Maxfield <[email protected]>
+
[WebGPU] Implement first draft of buffer mapping according to the spec
https://bugs.webkit.org/show_bug.cgi?id=237870
Modified: trunk/Source/WebGPU/WebGPU/CommandEncoder.h (291371 => 291372)
--- trunk/Source/WebGPU/WebGPU/CommandEncoder.h 2022-03-16 21:58:52 UTC (rev 291371)
+++ trunk/Source/WebGPU/WebGPU/CommandEncoder.h 2022-03-16 22:13:40 UTC (rev 291372)
@@ -25,9 +25,9 @@
#pragma once
+#import "CommandsMixin.h"
#import <wtf/FastMalloc.h>
#import <wtf/Ref.h>
-#import <wtf/RefCounted.h>
#import <wtf/RefPtr.h>
namespace WebGPU {
@@ -38,7 +38,7 @@
class QuerySet;
class RenderPassEncoder;
-class CommandEncoder : public RefCounted<CommandEncoder> {
+class CommandEncoder : public RefCounted<CommandEncoder>, public CommandsMixin {
WTF_MAKE_FAST_ALLOCATED;
public:
static Ref<CommandEncoder> create(id<MTLCommandBuffer> commandBuffer)
@@ -66,7 +66,13 @@
private:
CommandEncoder(id<MTLCommandBuffer>);
+ bool validateFinish() const;
+
+ void ensureBlitCommandEncoder();
+ void finalizeBlitCommandEncoder();
+
id<MTLCommandBuffer> m_commandBuffer { nil };
+ id<MTLBlitCommandEncoder> m_blitCommandEncoder { nil };
};
} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU/CommandEncoder.mm (291371 => 291372)
--- trunk/Source/WebGPU/WebGPU/CommandEncoder.mm 2022-03-16 21:58:52 UTC (rev 291371)
+++ trunk/Source/WebGPU/WebGPU/CommandEncoder.mm 2022-03-16 22:13:40 UTC (rev 291372)
@@ -32,13 +32,26 @@
#import "Device.h"
#import "QuerySet.h"
#import "RenderPassEncoder.h"
+#import "Utilities.h"
namespace WebGPU {
RefPtr<CommandEncoder> Device::createCommandEncoder(const WGPUCommandEncoderDescriptor& descriptor)
{
- UNUSED_PARAM(descriptor);
- return CommandEncoder::create(nil);
+ if (descriptor.nextInChain)
+ return nullptr;
+
+ // https://gpuweb.github.io/gpuweb/#dom-gpudevice-createcommandencoder
+
+ auto *commandBufferDescriptor = [MTLCommandBufferDescriptor new];
+ commandBufferDescriptor.errorOptions = MTLCommandBufferErrorOptionEncoderExecutionStatus;
+ id<MTLCommandBuffer> commandBuffer = [getQueue().commandQueue() commandBufferWithDescriptor:commandBufferDescriptor];
+ if (!commandBuffer)
+ return nullptr;
+
+ commandBuffer.label = [NSString stringWithCString:descriptor.label encoding:NSUTF8StringEncoding];
+
+ return CommandEncoder::create(commandBuffer);
}
CommandEncoder::CommandEncoder(id<MTLCommandBuffer> commandBuffer)
@@ -48,6 +61,18 @@
CommandEncoder::~CommandEncoder() = default;
+void CommandEncoder::ensureBlitCommandEncoder()
+{
+ if (!m_blitCommandEncoder)
+ m_blitCommandEncoder = [m_commandBuffer blitCommandEncoder];
+}
+
+void CommandEncoder::finalizeBlitCommandEncoder()
+{
+ if (m_blitCommandEncoder)
+ [m_blitCommandEncoder endEncoding];
+}
+
RefPtr<ComputePassEncoder> CommandEncoder::beginComputePass(const WGPUComputePassDescriptor& descriptor)
{
UNUSED_PARAM(descriptor);
@@ -60,13 +85,70 @@
return RenderPassEncoder::create(nil);
}
+static bool validateCopyBufferToBuffer(const Buffer& source, uint64_t sourceOffset, const Buffer& destination, uint64_t destinationOffset, uint64_t size)
+{
+ // FIXME: "source is valid to use with this."
+
+ // FIXME: "destination is valid to use with this."
+
+ // "source.[[usage]] contains COPY_SRC."
+ if (!(source.usage() & WGPUBufferUsage_CopySrc))
+ return false;
+
+ // "destination.[[usage]] contains COPY_DST."
+ if (!(destination.usage() & WGPUBufferUsage_CopyDst))
+ return false;
+
+ // "size is a multiple of 4."
+ if (size % 4)
+ return false;
+
+ // "sourceOffset is a multiple of 4."
+ if (sourceOffset % 4)
+ return false;
+
+ // "destinationOffset is a multiple of 4."
+ if (destinationOffset % 4)
+ return false;
+
+ // FIXME: "(sourceOffset + size) does not overflow a GPUSize64."
+
+ // FIXME: "(destinationOffset + size) does not overflow a GPUSize64."
+
+ // FIXME: "source.[[size]] is greater than or equal to (sourceOffset + size)."
+ // FIXME: Use checked arithmetic
+ if (source.size() < sourceOffset + size)
+ return false;
+
+ // FIXME: "destination.[[size]] is greater than or equal to (destinationOffset + size)."
+ // FIXME: Use checked arithmetic
+ if (destination.size() < destinationOffset + size)
+ return false;
+
+ // FIXME: "source and destination are not the same GPUBuffer."
+ if (&source == &destination)
+ return false;
+
+ return true;
+}
+
void CommandEncoder::copyBufferToBuffer(const Buffer& source, uint64_t sourceOffset, const Buffer& destination, uint64_t destinationOffset, uint64_t size)
{
- UNUSED_PARAM(source);
- UNUSED_PARAM(sourceOffset);
- UNUSED_PARAM(destination);
- UNUSED_PARAM(destinationOffset);
- UNUSED_PARAM(size);
+ // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-copybuffertobuffer
+
+ // "Prepare the encoder state of this. If it returns false, stop."
+ if (!prepareTheEncoderState())
+ return;
+
+ // "If any of the following conditions are unsatisfied
+ if (!validateCopyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size)) {
+ // FIXME: "generate a validation error and stop."
+ return;
+ }
+
+ ensureBlitCommandEncoder();
+
+ [m_blitCommandEncoder copyFromBuffer:source.buffer() sourceOffset:static_cast<NSUInteger>(sourceOffset) toBuffer:destination.buffer() destinationOffset:destinationOffset size:size];
}
void CommandEncoder::copyBufferToTexture(const WGPUImageCopyBuffer& source, const WGPUImageCopyTexture& destination, const WGPUExtent3D& copySize)
@@ -97,10 +179,53 @@
UNUSED_PARAM(size);
}
+bool CommandEncoder::validateFinish() const
+{
+ // "Let validationSucceeded be true if all of the following requirements are met, and false otherwise."
+
+ // FIXME: "this must be valid."
+
+ // "this.[[state]] must be "open"."
+ if (m_state != EncoderState::Open)
+ return false;
+
+ // FIXME: "this.[[debug_group_stack]] must be empty."
+
+ // FIXME: "Every usage scope contained in this must satisfy the usage scope validation."
+
+ return true;
+}
+
RefPtr<CommandBuffer> CommandEncoder::finish(const WGPUCommandBufferDescriptor& descriptor)
{
- UNUSED_PARAM(descriptor);
- return CommandBuffer::create(nil);
+ if (descriptor.nextInChain)
+ return nullptr;
+
+ // https://gpuweb.github.io/gpuweb/#dom-gpucommandencoder-finish
+
+ // "Let validationSucceeded be true if all of the following requirements are met, and false otherwise."
+ auto validationFailed = !validateFinish();
+
+ // "Set this.[[state]] to "ended"."
+ m_state = EncoderState::Ended;
+
+ // "If validationSucceeded is false, then:"
+ if (validationFailed) {
+ // FIXME: "Generate a validation error."
+
+ // FIXME: "Return a new invalid GPUCommandBuffer."
+ return nullptr;
+ }
+
+ finalizeBlitCommandEncoder();
+
+ // "Set commandBuffer.[[command_list]] to this.[[commands]]."
+ auto *commandBuffer = m_commandBuffer;
+ m_commandBuffer = nil;
+
+ commandBuffer.label = [NSString stringWithCString:descriptor.label encoding:NSUTF8StringEncoding];
+
+ return CommandBuffer::create(commandBuffer);
}
void CommandEncoder::insertDebugMarker(const char* markerLabel)
Added: trunk/Source/WebGPU/WebGPU/CommandsMixin.h (0 => 291372)
--- trunk/Source/WebGPU/WebGPU/CommandsMixin.h (rev 0)
+++ trunk/Source/WebGPU/WebGPU/CommandsMixin.h 2022-03-16 22:13:40 UTC (rev 291372)
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#import <wtf/RefCounted.h>
+
+namespace WebGPU {
+
+class CommandsMixin {
+protected:
+ bool prepareTheEncoderState() const;
+
+ enum class EncoderState : uint8_t {
+ Open,
+ Locked,
+ Ended
+ };
+ EncoderState m_state { EncoderState::Open };
+};
+
+} // namespace WebGPU
Added: trunk/Source/WebGPU/WebGPU/CommandsMixin.mm (0 => 291372)
--- trunk/Source/WebGPU/WebGPU/CommandsMixin.mm (rev 0)
+++ trunk/Source/WebGPU/WebGPU/CommandsMixin.mm 2022-03-16 22:13:40 UTC (rev 291372)
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021-2022 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "config.h"
+#import "CommandsMixin.h"
+
+namespace WebGPU {
+
+bool CommandsMixin::prepareTheEncoderState() const
+{
+ // https://gpuweb.github.io/gpuweb/#abstract-opdef-prepare-the-encoder-state
+
+ switch (m_state) {
+ case EncoderState::Open:
+ return true;
+ case EncoderState::Locked:
+ // FIXME: "Make encoder invalid"
+ return false;
+ case EncoderState::Ended:
+ // FIXME: "Generate a validation error"
+ return false;
+ }
+}
+
+} // namespace WebGPU
Modified: trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj (291371 => 291372)
--- trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-03-16 21:58:52 UTC (rev 291371)
+++ trunk/Source/WebGPU/WebGPU.xcodeproj/project.pbxproj 2022-03-16 22:13:40 UTC (rev 291372)
@@ -13,6 +13,8 @@
1C2CEDEE271E8A7300EDC16F /* Metal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1C2CEDED271E8A7300EDC16F /* Metal.framework */; };
1C5319C027BDC6CC00CD127E /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5319BF27BDC6CC00CD127E /* main.swift */; };
1C5319C527BDC72700CD127E /* WebGPU.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1CEBD7E32716AFBA00A5254D /* WebGPU.framework */; };
+ 1C582FF927E04131009B40F0 /* CommandsMixin.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C582FF727E04131009B40F0 /* CommandsMixin.mm */; };
+ 1C582FFA27E04131009B40F0 /* CommandsMixin.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C582FF827E04131009B40F0 /* CommandsMixin.h */; };
1C5ACA94273A41C20095F8D5 /* Instance.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C5ACA92273A41C20095F8D5 /* Instance.mm */; };
1C5ACAB6273A426D0095F8D5 /* RenderPipeline.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C5ACA98273A426D0095F8D5 /* RenderPipeline.mm */; };
1C5ACABB273A426D0095F8D5 /* Buffer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C5ACA9D273A426D0095F8D5 /* Buffer.mm */; };
@@ -133,6 +135,8 @@
1C5319BD27BDC6CB00CD127E /* CommandLinePlayground */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = CommandLinePlayground; sourceTree = BUILT_PRODUCTS_DIR; };
1C5319BF27BDC6CC00CD127E /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = "<group>"; };
1C5319CA27BDD70000CD127E /* CommandLinePlayground.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = CommandLinePlayground.xcconfig; sourceTree = "<group>"; };
+ 1C582FF727E04131009B40F0 /* CommandsMixin.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = CommandsMixin.mm; sourceTree = "<group>"; };
+ 1C582FF827E04131009B40F0 /* CommandsMixin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CommandsMixin.h; sourceTree = "<group>"; };
1C5ACA92273A41C20095F8D5 /* Instance.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = Instance.mm; sourceTree = "<group>"; };
1C5ACA96273A426D0095F8D5 /* Surface.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Surface.h; sourceTree = "<group>"; };
1C5ACA97273A426D0095F8D5 /* SwapChain.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SwapChain.h; sourceTree = "<group>"; };
@@ -334,6 +338,8 @@
1C5ACAE2273A55CD0095F8D5 /* CommandBuffer.mm */,
1C5ACA9E273A426D0095F8D5 /* CommandEncoder.h */,
1C5ACAAB273A426D0095F8D5 /* CommandEncoder.mm */,
+ 1C582FF827E04131009B40F0 /* CommandsMixin.h */,
+ 1C582FF727E04131009B40F0 /* CommandsMixin.mm */,
1C5ACAAA273A426D0095F8D5 /* ComputePassEncoder.h */,
1C5ACAA8273A426D0095F8D5 /* ComputePassEncoder.mm */,
1C5ACAA7273A426D0095F8D5 /* ComputePipeline.h */,
@@ -476,6 +482,7 @@
buildActionMask = 2147483647;
files = (
1C5ACAD7273A4D700095F8D5 /* BindGroup.h in Headers */,
+ 1C582FFA27E04131009B40F0 /* CommandsMixin.h in Headers */,
1CEBD7E72716AFBA00A5254D /* WebGPU.h in Headers */,
1C5ACAD3273A4C860095F8D5 /* WebGPUExt.h in Headers */,
);
@@ -722,6 +729,7 @@
1C5ACABB273A426D0095F8D5 /* Buffer.mm in Sources */,
1C5ACAE3273A55CD0095F8D5 /* CommandBuffer.mm in Sources */,
1C5ACAC9273A426E0095F8D5 /* CommandEncoder.mm in Sources */,
+ 1C582FF927E04131009B40F0 /* CommandsMixin.mm in Sources */,
1C5ACAC6273A426D0095F8D5 /* ComputePassEncoder.mm in Sources */,
1C5ACAC0273A426D0095F8D5 /* ComputePipeline.mm in Sources */,
1C5ACAC1273A426D0095F8D5 /* Device.mm in Sources */,