1/*
2 * Copyright (C) 2019 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#include "config.h"
27#include "WebGPUBindGroupDescriptor.h"
28
29#if ENABLE(WEBGPU)
30
31#include "GPUBindGroupDescriptor.h"
32#include "GPUBuffer.h"
33#include "Logging.h"
34#include <wtf/Variant.h>
35
36namespace WebCore {
37
38static bool validateBufferBindingType(const GPUBuffer* buffer, const GPUBindGroupLayoutBinding& binding, const char* const functionName)
39{
40#if LOG_DISABLED
41 UNUSED_PARAM(functionName);
42#endif
43
44 switch (binding.type) {
45 case GPUBindingType::UniformBuffer:
46 if (!buffer->isUniform()) {
47 LOG(WebGPU, "%s: GPUBuffer resource for binding %u does not have UNIFORM usage!", functionName, binding.binding);
48 return false;
49 }
50 return true;
51 case GPUBindingType::StorageBuffer:
52 if (!buffer->isStorage()) {
53 LOG(WebGPU, "%s: GPUBuffer resource for binding %u does not have STORAGE usage!", functionName, binding.binding);
54 return false;
55 }
56 return true;
57 default:
58 LOG(WebGPU, "%s: Layout binding %u is not a buffer-type resource!", functionName, binding.binding);
59 return false;
60 }
61}
62
63Optional<GPUBindGroupDescriptor> WebGPUBindGroupDescriptor::tryCreateGPUBindGroupDescriptor() const
64{
65 const char* const functionName = "GPUDevice::createBindGroup()";
66
67 if (!layout || !layout->bindGroupLayout()) {
68 LOG(WebGPU, "%s: Invalid GPUBindGroupLayout!", functionName);
69 return WTF::nullopt;
70 }
71
72 if (bindings.size() != layout->bindGroupLayout()->bindingsMap().size()) {
73 LOG(WebGPU, "%s: Mismatched number of GPUBindGroupLayoutBindings and GPUBindGroupBindings!", functionName);
74 return WTF::nullopt;
75 }
76
77 auto layoutMap = layout->bindGroupLayout()->bindingsMap();
78
79 Vector<GPUBindGroupBinding> bindGroupBindings;
80 bindGroupBindings.reserveCapacity(bindings.size());
81
82 for (const auto& binding : bindings) {
83 auto iterator = layoutMap.find(binding.binding);
84 if (iterator == layoutMap.end()) {
85 LOG(WebGPU, "%s: GPUBindGroupLayoutBinding %u not found in GPUBindGroupLayout!", functionName, binding.binding);
86 return WTF::nullopt;
87 }
88
89 const auto layoutBinding = iterator->value;
90
91 auto bindingResourceVisitor = WTF::makeVisitor([](const RefPtr<WebGPUSampler>& sampler) -> Optional<GPUBindingResource> {
92 if (!sampler)
93 return WTF::nullopt;
94 auto gpuSampler = sampler->sampler();
95 if (!gpuSampler)
96 return WTF::nullopt;
97
98 return static_cast<GPUBindingResource>(makeRef(*gpuSampler));
99 }, [](const RefPtr<WebGPUTextureView>& view) -> Optional<GPUBindingResource> {
100 if (!view)
101 return WTF::nullopt;
102 auto texture = view->texture();
103 if (!texture)
104 return WTF::nullopt;
105
106 return static_cast<GPUBindingResource>(makeRef(*texture));
107 }, [&layoutBinding, functionName] (WebGPUBufferBinding bufferBinding) -> Optional<GPUBindingResource> {
108 if (!bufferBinding.buffer)
109 return WTF::nullopt;
110 auto buffer = bufferBinding.buffer->buffer();
111 if (!buffer)
112 return WTF::nullopt;
113
114 if (!validateBufferBindingType(buffer, layoutBinding.externalBinding, functionName))
115 return WTF::nullopt;
116
117 return static_cast<GPUBindingResource>(GPUBufferBinding { makeRef(*buffer), bufferBinding.offset, bufferBinding.size });
118 });
119
120 auto bindingResource = WTF::visit(bindingResourceVisitor, binding.resource);
121 if (!bindingResource) {
122 LOG(WebGPU, "%s: Invalid resource for binding %u!", functionName, layoutBinding.externalBinding.binding);
123 return WTF::nullopt;
124 }
125
126 bindGroupBindings.uncheckedAppend(GPUBindGroupBinding { binding.binding, WTFMove(bindingResource.value()) });
127 }
128
129 return GPUBindGroupDescriptor { makeRef(*layout->bindGroupLayout()), WTFMove(bindGroupBindings) };
130}
131
132} // namespace WebCore
133
134#endif // ENABLE(WEBGPU)
135