a26badf300a46c6a46db2fd54f65609beb98d935
[WebKit-https.git] / Source / WebCore / platform / graphics / gpu / cocoa / GPUBindGroupLayoutMetal.mm
1 /*
2  * Copyright (C) 2018 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 #import "config.h"
27 #import "GPUBindGroupLayout.h"
28
29 #if ENABLE(WEBGPU)
30
31 #import "GPUDevice.h"
32 #import "Logging.h"
33
34 #import <Foundation/Foundation.h>
35 #import <Metal/Metal.h>
36 #import <wtf/BlockObjCExceptions.h>
37
38 namespace WebCore {
39
40 static MTLDataType MTLDataTypeForBindingType(GPUBindingType type)
41 {
42     switch (type) {
43     case GPUBindingType::Sampler:
44         return MTLDataTypeSampler;
45     case GPUBindingType::SampledTexture:
46         return MTLDataTypeTexture;
47     case GPUBindingType::UniformBuffer:
48     case GPUBindingType::DynamicUniformBuffer:
49     case GPUBindingType::StorageBuffer:
50     case GPUBindingType::DynamicStorageBuffer:
51         return MTLDataTypePointer;
52     }
53 }
54
55 using ArgumentArray = RetainPtr<NSMutableArray<MTLArgumentDescriptor *>>;
56 static void appendArgumentToArray(ArgumentArray& array, RetainPtr<MTLArgumentDescriptor> argument)
57 {
58     BEGIN_BLOCK_OBJC_EXCEPTIONS;
59     if (!array)
60         array = adoptNS([[NSMutableArray alloc] initWithObjects:argument.get(), nil]);
61     else
62         [array addObject:argument.get()];
63     END_BLOCK_OBJC_EXCEPTIONS;
64 }
65
66 static RetainPtr<MTLArgumentEncoder> tryCreateMtlArgumentEncoder(const GPUDevice& device, ArgumentArray array)
67 {
68     RetainPtr<MTLArgumentEncoder> encoder;
69
70     BEGIN_BLOCK_OBJC_EXCEPTIONS;
71     encoder = adoptNS([device.platformDevice() newArgumentEncoderWithArguments:array.get()]);
72     END_BLOCK_OBJC_EXCEPTIONS;
73     if (!encoder) {
74         LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentEncoder!");
75         return nullptr;
76     }
77     return encoder;
78 };
79
80 static RetainPtr<MTLArgumentDescriptor> argumentDescriptor(MTLDataType dataType, NSUInteger index)
81 {
82     RetainPtr<MTLArgumentDescriptor> mtlArgument;
83     BEGIN_BLOCK_OBJC_EXCEPTIONS;
84     mtlArgument = adoptNS([MTLArgumentDescriptor new]);
85     END_BLOCK_OBJC_EXCEPTIONS;
86
87     // FIXME: https://bugs.webkit.org/show_bug.cgi?id=201384 This needs to set the "textureType" field
88     [mtlArgument setDataType:dataType];
89     [mtlArgument setIndex:index];
90     return mtlArgument;
91 }
92
93 RefPtr<GPUBindGroupLayout> GPUBindGroupLayout::tryCreate(const GPUDevice& device, const GPUBindGroupLayoutDescriptor& descriptor)
94 {
95     if (!device.platformDevice()) {
96         LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Invalid MTLDevice!");
97         return nullptr;
98     }
99
100     ArgumentArray vertexArgs, fragmentArgs, computeArgs, vertexLengths, fragmentLengths, computeLengths;
101     BindingsMapType bindingsMap;
102
103     unsigned internalName = 0;
104     unsigned internalLengthBase = descriptor.bindings.size();
105     for (const auto& binding : descriptor.bindings) {
106         Optional<unsigned> extraIndex;
107         auto internalDetails = ([&]() -> GPUBindGroupLayout::InternalBindingDetails {
108             switch (binding.type) {
109             case GPUBindingType::UniformBuffer:
110                 extraIndex = internalLengthBase++;
111                 return GPUBindGroupLayout::UniformBuffer { *extraIndex };
112             case GPUBindingType::DynamicUniformBuffer:
113                 extraIndex = internalLengthBase++;
114                 return GPUBindGroupLayout::DynamicUniformBuffer { *extraIndex };
115             case GPUBindingType::Sampler:
116                 return GPUBindGroupLayout::Sampler { };
117             case GPUBindingType::SampledTexture:
118                 return GPUBindGroupLayout::SampledTexture { };
119             case GPUBindingType::StorageBuffer:
120                 extraIndex = internalLengthBase++;
121                 return GPUBindGroupLayout::StorageBuffer { *extraIndex };
122             default:
123                 ASSERT(binding.type == GPUBindingType::DynamicStorageBuffer);
124                 extraIndex = internalLengthBase++;
125                 return GPUBindGroupLayout::DynamicStorageBuffer { *extraIndex };
126             }
127         })();
128         Binding bindingDetails = { binding, internalName++, WTFMove(internalDetails) };
129         if (!bindingsMap.add(binding.binding, bindingDetails)) {
130             LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Duplicate binding %u found in GPUBindGroupLayoutDescriptor!", binding.binding);
131             return nullptr;
132         }
133
134         RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeForBindingType(binding.type), bindingDetails.internalName);
135
136         if (!mtlArgument) {
137             LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding);
138             return nullptr;
139         }
140
141         auto addIndices = [&](ArgumentArray& args, ArgumentArray& lengths) -> bool {
142             appendArgumentToArray(args, mtlArgument);
143             if (extraIndex) {
144                 RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeUInt2, *extraIndex);
145                 if (!mtlArgument) {
146                     LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding);
147                     return false;
148                 }
149                 appendArgumentToArray(lengths, mtlArgument);
150             }
151             return true;
152         };
153         if ((binding.visibility & GPUShaderStageBit::Flags::Vertex) && !addIndices(vertexArgs, vertexLengths))
154             return nullptr;
155         if ((binding.visibility & GPUShaderStageBit::Flags::Fragment) && !addIndices(fragmentArgs, fragmentLengths))
156             return nullptr;
157         if ((binding.visibility & GPUShaderStageBit::Flags::Compute) && !addIndices(computeArgs, computeLengths))
158             return nullptr;
159     }
160
161     BEGIN_BLOCK_OBJC_EXCEPTIONS;
162     [vertexArgs addObjectsFromArray:vertexLengths.get()];
163     [fragmentArgs addObjectsFromArray:fragmentLengths.get()];
164     [computeArgs addObjectsFromArray:computeLengths.get()];
165     END_BLOCK_OBJC_EXCEPTIONS;
166
167     RetainPtr<MTLArgumentEncoder> vertex, fragment, compute;
168
169     if (vertexArgs && !(vertex = tryCreateMtlArgumentEncoder(device, vertexArgs)))
170         return nullptr;
171     if (fragmentArgs && !(fragment = tryCreateMtlArgumentEncoder(device, fragmentArgs)))
172         return nullptr;
173     if (computeArgs && !(compute = tryCreateMtlArgumentEncoder(device, computeArgs)))
174         return nullptr;
175
176     return adoptRef(new GPUBindGroupLayout(WTFMove(bindingsMap), WTFMove(vertex), WTFMove(fragment), WTFMove(compute)));
177 }
178
179 GPUBindGroupLayout::GPUBindGroupLayout(BindingsMapType&& bindingsMap, RetainPtr<MTLArgumentEncoder>&& vertex, RetainPtr<MTLArgumentEncoder>&& fragment, RetainPtr<MTLArgumentEncoder>&& compute)
180     : m_vertexEncoder(WTFMove(vertex))
181     , m_fragmentEncoder(WTFMove(fragment))
182     , m_computeEncoder(WTFMove(compute))
183     , m_bindingsMap(WTFMove(bindingsMap))
184 {
185 }
186
187 } // namespace WebCore
188
189 #endif // ENABLE(WEBGPU)