blob: 7d5b1654eed076c1760268df0026db7220657b8c [file] [log] [blame]
/*
* Copyright (C) 2021 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 "WebGPUAdapterImpl.h"
#if HAVE(WEBGPU_IMPLEMENTATION)
#include "WebGPUConvertToBackingContext.h"
#include "WebGPUDeviceImpl.h"
#include <WebGPU/WebGPUExt.h>
namespace PAL::WebGPU {
static String adapterName(WGPUAdapter adapter)
{
WGPUAdapterProperties properties;
wgpuAdapterGetProperties(adapter, &properties);
return properties.name;
}
static Ref<SupportedFeatures> supportedFeatures(WGPUAdapter adapter)
{
Vector<String> result;
for (size_t i = 0; ; ++i) {
auto feature = wgpuAdapterGetFeatureAtIndex(adapter, i);
if (feature == WGPUFeatureName_Undefined)
break;
switch (static_cast<uint>(feature)) {
case WGPUFeatureName_DepthClamping:
break;
case WGPUFeatureName_Depth24UnormStencil8:
result.append("depth24unorm-stencil8"_s);
break;
case WGPUFeatureName_Depth32FloatStencil8:
result.append("depth32float-stencil8"_s);
break;
case WGPUFeatureName_TimestampQuery:
result.append("timestamp-query"_s);
break;
case WGPUFeatureName_PipelineStatisticsQuery:
result.append("pipeline-statistics-query"_s);
break;
case WGPUFeatureName_TextureCompressionBC:
result.append("texture-compression-bc"_s);
break;
case WGPUFeatureName_DepthClipControl:
result.append("depth-clip-control"_s);
break;
case WGPUFeatureName_IndirectFirstInstance:
result.append("indirect-first-instance"_s);
break;
case WGPUFeatureName_TextureCompressionETC2:
result.append("texture-compression-etc2"_s);
break;
case WGPUFeatureName_TextureCompressionASTC:
result.append("texture-compression-astc"_s);
break;
default:
break;
}
}
return SupportedFeatures::create(WTFMove(result));
}
static Ref<SupportedLimits> supportedLimits(WGPUAdapter adapter)
{
WGPUSupportedLimits limits;
limits.nextInChain = nullptr;
auto result = wgpuAdapterGetLimits(adapter, &limits);
ASSERT_UNUSED(result, result);
return SupportedLimits::create(
limits.limits.maxTextureDimension1D,
limits.limits.maxTextureDimension2D,
limits.limits.maxTextureDimension3D,
limits.limits.maxTextureArrayLayers,
limits.limits.maxBindGroups,
limits.limits.maxDynamicUniformBuffersPerPipelineLayout,
limits.limits.maxDynamicStorageBuffersPerPipelineLayout,
limits.limits.maxSampledTexturesPerShaderStage,
limits.limits.maxSamplersPerShaderStage,
limits.limits.maxStorageBuffersPerShaderStage,
limits.limits.maxStorageTexturesPerShaderStage,
limits.limits.maxUniformBuffersPerShaderStage,
limits.limits.maxUniformBufferBindingSize,
limits.limits.maxStorageBufferBindingSize,
limits.limits.minUniformBufferOffsetAlignment,
limits.limits.minStorageBufferOffsetAlignment,
limits.limits.maxVertexBuffers,
limits.limits.maxVertexAttributes,
limits.limits.maxVertexBufferArrayStride,
limits.limits.maxInterStageShaderComponents,
limits.limits.maxComputeWorkgroupStorageSize,
limits.limits.maxComputeInvocationsPerWorkgroup,
limits.limits.maxComputeWorkgroupSizeX,
limits.limits.maxComputeWorkgroupSizeY,
limits.limits.maxComputeWorkgroupSizeZ,
limits.limits.maxComputeWorkgroupsPerDimension);
}
static bool isFallbackAdapter(WGPUAdapter adapter)
{
WGPUAdapterProperties properties;
wgpuAdapterGetProperties(adapter, &properties);
return properties.adapterType == WGPUAdapterType_CPU;
}
AdapterImpl::AdapterImpl(WGPUAdapter adapter, ConvertToBackingContext& convertToBackingContext)
: Adapter(adapterName(adapter), supportedFeatures(adapter), supportedLimits(adapter), WebGPU::isFallbackAdapter(adapter))
, m_backing(adapter)
, m_convertToBackingContext(convertToBackingContext)
{
}
AdapterImpl::~AdapterImpl()
{
wgpuAdapterRelease(m_backing);
}
void requestDeviceCallback(WGPURequestDeviceStatus status, WGPUDevice device, const char* message, void* userdata)
{
auto adapter = adoptRef(*static_cast<AdapterImpl*>(userdata)); // adoptRef is balanced by leakRef in requestDevice() below. We have to do this because we're using a C API with no concept of reference counting or blocks.
adapter->requestDeviceCallback(status, device, message);
}
void AdapterImpl::requestDevice(const DeviceDescriptor& descriptor, WTF::Function<void(Ref<Device>&&)>&& callback)
{
Ref protectedThis(*this);
auto label = descriptor.label.utf8();
WGPUDeviceDescriptorLabel backingDescriptorLabel {
{
nullptr,
static_cast<WGPUSType>(WGPUSType_DeviceDescriptorLabel),
},
nullptr,
label.data()
};
auto features = descriptor.requiredFeatures.map([this] (auto featureName) {
return m_convertToBackingContext->convertToBacking(featureName);
});
WGPURequiredLimits limits {
nullptr, {
0, // maxTextureDimension1D
0, // maxTextureDimension2D
0, // maxTextureDimension3D
0, // maxTextureArrayLayers
0, // maxBindGroups
0, // maxDynamicUniformBuffersPerPipelineLayout
0, // maxDynamicStorageBuffersPerPipelineLayout
0, // maxSampledTexturesPerShaderStage
0, // maxSamplersPerShaderStage
0, // maxStorageBuffersPerShaderStage
0, // maxStorageTexturesPerShaderStage
0, // maxUniformBuffersPerShaderStage
0, // maxUniformBufferBindingSize
0, // maxStorageBufferBindingSize
0, // minUniformBufferOffsetAlignment
0, // minStorageBufferOffsetAlignment
0, // maxVertexBuffers
0, // maxVertexAttributes
0, // maxVertexBufferArrayStride
0, // maxInterStageShaderComponents
0, // maxComputeWorkgroupStorageSize
0, // maxComputeInvocationsPerWorkgroup
0, // maxComputeWorkgroupSizeX
0, // maxComputeWorkgroupSizeY
0, // maxComputeWorkgroupSizeZ
0, // maxComputeWorkgroupsPerDimension
},
};
WGPUDeviceDescriptor backingDescriptor {
&backingDescriptorLabel.header,
static_cast<uint32_t>(features.size()),
features.data(),
&limits,
};
m_callbacks.append(WTFMove(callback));
wgpuAdapterRequestDevice(m_backing, &backingDescriptor, &WebGPU::requestDeviceCallback, &protectedThis.leakRef()); // leakRef is balanced by adoptRef in requestDeviceCallback() above. We have to do this because we're using a C API with no concept of reference counting or blocks.
}
void AdapterImpl::requestDeviceCallback(WGPURequestDeviceStatus, WGPUDevice device, const char* message)
{
UNUSED_PARAM(message);
auto callback = m_callbacks.takeFirst();
callback(DeviceImpl::create(device, Ref { features() }, Ref { limits() }, m_convertToBackingContext));
}
} // namespace PAL::WebGPU
#endif // HAVE(WEBGPU_IMPLEMENTATION)