Unreviewed, rolling out r249369.
[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     [mtlArgument setDataType:dataType];
88     [mtlArgument setIndex:index];
89     return mtlArgument;
90 }
91
92 RefPtr<GPUBindGroupLayout> GPUBindGroupLayout::tryCreate(const GPUDevice& device, const GPUBindGroupLayoutDescriptor& descriptor)
93 {
94     if (!device.platformDevice()) {
95         LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Invalid MTLDevice!");
96         return nullptr;
97     }
98
99     ArgumentArray vertexArgs, fragmentArgs, computeArgs, vertexLengths, fragmentLengths, computeLengths;
100     BindingsMapType bindingsMap;
101
102     unsigned internalName = 0;
103     unsigned internalLengthBase = descriptor.bindings.size();
104     for (const auto& binding : descriptor.bindings) {
105         Optional<unsigned> extraIndex;
106         auto internalDetails = ([&]() -> GPUBindGroupLayout::InternalBindingDetails {
107             switch (binding.type) {
108             case GPUBindingType::UniformBuffer:
109                 extraIndex = internalLengthBase++;
110                 return GPUBindGroupLayout::UniformBuffer { *extraIndex };
111             case GPUBindingType::DynamicUniformBuffer:
112                 extraIndex = internalLengthBase++;
113                 return GPUBindGroupLayout::DynamicUniformBuffer { *extraIndex };
114             case GPUBindingType::Sampler:
115                 return GPUBindGroupLayout::Sampler { };
116             case GPUBindingType::SampledTexture:
117                 return GPUBindGroupLayout::SampledTexture { };
118             case GPUBindingType::StorageBuffer:
119                 extraIndex = internalLengthBase++;
120                 return GPUBindGroupLayout::StorageBuffer { *extraIndex };
121             default:
122                 ASSERT(binding.type == GPUBindingType::DynamicStorageBuffer);
123                 extraIndex = internalLengthBase++;
124                 return GPUBindGroupLayout::DynamicStorageBuffer { *extraIndex };
125             }
126         })();
127         Binding bindingDetails = { binding, internalName++, WTFMove(internalDetails) };
128         if (!bindingsMap.add(binding.binding, bindingDetails)) {
129             LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Duplicate binding %u found in GPUBindGroupLayoutDescriptor!", binding.binding);
130             return nullptr;
131         }
132
133         RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeForBindingType(binding.type), bindingDetails.internalName);
134
135         if (!mtlArgument) {
136             LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding);
137             return nullptr;
138         }
139
140         auto addIndices = [&](ArgumentArray& args, ArgumentArray& lengths) -> bool {
141             appendArgumentToArray(args, mtlArgument);
142             if (extraIndex) {
143                 RetainPtr<MTLArgumentDescriptor> mtlArgument = argumentDescriptor(MTLDataTypeUInt2, *extraIndex);
144                 if (!mtlArgument) {
145                     LOG(WebGPU, "GPUBindGroupLayout::tryCreate(): Unable to create MTLArgumentDescriptor for binding %u!", binding.binding);
146                     return false;
147                 }
148                 appendArgumentToArray(lengths, mtlArgument);
149             }
150             return true;
151         };
152         if ((binding.visibility & GPUShaderStageBit::Flags::Vertex) && !addIndices(vertexArgs, vertexLengths))
153             return nullptr;
154         if ((binding.visibility & GPUShaderStageBit::Flags::Fragment) && !addIndices(fragmentArgs, fragmentLengths))
155             return nullptr;
156         if ((binding.visibility & GPUShaderStageBit::Flags::Compute) && !addIndices(computeArgs, computeLengths))
157             return nullptr;
158     }
159
160     BEGIN_BLOCK_OBJC_EXCEPTIONS;
161     [vertexArgs addObjectsFromArray:vertexLengths.get()];
162     [fragmentArgs addObjectsFromArray:fragmentLengths.get()];
163     [computeArgs addObjectsFromArray:computeLengths.get()];
164     END_BLOCK_OBJC_EXCEPTIONS;
165
166     RetainPtr<MTLArgumentEncoder> vertex, fragment, compute;
167
168     if (vertexArgs && !(vertex = tryCreateMtlArgumentEncoder(device, vertexArgs)))
169         return nullptr;
170     if (fragmentArgs && !(fragment = tryCreateMtlArgumentEncoder(device, fragmentArgs)))
171         return nullptr;
172     if (computeArgs && !(compute = tryCreateMtlArgumentEncoder(device, computeArgs)))
173         return nullptr;
174
175     return adoptRef(new GPUBindGroupLayout(WTFMove(bindingsMap), WTFMove(vertex), WTFMove(fragment), WTFMove(compute)));
176 }
177
178 GPUBindGroupLayout::GPUBindGroupLayout(BindingsMapType&& bindingsMap, RetainPtr<MTLArgumentEncoder>&& vertex, RetainPtr<MTLArgumentEncoder>&& fragment, RetainPtr<MTLArgumentEncoder>&& compute)
179     : m_vertexEncoder(WTFMove(vertex))
180     , m_fragmentEncoder(WTFMove(fragment))
181     , m_computeEncoder(WTFMove(compute))
182     , m_bindingsMap(WTFMove(bindingsMap))
183 {
184 }
185
186 } // namespace WebCore
187
188 #endif // ENABLE(WEBGPU)