WebKit Bugzilla
Attachment 362572 Details for
Bug 194665
: [Web GPU] Buffer updates part 1: async mapping functions, unmap, and destroy
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Patch
bug-194665-20190220170216.patch (text/plain), 52.99 KB, created by
Justin Fan
on 2019-02-20 17:02:17 PST
(
hide
)
Description:
Patch
Filename:
MIME Type:
Creator:
Justin Fan
Created:
2019-02-20 17:02:17 PST
Size:
52.99 KB
patch
obsolete
>Subversion Revision: 241328 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index a420326f3b772cf5f430abd161844c239e15fbd0..9f00a1075f25a2ebc027cdd8b745750bedac8c51 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,52 @@ >+2019-02-14 Justin Fan <justin_fan@apple.com> >+ >+ [WebGPU] (WIP) Buffer updates part 1: async mapping functions, unmap, and destroy >+ https://bugs.webkit.org/show_bug.cgi?id=194665 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ buffers.html updated to test all new functionality. Other tests updated to match new API. >+ >+ * Modules/webgpu/WebGPUBuffer.cpp: >+ (WebCore::WebGPUBuffer::create): >+ (WebCore::WebGPUBuffer::WebGPUBuffer): >+ (WebCore::WebGPUBuffer::mapReadAsync): >+ (WebCore::WebGPUBuffer::mapWriteAsync): >+ (WebCore::WebGPUBuffer::unmap): >+ (WebCore::WebGPUBuffer::destroy): >+ * Modules/webgpu/WebGPUBuffer.h: >+ (WebCore::WebGPUBuffer::buffer const): >+ (WebCore::WebGPUBuffer::mapping const): Deleted. >+ (WebCore::WebGPUBuffer::unmap): Deleted. >+ (WebCore::WebGPUBuffer::destroy): Deleted. >+ * Modules/webgpu/WebGPUBuffer.idl: >+ * Modules/webgpu/WebGPUDevice.cpp: >+ (WebCore::WebGPUDevice::createBuffer const): >+ (WebCore::WebGPUDevice::createBindGroup const): >+ * Modules/webgpu/WebGPUDevice.h: >+ * Modules/webgpu/WebGPURenderPassEncoder.cpp: >+ (WebCore::WebGPURenderPassEncoder::setVertexBuffers): >+ * platform/graphics/gpu/GPUBuffer.h: >+ (WebCore::GPUBuffer::isMappable const): >+ (WebCore::GPUBuffer::isMapWriteable const): >+ (WebCore::GPUBuffer::isMapReadable const): >+ (WebCore::GPUBuffer::mapping const): Deleted. >+ * platform/graphics/gpu/GPUBufferUsage.h: >+ * platform/graphics/gpu/GPUDevice.cpp: >+ (WebCore::GPUDevice::tryCreateBuffer const): >+ (WebCore::GPUDevice::createBuffer const): Deleted. >+ * platform/graphics/gpu/GPUDevice.h: >+ * platform/graphics/gpu/cocoa/GPUBufferMetal.mm: >+ (WebCore::GPUBuffer::tryCreateMappableBuffer): >+ (WebCore::GPUBuffer::tryCreate): >+ (WebCore::GPUBuffer::GPUBuffer): >+ (WebCore::GPUBuffer::~GPUBuffer): >+ (WebCore::GPUBuffer::resolveMappingPromise): >+ (WebCore::GPUBuffer::mapReadAsync): >+ (WebCore::GPUBuffer::mapWriteAsync): >+ (WebCore::GPUBuffer::unmap): >+ (WebCore::GPUBuffer::create): Deleted. >+ > 2019-02-12 Justin Fan <justin_fan@apple.com> > > [WebGPU] Remove WebGPUBufferDescriptor/Usage and use GPU versions >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..dd25078d40120b23d2ac374b26b4ac37a8698d0e >--- /dev/null >+++ b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.cpp >@@ -0,0 +1,119 @@ >+/* >+ * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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. >+ */ >+ >+#include "config.h" >+#include "WebGPUBindGroupDescriptor.h" >+ >+#if ENABLE(WEBGPU) >+ >+#include "GPUBindGroupDescriptor.h" >+#include "GPUBuffer.h" >+#include "Logging.h" >+#include <wtf/Variant.h> >+ >+namespace WebCore { >+ >+static bool validateBufferBindingType(const GPUBuffer* buffer, const GPUBindGroupLayoutBinding& binding, const char* const functionName) >+{ >+#if LOG_DISABLED >+ UNUSED_PARAM(functionName); >+#endif >+ >+ switch (binding.type) { >+ case GPUBindGroupLayoutBinding::BindingType::UniformBuffer: >+ if (!buffer->isUniform()) { >+ LOG(WebGPU, "%s: GPUBuffer resource for binding %lu does not have UNIFORM usage!", functionName, binding.binding); >+ return false; >+ } >+ return true; >+ case GPUBindGroupLayoutBinding::BindingType::StorageBuffer: >+ if (!buffer->isStorage()) { >+ LOG(WebGPU, "%s: GPUBuffer resource for binding %lu does not have STORAGE usage!", functionName, binding.binding); >+ return false; >+ } >+ return true; >+ default: >+ LOG(WebGPU, "%s: Layout binding %lu is not a buffer-type resource!", functionName, binding.binding); >+ return false; >+ } >+} >+ >+Optional<GPUBindGroupDescriptor> WebGPUBindGroupDescriptor::validateAndConvertToGPUVersion() const >+{ >+ const char* const functionName = "GPUDevice::createBindGroup()"; >+ >+ if (!layout || !layout->bindGroupLayout()) { >+ LOG(WebGPU, "%s: Invalid GPUBindGroupLayout!", functionName); >+ return WTF::nullopt; >+ } >+ >+ if (bindings.size() != layout->bindGroupLayout()->bindingsMap().size()) { >+ LOG(WebGPU, "%s: Mismatched number of GPUBindGroupLayoutBindings and GPUBindGroupBindings!", functionName); >+ return WTF::nullopt; >+ } >+ >+ auto layoutMap = layout->bindGroupLayout()->bindingsMap(); >+ >+ Vector<GPUBindGroupBinding> bindGroupBindings; >+ bindGroupBindings.reserveCapacity(bindings.size()); >+ >+ for (const auto& binding : bindings) { >+ auto iterator = layoutMap.find(binding.binding); >+ if (iterator == layoutMap.end()) { >+ LOG(WebGPU, "%s: GPUBindGroupLayoutBinding %lu not found in GPUBindGroupLayout!", functionName, binding.binding); >+ return WTF::nullopt; >+ } >+ >+ auto layoutBinding = iterator->value; >+ >+ auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> { >+ // FIXME: Validate binding type with the texture's usage flags. >+ if (view) >+ return static_cast<GPUBindingResource>(view->texture()); >+ return WTF::nullopt; >+ }, [&layoutBinding, functionName] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> { >+ if (binding.buffer && binding.buffer->buffer()) { >+ if (!validateBufferBindingType(binding.buffer->buffer().get(), layoutBinding, functionName)) >+ return WTF::nullopt; >+ >+ return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer().releaseNonNull(), binding.offset, binding.size }); >+ } >+ LOG(WebGPU, "%s: Invalid GPUBindingResource for binding %lu in GPUBindGroupBindings!", functionName, layoutBinding.binding); >+ return WTF::nullopt; >+ }); >+ >+ auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource); >+ if (bindingResource) >+ bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) }); >+ else >+ return WTF::nullopt; >+ } >+ >+ return GPUBindGroupDescriptor { layout->bindGroupLayout().releaseNonNull(), WTFMove(bindGroupBindings) }; >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h >index 67fd939cc4705a3913b3c33a8c8e31346b9dd4eb..d99656f5046d8adc21380f572af59ed2cd17dfe5 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h >+++ b/Source/WebCore/Modules/webgpu/WebGPUBindGroupDescriptor.h >@@ -29,12 +29,17 @@ > > #include "WebGPUBindGroupBinding.h" > #include "WebGPUBindGroupLayout.h" >+#include <wtf/Optional.h> > #include <wtf/RefPtr.h> > #include <wtf/Vector.h> > > namespace WebCore { > >+struct GPUBindGroupDescriptor; >+ > struct WebGPUBindGroupDescriptor { >+ Optional<GPUBindGroupDescriptor> validateAndConvertToGPUVersion() const; >+ > RefPtr<WebGPUBindGroupLayout> layout; > Vector<WebGPUBindGroupBinding> bindings; > }; >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp b/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp >index 909a5c7642f24af64248d999dc31c4e420f40861..b757d83683c447f798c4607f81f8b1cdcdef917f 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp >+++ b/Source/WebCore/Modules/webgpu/WebGPUBuffer.cpp >@@ -28,18 +28,54 @@ > > #if ENABLE(WEBGPU) > >+#include "Logging.h" >+ > namespace WebCore { > >-Ref<WebGPUBuffer> WebGPUBuffer::create(Ref<GPUBuffer>&& buffer) >+Ref<WebGPUBuffer> WebGPUBuffer::create(RefPtr<GPUBuffer>&& buffer) > { > return adoptRef(*new WebGPUBuffer(WTFMove(buffer))); > } > >-WebGPUBuffer::WebGPUBuffer(Ref<GPUBuffer>&& buffer) >+WebGPUBuffer::WebGPUBuffer(RefPtr<GPUBuffer>&& buffer) > : m_buffer(WTFMove(buffer)) > { > } > >+void WebGPUBuffer::mapReadAsync(ArrayBufferPromise&& promise) >+{ >+ rejectOrPendMappingPromise(WTFMove(promise), true); >+} >+ >+void WebGPUBuffer::mapWriteAsync(ArrayBufferPromise&& promise) >+{ >+ rejectOrPendMappingPromise(WTFMove(promise), false); >+} >+ >+void WebGPUBuffer::unmap() >+{ >+ if (m_buffer) >+ m_buffer->unmap(); >+} >+ >+void WebGPUBuffer::destroy() >+{ >+ unmap(); >+ // TODO: Ensure that GPUBuffer is kept alive by resource bindings if still being used by GPU. >+ m_buffer = nullptr; >+} >+ >+void WebGPUBuffer::rejectOrPendMappingPromise(ArrayBufferPromise&& promise, bool isRead) >+{ >+ if (!m_buffer) { >+ LOG(WebGPU, "WebGPUBuffer::map%sAsync(): Invalid operation!", isRead ? "Read" : "Write"); >+ promise.reject(); >+ return; >+ } >+ >+ m_buffer->pendMappingPromise(WTFMove(promise), isRead); >+} >+ > } // namespace WebCore > > #endif // ENABLE(WEBGPU) >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBuffer.h b/Source/WebCore/Modules/webgpu/WebGPUBuffer.h >index 51aebf2e2a785a19da3b0db6868adacd7cbcb248..e485f437260bed19aa48412226f440f9b0b59116 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUBuffer.h >+++ b/Source/WebCore/Modules/webgpu/WebGPUBuffer.h >@@ -28,26 +28,35 @@ > #if ENABLE(WEBGPU) > > #include "GPUBuffer.h" >- >+#include "GPUBufferUsage.h" > #include <wtf/RefCounted.h> > #include <wtf/RefPtr.h> > >+namespace JSC { >+class ArrayBuffer; >+} >+ > namespace WebCore { > >+struct GPUBufferDescriptor; >+ > class WebGPUBuffer : public RefCounted<WebGPUBuffer> { > public: >- static Ref<WebGPUBuffer> create(Ref<GPUBuffer>&&); >+ static Ref<WebGPUBuffer> create(RefPtr<GPUBuffer>&&); > >- const GPUBuffer& buffer() const { return m_buffer.get(); } >+ RefPtr<const GPUBuffer> buffer() const { return m_buffer; } > >- JSC::ArrayBuffer* mapping() const { return m_buffer->mapping(); } >- void unmap() { /* FIXME: Unimplemented stub. */ } >- void destroy() { /* FIXME: Unimplemented stub. */ } >+ void mapReadAsync(ArrayBufferPromise&&); >+ void mapWriteAsync(ArrayBufferPromise&&); >+ void unmap(); >+ void destroy(); > > private: >- explicit WebGPUBuffer(Ref<GPUBuffer>&&); >+ explicit WebGPUBuffer(RefPtr<GPUBuffer>&&); >+ >+ void rejectOrPendMappingPromise(ArrayBufferPromise&&, bool); > >- Ref<GPUBuffer> m_buffer; >+ RefPtr<GPUBuffer> m_buffer; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl b/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl >index 308667ef4355de1d259c68a30d50a258ace88486..752ae7456e9207636f36d616f507759f94167ea6 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl >+++ b/Source/WebCore/Modules/webgpu/WebGPUBuffer.idl >@@ -28,7 +28,10 @@ > EnabledAtRuntime=WebGPU, > ImplementationLacksVTable > ] interface WebGPUBuffer { >- readonly attribute ArrayBuffer? mapping; >+ //void setSubData(u32 offset, ArrayBuffer data); >+ >+ Promise<ArrayBuffer> mapReadAsync(); >+ Promise<ArrayBuffer> mapWriteAsync(); > void unmap(); > > void destroy(); >diff --git a/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp b/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp >index ea3b3c7a39ad15e93b256a405a54ec5847a5b727..8e8b3ab7b6b7cbccc397b85e28fba4faa0925df5 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp >+++ b/Source/WebCore/Modules/webgpu/WebGPUDevice.cpp >@@ -55,7 +55,6 @@ > #include "WebGPUShaderModule.h" > #include "WebGPUShaderModuleDescriptor.h" > #include "WebGPUTexture.h" >-#include <wtf/Variant.h> > > namespace WebCore { > >@@ -73,11 +72,10 @@ WebGPUDevice::WebGPUDevice(Ref<WebGPUAdapter>&& adapter, Ref<GPUDevice>&& device > UNUSED_PARAM(m_adapter); > } > >-RefPtr<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const >+Ref<WebGPUBuffer> WebGPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const > { >- if (auto buffer = m_device->createBuffer(WTFMove(descriptor))) >- return WebGPUBuffer::create(buffer.releaseNonNull()); >- return nullptr; >+ auto buffer = m_device->tryCreateBuffer(WTFMove(descriptor)); >+ return WebGPUBuffer::create(WTFMove(buffer)); > } > > Ref<WebGPUTexture> WebGPUDevice::createTexture(GPUTextureDescriptor&& descriptor) const >@@ -104,44 +102,11 @@ Ref<WebGPUPipelineLayout> WebGPUDevice::createPipelineLayout(WebGPUPipelineLayou > > Ref<WebGPUBindGroup> WebGPUDevice::createBindGroup(WebGPUBindGroupDescriptor&& descriptor) const > { >- if (!descriptor.layout || !descriptor.layout->bindGroupLayout()) { >- LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindGroupLayout!"); >+ auto gpuDescriptor = descriptor.validateAndConvertToGPUVersion(); >+ if (!gpuDescriptor) > return WebGPUBindGroup::create(nullptr); >- } >- >- if (descriptor.bindings.size() != descriptor.layout->bindGroupLayout()->bindingsMap().size()) { >- LOG(WebGPU, "WebGPUDevice::createBindGroup(): Mismatched number of WebGPUBindGroupLayoutBindings and WebGPUBindGroupBindings!"); >- return WebGPUBindGroup::create(nullptr); >- } > >- auto bindingResourceVisitor = WTF::makeVisitor([] (RefPtr<WebGPUTextureView> view) -> Optional<GPUBindingResource> { >- if (view) >- return static_cast<GPUBindingResource>(view->texture()); >- return WTF::nullopt; >- }, [] (const WebGPUBufferBinding& binding) -> Optional<GPUBindingResource> { >- if (binding.buffer) >- return static_cast<GPUBindingResource>(GPUBufferBinding { binding.buffer->buffer(), binding.offset, binding.size }); >- return WTF::nullopt; >- }); >- >- Vector<GPUBindGroupBinding> bindGroupBindings; >- bindGroupBindings.reserveCapacity(descriptor.bindings.size()); >- >- for (const auto& binding : descriptor.bindings) { >- if (!descriptor.layout->bindGroupLayout()->bindingsMap().contains(binding.binding)) { >- LOG(WebGPU, "WebGPUDevice::createBindGroup(): WebGPUBindGroupBinding %lu not found in WebGPUBindGroupLayout!", binding.binding); >- return WebGPUBindGroup::create(nullptr); >- } >- >- auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource); >- if (bindingResource) >- bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) }); >- else { >- LOG(WebGPU, "WebGPUDevice::createBindGroup(): Invalid WebGPUBindingResource for binding %lu in WebGPUBindGroupBindings!", binding.binding); >- return WebGPUBindGroup::create(nullptr); >- } >- } >- auto bindGroup = GPUBindGroup::create(GPUBindGroupDescriptor { descriptor.layout->bindGroupLayout().releaseNonNull(), WTFMove(bindGroupBindings) }); >+ auto bindGroup = GPUBindGroup::create(WTFMove(*gpuDescriptor)); > return WebGPUBindGroup::create(WTFMove(bindGroup)); > } > >diff --git a/Source/WebCore/Modules/webgpu/WebGPUDevice.h b/Source/WebCore/Modules/webgpu/WebGPUDevice.h >index a97485f8a2e5f0aeed26eacb6913d7d0c9a9ec9a..059825ac57dd00da60bba2d3521d86a15e092769 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPUDevice.h >+++ b/Source/WebCore/Modules/webgpu/WebGPUDevice.h >@@ -62,7 +62,7 @@ public: > const WebGPUAdapter& adapter() const { return m_adapter.get(); } > const GPUDevice& device() const { return m_device.get(); } > >- RefPtr<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const; >+ Ref<WebGPUBuffer> createBuffer(GPUBufferDescriptor&&) const; > Ref<WebGPUTexture> createTexture(GPUTextureDescriptor&&) const; > > Ref<WebGPUBindGroupLayout> createBindGroupLayout(WebGPUBindGroupLayoutDescriptor&&) const; >diff --git a/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp b/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp >index 03fb31bbc39cbb00f14b0c8a696df5fa6a3d3790..e196b12e337bfa0ff40a53f7391b2c5bf4af38db 100644 >--- a/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp >+++ b/Source/WebCore/Modules/webgpu/WebGPURenderPassEncoder.cpp >@@ -49,19 +49,35 @@ WebGPURenderPassEncoder::WebGPURenderPassEncoder(Ref<WebGPUCommandBuffer>&& crea > > void WebGPURenderPassEncoder::setVertexBuffers(unsigned long startSlot, Vector<RefPtr<WebGPUBuffer>>&& buffers, Vector<unsigned long long>&& offsets) > { >+#if !LOG_DISABLED >+ const char* const functionName = "GPURenderPassEncoder::setVertexBuffers()"; >+#endif > if (buffers.isEmpty() || buffers.size() != offsets.size()) { >- LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid number of buffers or offsets!"); >+ LOG(WebGPU, "%s: Invalid number of buffers or offsets!", functionName); > return; > } > > if (startSlot + buffers.size() > maxVertexBuffers) { >- LOG(WebGPU, "WebGPURenderPassEncoder::setVertexBuffers: Invalid startSlot %lu for %lu buffers!", startSlot, buffers.size()); >+ LOG(WebGPU, "%s: Invalid startSlot %lu for %lu buffers!", functionName, startSlot, buffers.size()); > return; > } > >- auto gpuBuffers = buffers.map([] (const auto& buffer) -> Ref<const GPUBuffer> { >- return buffer->buffer(); >- }); >+ Vector<Ref<const GPUBuffer>> gpuBuffers; >+ gpuBuffers.reserveCapacity(buffers.size()); >+ >+ for (const auto& buffer : buffers) { >+ if (!buffer || !buffer->buffer()) { >+ LOG(WebGPU, "%s: Invalid or destroyed buffer in list!", functionName); >+ return; >+ } >+ >+ if (!buffer->buffer()->isVertex()) { >+ LOG(WebGPU, "%s: Buffer was not created with VERTEX usage!", functionName); >+ return; >+ } >+ >+ gpuBuffers.uncheckedAppend(buffer->buffer().releaseNonNull()); >+ } > > m_passEncoder->setVertexBuffers(startSlot, WTFMove(gpuBuffers), WTFMove(offsets)); > } >diff --git a/Source/WebCore/Sources.txt b/Source/WebCore/Sources.txt >index ccf6b3a74306b11d02d6022af01779d6f3b27d9c..28f66ef7428ca9cdfce1ffec20cbd6137f7af4c9 100644 >--- a/Source/WebCore/Sources.txt >+++ b/Source/WebCore/Sources.txt >@@ -348,6 +348,7 @@ Modules/webgpu/WHLSL/AST/WHLSLIntegerLiteral.cpp > Modules/webgpu/WHLSL/AST/WHLSLUnsignedIntegerLiteral.cpp > Modules/webgpu/WebGPU.cpp > Modules/webgpu/WebGPUBindGroup.cpp >+Modules/webgpu/WebGPUBindGroupDescriptor.cpp > Modules/webgpu/WebGPUAdapter.cpp > Modules/webgpu/WebGPUBindGroupLayout.cpp > Modules/webgpu/WebGPUBuffer.cpp >diff --git a/Source/WebCore/WebCore.xcodeproj/project.pbxproj b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >index 13e6df6921f43747feed026444af869be5d9fda1..84eef9ee1efddfa98a985e5e03a77eae27a4490a 100644 >--- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj >+++ b/Source/WebCore/WebCore.xcodeproj/project.pbxproj >@@ -4255,6 +4255,7 @@ > D05CED2A0A40BB2C00C5AF38 /* FormatBlockCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D05CED280A40BB2C00C5AF38 /* FormatBlockCommand.h */; }; > D06C0D8F0CFD11460065F43F /* RemoveFormatCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D06C0D8D0CFD11460065F43F /* RemoveFormatCommand.h */; }; > D07DEABA0A36554A00CA30F8 /* InsertListCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */; }; >+ D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D084033A221CBF5400007205 /* GPUBuffer.cpp */; }; > D0843A4B20FEBE3D00FE860E /* GraphicsContext3DManager.h in Headers */ = {isa = PBXBuildFile; fileRef = D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */; settings = {ATTRIBUTES = (Private, ); }; }; > D086FE9809D53AAB005BC74D /* UnlinkCommand.h in Headers */ = {isa = PBXBuildFile; fileRef = D086FE9609D53AAB005BC74D /* UnlinkCommand.h */; }; > D08B00E220A282490004BC0A /* WebGLCompressedTextureASTC.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D0A20D562092A0A600E0C259 /* WebGLCompressedTextureASTC.cpp */; }; >@@ -14073,6 +14074,8 @@ > D07DEAB80A36554A00CA30F8 /* InsertListCommand.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = InsertListCommand.h; sourceTree = "<group>"; }; > D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GPUBindGroupLayoutDescriptor.h; sourceTree = "<group>"; }; > D083D98621C4813E008E8EFF /* WebGPUBindGroupLayoutDescriptor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WebGPUBindGroupLayoutDescriptor.h; path = Modules/streams/WebGPUBindGroupLayoutDescriptor.h; sourceTree = SOURCE_ROOT; }; >+ D084033A221CBF5400007205 /* GPUBuffer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GPUBuffer.cpp; sourceTree = "<group>"; }; >+ D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = WebGPUBindGroupDescriptor.cpp; sourceTree = "<group>"; }; > D0843A4A20FEBE3D00FE860E /* GraphicsContext3DManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GraphicsContext3DManager.h; sourceTree = "<group>"; }; > D0843A4C20FEC16500FE860E /* GraphicsContext3DManager.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = GraphicsContext3DManager.cpp; sourceTree = "<group>"; }; > D086FE9609D53AAB005BC74D /* UnlinkCommand.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UnlinkCommand.h; sourceTree = "<group>"; }; >@@ -18478,6 +18481,7 @@ > D02454D021C4A41C00B73628 /* GPUBindGroupLayout.h */, > D0B8BB0121C46E78000C7681 /* GPUBindGroupLayoutBinding.h */, > D083D98421C48050008E8EFF /* GPUBindGroupLayoutDescriptor.h */, >+ D084033A221CBF5400007205 /* GPUBuffer.cpp */, > D0D8649221B760F2003C983C /* GPUBuffer.h */, > D0BE104A21E6872F00E42A89 /* GPUBufferBinding.h */, > D0D8648721B64CAA003C983C /* GPUBufferDescriptor.h */, >@@ -26103,6 +26107,7 @@ > D0BE106221E6C0EB00E42A89 /* WebGPUBindGroup.idl */, > D0BE104F21E69F8300E42A89 /* WebGPUBindGroupBinding.h */, > D0BE105021E69F8300E42A89 /* WebGPUBindGroupBinding.idl */, >+ D084033D221E186400007205 /* WebGPUBindGroupDescriptor.cpp */, > D0BE105221E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.h */, > D0BE105321E6AA0D00E42A89 /* WebGPUBindGroupDescriptor.idl */, > D003287A21C8645B00622AA6 /* WebGPUBindGroupLayout.cpp */, >@@ -32941,6 +32946,7 @@ > 51A9D9E9195B931F001B2B5C /* GamepadManager.cpp in Sources */, > 515BE1911D54F5FB00DD7C68 /* GamepadProvider.cpp in Sources */, > 837964CF1F8DB69D00218EA0 /* GeolocationPositionIOS.mm in Sources */, >+ D084033C221CBF6900007205 /* GPUBuffer.cpp in Sources */, > 6E21C6C01126338500A7BE02 /* GraphicsContext3D.cpp in Sources */, > 7C3E510B18DF8F3500C112F7 /* HTMLConverter.mm in Sources */, > A8D06B3A0A265DCD005E7203 /* HTMLNames.cpp in Sources */, >diff --git a/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp b/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp >new file mode 100644 >index 0000000000000000000000000000000000000000..ece059aaa7866bd31679af93885ecca0c98150e2 >--- /dev/null >+++ b/Source/WebCore/platform/graphics/gpu/GPUBuffer.cpp >@@ -0,0 +1,40 @@ >+/* >+ * Copyright (C) 2019 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. AND ITS CONTRIBUTORS ``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 ITS 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. >+ */ >+ >+#include "config.h" >+#include "GPUBuffer.h" >+ >+#if ENABLE(WEBGPU) >+ >+namespace WebCore { >+ >+GPUBuffer::PendingMapPromise::PendingMapPromise(ArrayBufferPromise&& pending) >+ : promise(WTFMove(pending)) >+{ >+} >+ >+} // namespace WebCore >+ >+#endif // ENABLE(WEBGPU) >diff --git a/Source/WebCore/platform/graphics/gpu/GPUBuffer.h b/Source/WebCore/platform/graphics/gpu/GPUBuffer.h >index deb583dc86a9da3832e5920e0590e32e18cfeafd..3d5de9e129f0875d880c194672d449e1e9804afe 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUBuffer.h >+++ b/Source/WebCore/platform/graphics/gpu/GPUBuffer.h >@@ -27,6 +27,8 @@ > > #if ENABLE(WEBGPU) > >+#include "GPUBufferUsage.h" >+#include "JSDOMPromiseDeferred.h" > #include <wtf/Ref.h> > #include <wtf/RefCounted.h> > #include <wtf/RetainPtr.h> >@@ -43,6 +45,7 @@ class GPUDevice; > > struct GPUBufferDescriptor; > >+using ArrayBufferPromise = DOMPromiseDeferred<IDLInterface<JSC::ArrayBuffer*>>; > using PlatformBuffer = MTLBuffer; > using PlatformBufferSmartPtr = RetainPtr<MTLBuffer>; > >@@ -50,17 +53,54 @@ class GPUBuffer : public RefCounted<GPUBuffer> { > public: > ~GPUBuffer(); > >- static RefPtr<GPUBuffer> create(const GPUDevice&, GPUBufferDescriptor&&); >+ static RefPtr<GPUBuffer> tryCreate(const GPUDevice&, GPUBufferDescriptor&&); > > PlatformBuffer *platformBuffer() const { return m_platformBuffer.get(); } >+ bool isVertex() const { return m_isVertex; } >+ bool isUniform() const { return m_isUniform; } >+ bool isStorage() const { return m_isStorage; } >+ bool isReadOnly() const { return m_isReadOnly; } > >- JSC::ArrayBuffer* mapping() const { return m_mapping.get(); } >+ void pendMappingPromise(ArrayBufferPromise&&, bool); >+ void unmap(); > > private: >- explicit GPUBuffer(PlatformBufferSmartPtr&&, RefPtr<JSC::ArrayBuffer>&&); >+ struct PendingMapPromise : RefCounted<PendingMapPromise> { >+ static Ref<PendingMapPromise> create(ArrayBufferPromise&& promise) >+ { >+ return adoptRef(*new PendingMapPromise(WTFMove(promise))); >+ } >+ >+ ArrayBufferPromise promise; >+ >+ private: >+ PendingMapPromise(ArrayBufferPromise&&); >+ }; >+ >+ GPUBuffer(PlatformBufferSmartPtr&&, const GPUBufferDescriptor&); >+ >+ static RefPtr<GPUBuffer> tryCreateSharedBuffer(const GPUDevice&, const GPUBufferDescriptor&); >+ void enqueuePromiseResolution(); >+ void resolveMapRead(); >+ void resolveMapWrite(); >+ >+ bool isMappable() const { return m_isMapWriteable || m_isMapReadable; } >+ bool isMapWriteable() const { return m_isMapWriteable && !m_isMapped; } >+ bool isMapReadable() const { return m_isMapReadable && !m_isMapped; } > > PlatformBufferSmartPtr m_platformBuffer; >- RefPtr<JSC::ArrayBuffer> m_mapping; >+ RefPtr<JSC::ArrayBuffer> m_stagingBuffer; >+ RefPtr<PendingMapPromise> m_pendingMapPromise; >+ >+ unsigned long m_byteLength; >+ unsigned m_numQueuedCommandBuffers = 0; >+ bool m_isMapWriteable; >+ bool m_isMapReadable; >+ bool m_isMapped = false; >+ bool m_isVertex; >+ bool m_isUniform; >+ bool m_isStorage; >+ bool m_isReadOnly; > }; > > } // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h b/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h >index 5ab4024a1325405a5b1cf7e8dbb3998d8c2cd194..d2c4a67b07e6e7c255ddb4ebf52290f65801d44c 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h >+++ b/Source/WebCore/platform/graphics/gpu/GPUBufferUsage.h >@@ -35,7 +35,7 @@ using GPUBufferUsageFlags = unsigned long; > > class GPUBufferUsage : public RefCounted<GPUBufferUsage> { > public: >- enum class Flags : GPUBufferUsageFlags { >+ enum Flags : GPUBufferUsageFlags { > None = 0, > MapRead = 1, > MapWrite = 2, >diff --git a/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp b/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp >index 16351e80fe7cdcad4abd434f16d9665a24690335..c6ad216e4e711a61ab460bf1724340f54900084f 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp >+++ b/Source/WebCore/platform/graphics/gpu/GPUDevice.cpp >@@ -44,9 +44,9 @@ > > namespace WebCore { > >-RefPtr<GPUBuffer> GPUDevice::createBuffer(GPUBufferDescriptor&& descriptor) const >+RefPtr<GPUBuffer> GPUDevice::tryCreateBuffer(GPUBufferDescriptor&& descriptor) const > { >- return GPUBuffer::create(*this, WTFMove(descriptor)); >+ return GPUBuffer::tryCreate(*this, WTFMove(descriptor)); > } > > RefPtr<GPUTexture> GPUDevice::tryCreateTexture(GPUTextureDescriptor&& descriptor) const >diff --git a/Source/WebCore/platform/graphics/gpu/GPUDevice.h b/Source/WebCore/platform/graphics/gpu/GPUDevice.h >index 456eb8455dd4e564c4532bd3b2c3fd6271b59b49..7fce8f483e5e448af24eb063d4fac5b70de62f17 100644 >--- a/Source/WebCore/platform/graphics/gpu/GPUDevice.h >+++ b/Source/WebCore/platform/graphics/gpu/GPUDevice.h >@@ -60,7 +60,7 @@ class GPUDevice : public RefCounted<GPUDevice> { > public: > static RefPtr<GPUDevice> create(Optional<GPURequestAdapterOptions>&&); > >- RefPtr<GPUBuffer> createBuffer(GPUBufferDescriptor&&) const; >+ RefPtr<GPUBuffer> tryCreateBuffer(GPUBufferDescriptor&&) const; > RefPtr<GPUTexture> tryCreateTexture(GPUTextureDescriptor&&) const; > > RefPtr<GPUBindGroupLayout> tryCreateBindGroupLayout(GPUBindGroupLayoutDescriptor&&) const; >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm >index fcc276dbe14295381b43325c0cc26dfd48534ae7..52a33f8eaca80b2f2bfb98c73a5ac4ae2510ab83 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUBufferMetal.mm >@@ -31,65 +31,153 @@ > #import "GPUBufferDescriptor.h" > #import "GPUDevice.h" > #import "Logging.h" >- >-#import <Foundation/NSRange.h> >+#import "Microtasks.h" > #import <JavaScriptCore/ArrayBuffer.h> > #import <Metal/Metal.h> >-#import <wtf/Gigacage.h> >-#import <wtf/PageBlock.h> >+#import <wtf/BlockObjCExceptions.h> > > namespace WebCore { > >-RefPtr<GPUBuffer> GPUBuffer::create(const GPUDevice& device, GPUBufferDescriptor&& descriptor) >+RefPtr<GPUBuffer> GPUBuffer::tryCreateSharedBuffer(const GPUDevice& device, const GPUBufferDescriptor& descriptor) >+{ >+ ASSERT(device.platformDevice()); >+ >+ RetainPtr<MTLBuffer> mtlBuffer; >+ >+ BEGIN_BLOCK_OBJC_EXCEPTIONS; >+ >+ mtlBuffer = adoptNS([device.platformDevice() newBufferWithLength:descriptor.size options: MTLResourceCPUCacheModeDefaultCache]); >+ >+ END_BLOCK_OBJC_EXCEPTIONS; >+ >+ if (!mtlBuffer) { >+ LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!"); >+ return nullptr; >+ } >+ >+ return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), descriptor)); >+} >+ >+static const auto readOnlyMask = GPUBufferUsage::Index | GPUBufferUsage::Vertex | GPUBufferUsage::Uniform | GPUBufferUsage::TransferSrc; >+ >+RefPtr<GPUBuffer> GPUBuffer::tryCreate(const GPUDevice& device, GPUBufferDescriptor&& descriptor) > { > if (!device.platformDevice()) { > LOG(WebGPU, "GPUBuffer::create(): Invalid GPUDevice!"); > return nullptr; > } > >- size_t pageSize = WTF::pageSize(); >- size_t pageAlignedSize = roundUpToMultipleOf(pageSize, descriptor.size); >- void* pageAlignedCopy = Gigacage::tryAlignedMalloc(Gigacage::Primitive, pageSize, pageAlignedSize); >- if (!pageAlignedCopy) { >- LOG(WebGPU, "GPUBuffer::create(): Unable to allocate memory!"); >+ if ((descriptor.usage & GPUBufferUsage::MapWrite) && (descriptor.usage & GPUBufferUsage::MapRead)) { >+ LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both MAP_READ and MAP_WRITE usage!"); > return nullptr; > } > >- auto arrayBuffer = ArrayBuffer::createFromBytes(pageAlignedCopy, descriptor.size, [] (void* ptr) { >- Gigacage::alignedFree(Gigacage::Primitive, ptr); >- }); >- arrayBuffer->ref(); >- ArrayBuffer* arrayBufferContents = arrayBuffer.ptr(); >- // FIXME: Default this MTLResourceOptions. >- PlatformBufferSmartPtr mtlBuffer = adoptNS([device.platformDevice() >- newBufferWithBytesNoCopy:arrayBuffer->data() >- length:pageAlignedSize >- options:MTLResourceCPUCacheModeDefaultCache >- deallocator:^(void*, NSUInteger) { >- arrayBufferContents->deref(); >- }]); >- >- if (!mtlBuffer) { >- LOG(WebGPU, "GPUBuffer::create(): Unable to create MTLBuffer!"); >- arrayBuffer->deref(); >+ if ((descriptor.usage & readOnlyMask) && (descriptor.usage & GPUBufferUsage::Storage)) { >+ LOG(WebGPU, "GPUBuffer::create(): Buffer cannot have both STORAGE and a read-only usage!"); > return nullptr; > } > >- return adoptRef(*new GPUBuffer(WTFMove(mtlBuffer), WTFMove(arrayBuffer))); >+ // Mappable buffers need (default) shared storage allocation. >+ if (descriptor.usage & (GPUBufferUsage::MapWrite | GPUBufferUsage::MapRead)) >+ return tryCreateSharedBuffer(device, descriptor); >+ >+ LOG(WebGPU, "GPUBuffer::create(): Support for non-mapped buffers not implemented!"); >+ return nullptr; > } > >-GPUBuffer::GPUBuffer(PlatformBufferSmartPtr&& platformBuffer, RefPtr<ArrayBuffer>&& arrayBuffer) >- : m_platformBuffer(WTFMove(platformBuffer)) >- , m_mapping(WTFMove(arrayBuffer)) >+GPUBuffer::GPUBuffer(RetainPtr<MTLBuffer>&& buffer, const GPUBufferDescriptor& descriptor) >+ : m_platformBuffer(WTFMove(buffer)) >+ , m_byteLength(descriptor.size) >+ , m_isMapWriteable(descriptor.usage & GPUBufferUsage::MapWrite) >+ , m_isMapReadable(descriptor.usage & GPUBufferUsage::MapRead) >+ , m_isVertex(descriptor.usage & GPUBufferUsage::Vertex) >+ , m_isUniform(descriptor.usage & GPUBufferUsage::Uniform) >+ , m_isStorage(descriptor.usage & GPUBufferUsage::Storage) >+ , m_isReadOnly(descriptor.usage & readOnlyMask) > { > } > > GPUBuffer::~GPUBuffer() > { >- if (m_mapping) { >- m_mapping->deref(); >- m_mapping = nullptr; >+ unmap(); >+} >+ >+void GPUBuffer::pendMappingPromise(ArrayBufferPromise&& promise, bool isRead) >+{ >+ // Reject if request is invalid. >+ if (isRead && !isMapReadable()) { >+ LOG(WebGPU, "GPUBuffer::mapReadAsync(): Invalid operation!"); >+ promise.reject(); >+ return; >+ >+ if (!isMapWriteable()) { >+ LOG(WebGPU, "GPUBuffer::mapWriteAsync(): Invalid operation!"); >+ promise.reject(); >+ return; > } >+ >+ ASSERT(!m_pendingMapPromise); >+ >+ m_pendingMapPromise = PendingMapPromise::create(WTFMove(promise)); >+ m_isMapped = true; >+ >+ // If GPU is not using this buffer, resolve the promise ASAP. >+ if (!m_numQueuedCommandBuffers) >+ enqueuePromiseResolution(); >+} >+ >+void GPUBuffer::enqueuePromiseResolution() >+{ >+ MicrotaskQueue::mainThreadQueue().append(std::make_unique<VoidMicrotask>([this, protectedThis = makeRef(*this)] () mutable { >+ if (m_isMapReadable) >+ resolveMapRead(); >+ else >+ resolveMapWrite(); >+ })); >+} >+ >+void GPUBuffer::resolveMapRead() >+{ >+ // If promise no longer exists, the buffer was likely unmapped. >+ if (!m_pendingMapPromise) >+ return; >+ >+ if (!m_stagingBuffer) >+ m_stagingBuffer = ArrayBuffer::create(1, m_byteLength); >+ >+ memcpy(m_stagingBuffer->data(), m_platformBuffer.get().contents, m_byteLength); >+ >+ auto ptr = m_stagingBuffer.get(); >+ m_pendingMapPromise->promise.resolve(ptr); >+ m_pendingMapPromise = nullptr; >+} >+ >+void GPUBuffer::resolveMapWrite() >+{ >+ // If promise no longer exists, the buffer was likely unmapped. >+ if (!m_pendingMapPromise) >+ return; >+ >+ m_stagingBuffer = ArrayBuffer::create(1, m_byteLength); >+ >+ auto ptr = m_stagingBuffer.get(); >+ m_pendingMapPromise->promise.resolve(ptr); >+ m_pendingMapPromise = nullptr; >+} >+ >+void GPUBuffer::unmap() >+{ >+ if (m_stagingBuffer && m_isMapWriteable) { >+ memcpy(m_platformBuffer.get().contents, m_stagingBuffer->data(), m_byteLength); >+ m_stagingBuffer = nullptr; >+ } >+ >+ if (m_pendingMapPromise) { >+ m_pendingMapPromise->promise.reject(); >+ m_pendingMapPromise = nullptr; >+ } >+ >+ m_isMapped = false; > } > > } // namespace WebCore >diff --git a/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm b/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm >index 4ffe38750c3314db9d00d52c40a3611098bdb952..a331b53583d5c23660e36377776159a91cef67fd 100644 >--- a/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm >+++ b/Source/WebCore/platform/graphics/gpu/cocoa/GPUProgrammablePassEncoderMetal.mm >@@ -61,17 +61,17 @@ void GPUProgrammablePassEncoder::setResourceAsBufferOnEncoder(MTLArgumentEncoder > } > > auto& bufferBinding = WTF::get<GPUBufferBinding>(resource); >- auto buffer = bufferBinding.buffer->platformBuffer(); >+ auto mtlBuffer = bufferBinding.buffer->platformBuffer(); > >- if (!buffer) { >+ if (!mtlBuffer) { > LOG(WebGPU, "%s: Invalid MTLBuffer in GPUBufferBinding!", functionName); > return; > } > > BEGIN_BLOCK_OBJC_EXCEPTIONS; > >- [argumentEncoder setBuffer:buffer offset:bufferBinding.offset atIndex:index]; >- useResource(buffer, MTLResourceUsageRead); >+ [argumentEncoder setBuffer:mtlBuffer offset:bufferBinding.offset atIndex:index]; >+ useResource(mtlBuffer, bufferBinding.buffer->isReadOnly() ? MTLResourceUsageRead : MTLResourceUsageRead | MTLResourceUsageWrite); > > END_BLOCK_OBJC_EXCEPTIONS; > } >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index c9dbfb9f9ba6b6504022268303ce463c16d91545..c1d9b756a909952864a7e630d5b676a1f41287de 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,13 @@ >+2019-02-14 Justin Fan <justin_fan@apple.com> >+ >+ [WebGPU] (WIP) Buffer updates part 1: async mapping functions, unmap, and destroy >+ https://bugs.webkit.org/show_bug.cgi?id=194665 >+ >+ Reviewed by NOBODY (OOPS!). >+ >+ * webgpu/buffer-resource-triangles.html: >+ * webgpu/buffers.html: >+ > 2019-02-12 Justin Fan <justin_fan@apple.com> > > [WebGPU] Remove WebGPUBufferDescriptor/Usage and use GPU versions >diff --git a/LayoutTests/webgpu/buffer-resource-triangles.html b/LayoutTests/webgpu/buffer-resource-triangles.html >index 0f3a1473df1105dda9075a870986829e560fe74b..b4a2855a65d06f0c187acd26c2a82f2d8f2cb8ad 100644 >--- a/LayoutTests/webgpu/buffer-resource-triangles.html >+++ b/LayoutTests/webgpu/buffer-resource-triangles.html >@@ -79,34 +79,33 @@ function createUniformBufferBindGroupLayout(bindNum, stage = WebGPUShaderStageBi > > const vertexSize = 4 * 4; > const verticesBufferSize = vertexSize * 3; >+function createAndUploadVerticesBuffer(device, promises) { >+ const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE }); >+ >+ const promise = buffer.mapWriteAsync().then(mapping => { >+ const mappedArray = new Float32Array(mapping); >+ mappedArray.set([ >+ 0, 1, 0, 1, >+ -1, -1, 0, 1, >+ 1, -1, 0, 1 >+ ]); >+ buffer.unmap(); >+ }); > >-// FIXME: Keep up to date with buffer upload decisions. >-function createVerticesBuffer(device) { >- const buffer = device.createBuffer({ size:verticesBufferSize, usage: GPUBufferUsage.VERTEX }); >- >- const vertices = [ >- 0, 1, 0, 1, >- -1, -1, 0, 1, >- 1, -1, 0, 1 >- ]; >- >- const mappedArray = new Float32Array(buffer.mapping); >- mappedArray.set(vertices); >- >+ promises.push(promise); > return buffer; > } > >-function createFloat4Buffer(device, a, b) { >- const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM }); >- >- const arrayBuffer = buffer.mapping; >- const floatArray = new Float32Array(arrayBuffer); >+function createFloat4Buffer(device, a, b, promises) { >+ const buffer = device.createBuffer({ size: vertexSize, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE }); > >- floatArray[0] = a; >- floatArray[1] = b; >- floatArray[2] = 0; >- floatArray[3] = 1; >+ const promise = buffer.mapWriteAsync().then(mapping => { >+ const mappedArray = new Float32Array(mapping); >+ mappedArray.set([a, b, 0, 1]); >+ buffer.unmap(); >+ }); > >+ promises.push(promise); > return buffer; > } > >@@ -126,16 +125,18 @@ async function test() { > const shaderModule = device.createShaderModule({ code: shaderCode }); > > // Create vertex data WebGPUBuffers. >- const verticesBuffer = createVerticesBuffer(device); >+ let bufferPromises = []; > >- const upperLeft = createFloat4Buffer(device, -1, 1); >- const upperMiddle = createFloat4Buffer(device, 0, 1); >- const upperRight = createFloat4Buffer(device, 1, 1); >- const lowerLeft = createFloat4Buffer(device, -1, -1); >- const lowerRight = createFloat4Buffer(device, 1, -1); >+ const verticesBuffer = createAndUploadVerticesBuffer(device, bufferPromises); >+ >+ const upperLeft = createFloat4Buffer(device, -1, 1, bufferPromises); >+ const upperMiddle = createFloat4Buffer(device, 0, 1, bufferPromises); >+ const upperRight = createFloat4Buffer(device, 1, 1, bufferPromises); >+ const lowerLeft = createFloat4Buffer(device, -1, -1, bufferPromises); >+ const lowerRight = createFloat4Buffer(device, 1, -1, bufferPromises); > > // Color data buffer. >- const green = createFloat4Buffer(device, 0, 1); >+ const green = createFloat4Buffer(device, 0, 1, bufferPromises); > > // Create vertex input state. > const inputState = { >@@ -195,21 +196,23 @@ async function test() { > bindings: [bgBindingUR, bgBindingUM, bgBindingLR] > }); > >- const commandBuffer = device.createCommandBuffer(); >- const passEncoder = beginBasicRenderPass(context, commandBuffer); >- passEncoder.setPipeline(pipeline); >- >- // Vertex data for upper triangles. >- passEncoder.setBindGroup(0, leftTriangleBG); >- passEncoder.setBindGroup(1, rightTriangleBG); >- // Lower triangle. >- passEncoder.setVertexBuffers(0, [verticesBuffer], [0]); >- passEncoder.draw(9, 1, 0, 0); >- >- const endCommandBuffer = passEncoder.endPass(); >- const queue = device.getQueue(); >- queue.submit([endCommandBuffer]); >- context.present(); >+ Promise.all(bufferPromises).then(() => { >+ const commandBuffer = device.createCommandBuffer(); >+ const passEncoder = beginBasicRenderPass(context, commandBuffer); >+ passEncoder.setPipeline(pipeline); >+ >+ // Vertex data for upper triangles. >+ passEncoder.setBindGroup(0, leftTriangleBG); >+ passEncoder.setBindGroup(1, rightTriangleBG); >+ // Lower triangle. >+ passEncoder.setVertexBuffers(0, [verticesBuffer], [0]); >+ passEncoder.draw(9, 1, 0, 0); >+ >+ const endCommandBuffer = passEncoder.endPass(); >+ const queue = device.getQueue(); >+ queue.submit([endCommandBuffer]); >+ context.present(); >+ }); > } > > test(); >diff --git a/LayoutTests/webgpu/buffers-expected.txt b/LayoutTests/webgpu/buffers-expected.txt >deleted file mode 100644 >index ad0fb71b7e07b27e157b86d4223ac4465044e705..0000000000000000000000000000000000000000 >--- a/LayoutTests/webgpu/buffers-expected.txt >+++ /dev/null >@@ -1,4 +0,0 @@ >-PASS [object WebGPU] is defined. >- >-PASS createBuffer() on WebGPUDevice. >- >diff --git a/LayoutTests/webgpu/buffers.html b/LayoutTests/webgpu/buffers.html >deleted file mode 100644 >index 6f70f4bbd733052fdb99618ee15da71d1966f6f6..0000000000000000000000000000000000000000 >--- a/LayoutTests/webgpu/buffers.html >+++ /dev/null >@@ -1,31 +0,0 @@ >-<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] --> >-<meta charset=utf-8> >-<title>Get the WebGPUDevice, create a WebGPUBuffer, and write vertex data to it.</title> >-<body> >-<script src="../resources/testharness.js"></script> >-<script src="../resources/testharnessreport.js"></script> >-<script src="../resources/js-test-pre.js"></script> >-<script src="js/basic-webgpu-functions.js"></script> >-<script> >-function createBuffer() { >- const buffer = defaultDevice.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE }); >- assert_true(buffer instanceof WebGPUBuffer, "createBuffer returned a WebGPUBuffer"); >- >- let arrayBuffer = buffer.mapping; >- let floatArray = new Float32Array(arrayBuffer); >- assert_equals(floatArray.length, 4); >- >- floatArray[0] = -1; >- floatArray[1] = 1; >- floatArray[2] = 0; >- floatArray[3] = 1; >-} >- >-promise_test(async t => { >- const canvas = document.createElement("canvas"); >- await setUpContexts(canvas); >- createBuffer(); >-}, "createBuffer() on WebGPUDevice."); >- >-</script> >-</body> >diff --git a/LayoutTests/webgpu/depth-enabled-triangle-strip.html b/LayoutTests/webgpu/depth-enabled-triangle-strip.html >index 03e6a72f571715101c522a7b70e6b9adf947dc0f..fe6936587f4746cb9e82bb34b6bb794773854ce1 100644 >--- a/LayoutTests/webgpu/depth-enabled-triangle-strip.html >+++ b/LayoutTests/webgpu/depth-enabled-triangle-strip.html >@@ -44,21 +44,22 @@ fragment float4 fragment_main(VertexOut v [[stage_in]]) > } > ` > >-function createVertexBuffer(device) { >+async function createVertexBuffer(device) { > const bufferSize = 4 * 4 * 4; >- const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE }); >+ const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE }); > > let floatArray = new Float32Array(buffer.mapping); >- >- const vertices = [ >- // float4 xyzw >- -1, 1, 0, 1, >- -1, -1, 0, 1, >- 1, 1, 0, 1, >- 1, -1, 0, 1 >- ]; >- >- floatArray.set(vertices); >+ buffer.mapWriteAsync().then(mapping => { >+ let mappedArray = new Float32Array(mapping); >+ mappedArray.set([ >+ // float4 xyzw >+ -1, 1, 0, 1, >+ -1, -1, 0, 1, >+ 1, 1, 0, 1, >+ 1, -1, 0, 1 >+ ]); >+ buffer.unmap(); >+ }); > > return buffer; > } >@@ -86,7 +87,7 @@ async function test() { > const context = createBasicContext(canvas, device); > // FIXME: Replace with non-MSL shaders. > const shaderModule = device.createShaderModule({ code: shaderCode }); >- const vertexBuffer = createVertexBuffer(device); >+ const vertexBuffer = await createVertexBuffer(device); > const inputStateDescriptor = createInputStateDescriptor(); > const depthStateDescriptor = createBasicDepthStateDescriptor(); > const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor, depthStateDescriptor); >diff --git a/LayoutTests/webgpu/map-write-buffers-expected.txt b/LayoutTests/webgpu/map-write-buffers-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..7d654058042b5312319b633bfab511743a809bfe >--- /dev/null >+++ b/LayoutTests/webgpu/map-write-buffers-expected.txt >@@ -0,0 +1,6 @@ >+ >+PASS Map write, unmap, and destroy a GPUBuffer. >+PASS Reject a map write on a buffer not created with MAP_WRITE usage. >+PASS Reject a map write on a mapped GPUBuffer. >+PASS Reject a pending map write if GPUBuffer is unmapped. >+ >diff --git a/LayoutTests/webgpu/map-write-buffers.html b/LayoutTests/webgpu/map-write-buffers.html >new file mode 100644 >index 0000000000000000000000000000000000000000..490e6309a8d6c9aa44c59af32b5a3df60fce2f55 >--- /dev/null >+++ b/LayoutTests/webgpu/map-write-buffers.html >@@ -0,0 +1,79 @@ >+<!DOCTYPE html><!-- webkit-test-runner [ experimental:WebGPUEnabled=true ] --> >+<meta charset=utf-8> >+<title>Get the WebGPUDevice, create a WebGPUBuffer, and write vertex data to it.</title> >+<body> >+<script src="../resources/testharness.js"></script> >+<script src="../resources/testharnessreport.js"></script> >+<script src="js/webgpu-functions.js"></script> >+<script> >+ >+async function runTests() { >+ const device = await getBasicDevice(); >+ >+ // Basic mapWriteAsync functionality >+ promise_test(async () => { >+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE }); >+ assert_true(buffer instanceof WebGPUBuffer, "createBuffer returned a WebGPUBuffer"); >+ >+ let arrayBuffer = await buffer.mapWriteAsync(); >+ >+ assert_true(arrayBuffer instanceof ArrayBuffer, "first mapWriteAsync resolved successfully"); >+ >+ let array = new Float32Array(arrayBuffer); >+ assert_equals(array[0], 0, "mapWriteAsync zeroed out storage"); >+ array.set([1, 2, 3, 4]); >+ >+ buffer.unmap(); >+ >+ const promise = buffer.mapWriteAsync(); // This will eventually reject due to buffer.destroy() >+ >+ buffer.destroy(); >+ >+ await promise.then(() => { >+ assert_unreached("Buffer was destroyed!"); >+ }, () => {}); >+ >+ }, "Map write, unmap, and destroy a GPUBuffer."); >+ >+ /* Basic validation */ >+ // FIXME: Test invalid combinations of GPUBufferUsage after implementing error handling. >+ >+ promise_test(async () => { >+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_READ }); >+ >+ await buffer.mapWriteAsync().then(() => { >+ assert_unreached("Buffer was not created with MAP_WRITE!"); >+ }, () => {}); >+ }, "Reject a map write on a buffer not created with MAP_WRITE usage."); >+ >+ /* Extended unmap/destroy and promise settling testing */ >+ >+ promise_test(async () => { >+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE }); >+ >+ buffer.mapWriteAsync().then(() => { >+ buffer.unmap(); >+ }, () => { >+ assert_unreached(); >+ }); >+ >+ await buffer.mapWriteAsync().then(() => { >+ assert_unreached("Map operation was invalid!"); // buffer was still in mapped state during promise creation >+ }, () => {}); >+ }, "Reject a map write on a mapped GPUBuffer."); >+ >+ promise_test(async () => { >+ const buffer = device.createBuffer({ size: 16, usage: GPUBufferUsage.MAP_WRITE }); >+ >+ const promise = buffer.mapWriteAsync(); >+ buffer.unmap(); >+ >+ await promise.then(() => { >+ assert_unreached("Buffer was unmapped!"); // buffer was unmapped, which rejects pending promises >+ },() => {}); >+ }, "Reject a pending map write if GPUBuffer is unmapped."); >+} >+ >+runTests(); >+</script> >+</body> >diff --git a/LayoutTests/webgpu/vertex-buffer-triangle-strip.html b/LayoutTests/webgpu/vertex-buffer-triangle-strip.html >index 86f923f49520a6775e36785edaec14c3cb9f7cb7..5090ad808f40aa6ac1b616f166fb1dd07e698f43 100644 >--- a/LayoutTests/webgpu/vertex-buffer-triangle-strip.html >+++ b/LayoutTests/webgpu/vertex-buffer-triangle-strip.html >@@ -38,23 +38,21 @@ fragment float4 fragment_main(VertexOut v [[stage_in]]) > } > ` > >-function createVertexBuffer(device) { >+async function createVertexBuffer(device) { > const bufferSize = 4 * 5 * 4; >- const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.MAP_WRITE }); >+ const buffer = device.createBuffer({ size: bufferSize, usage: GPUBufferUsage.VERTEX | GPUBufferUsage.MAP_WRITE }); > >- let floatArray = new Float32Array(buffer.mapping); >- >- const vertices = [ >- // float4 xyzw, float g >- -1, 1, 0, 1, 1, >- -1, -1, 0, 1, 1, >- 1, 1, 0, 1, 1, >- 1, -1, 0, 1, 1 >- ]; >- >- for (let i = 0; i < vertices.length; ++i) { >- floatArray[i] = vertices[i]; >- } >+ buffer.mapWriteAsync().then(mapping => { >+ let mappedArray = new Float32Array(mapping); >+ mappedArray.set([ >+ // float4 xyzw, float g >+ -1, 1, 0, 1, 1, >+ -1, -1, 0, 1, 1, >+ 1, 1, 0, 1, 1, >+ 1, -1, 0, 1, 1 >+ ]); >+ buffer.unmap(); >+ }); > > return buffer; > } >@@ -87,7 +85,7 @@ async function test() { > const context = createBasicContext(canvas, device); > // FIXME: Replace with non-MSL shaders. > const shaderModule = device.createShaderModule({ code: shaderCode }); >- const vertexBuffer = createVertexBuffer(device); >+ const vertexBuffer = await createVertexBuffer(device); > const inputStateDescriptor = createInputStateDescriptor(); > const pipeline = createBasicPipeline(shaderModule, device, null, inputStateDescriptor); > const commandBuffer = device.createCommandBuffer();
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 194665
:
362052
|
362062
|
362185
|
362187
|
362189
|
362198
|
362572
|
362667
|
362786
|
362792
|
362836