blob: 783c0130ba69b24387cd817eee2c85cc306389a7 [file] [log] [blame]
/*
* Copyright (C) 2018 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.
*/
#import "config.h"
#import "GPUTexture.h"
#if ENABLE(WEBGPU)
#import "GPUDevice.h"
#import "GPUTextureDescriptor.h"
#import "GPUUtils.h"
#import "Logging.h"
#import <Metal/Metal.h>
#import <wtf/BlockObjCExceptions.h>
#import <wtf/Optional.h>
namespace WebCore {
static MTLTextureType mtlTextureTypeForGPUTextureDescriptor(const GPUTextureDescriptor& descriptor)
{
switch (descriptor.dimension) {
case GPUTextureDimension::_1d:
return (descriptor.arrayLayerCount == 1) ? MTLTextureType1D : MTLTextureType1DArray;
case GPUTextureDimension::_2d: {
if (descriptor.arrayLayerCount == 1)
return (descriptor.sampleCount == 1) ? MTLTextureType2D : MTLTextureType2DMultisample;
return MTLTextureType2DArray;
}
case GPUTextureDimension::_3d:
return MTLTextureType3D;
}
}
static Optional<MTLTextureUsage> mtlTextureUsageForGPUTextureUsageFlags(OptionSet<GPUTextureUsage::Flags> flags, const char* const functionName)
{
#if LOG_DISABLED
UNUSED_PARAM(functionName);
#endif
if (flags.containsAny({ GPUTextureUsage::Flags::TransferSource, GPUTextureUsage::Flags::Sampled }) && (flags & GPUTextureUsage::Flags::Storage)) {
LOG(WebGPU, "%s: Texture cannot have both STORAGE and a read-only usage!", functionName);
return WTF::nullopt;
}
if (flags & GPUTextureUsage::Flags::OutputAttachment) {
if (flags.containsAny({ GPUTextureUsage::Flags::Storage, GPUTextureUsage::Flags::Sampled })) {
LOG(WebGPU, "%s: Texture cannot have OUTPUT_ATTACHMENT usage with STORAGE or SAMPLED usages!", functionName);
return WTF::nullopt;
}
return MTLTextureUsageRenderTarget | MTLTextureUsagePixelFormatView;
}
if (flags & GPUTextureUsage::Flags::Storage)
return MTLTextureUsageShaderWrite | MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
if (flags & GPUTextureUsage::Flags::Sampled)
return MTLTextureUsageShaderRead | MTLTextureUsagePixelFormatView;
return MTLTextureUsageUnknown;
}
#if !PLATFORM(MAC)
static MTLStorageMode storageModeForPixelFormatAndSampleCount(MTLPixelFormat format, unsigned samples)
{
// Depth, Stencil, DepthStencil, and Multisample textures must be allocated with the MTLStorageModePrivate resource option.
if (format == MTLPixelFormatDepth32Float_Stencil8 || samples > 1)
return MTLStorageModePrivate;
return MTLStorageModeShared;
}
#endif
static RetainPtr<MTLTextureDescriptor> tryCreateMtlTextureDescriptor(const char* const functionName, const GPUTextureDescriptor& descriptor, OptionSet<GPUTextureUsage::Flags> usage)
{
RetainPtr<MTLTextureDescriptor> mtlDescriptor;
BEGIN_BLOCK_OBJC_EXCEPTIONS;
mtlDescriptor = adoptNS([MTLTextureDescriptor new]);
END_BLOCK_OBJC_EXCEPTIONS;
if (!mtlDescriptor) {
LOG(WebGPU, "%s: Unable to create new MTLTextureDescriptor!", functionName);
return nullptr;
}
// FIXME: Add more validation as constraints are added to spec.
auto pixelFormat = static_cast<MTLPixelFormat>(platformTextureFormatForGPUTextureFormat(descriptor.format));
auto mtlUsage = mtlTextureUsageForGPUTextureUsageFlags(usage, functionName);
if (!mtlUsage)
return nullptr;
#if PLATFORM(MAC)
auto storageMode = MTLStorageModePrivate;
#else
auto storageMode = storageModeForPixelFormatAndSampleCount(pixelFormat, descriptor.sampleCount);
#endif
BEGIN_BLOCK_OBJC_EXCEPTIONS;
[mtlDescriptor setWidth:descriptor.size.width];
[mtlDescriptor setHeight:descriptor.size.height];
[mtlDescriptor setDepth:descriptor.size.depth];
[mtlDescriptor setArrayLength:descriptor.arrayLayerCount];
[mtlDescriptor setMipmapLevelCount:descriptor.mipLevelCount];
[mtlDescriptor setSampleCount:descriptor.sampleCount];
[mtlDescriptor setTextureType:mtlTextureTypeForGPUTextureDescriptor(descriptor)];
[mtlDescriptor setPixelFormat:pixelFormat];
[mtlDescriptor setUsage:*mtlUsage];
[mtlDescriptor setStorageMode:storageMode];
END_BLOCK_OBJC_EXCEPTIONS;
return mtlDescriptor;
}
RefPtr<GPUTexture> GPUTexture::tryCreate(const GPUDevice& device, const GPUTextureDescriptor& descriptor)
{
const char* const functionName = "GPUTexture::tryCreate()";
if (!device.platformDevice()) {
LOG(WebGPU, "%s: Invalid GPUDevice!", functionName);
return nullptr;
}
auto usage = OptionSet<GPUTextureUsage::Flags>::fromRaw(descriptor.usage);
auto mtlDescriptor = tryCreateMtlTextureDescriptor(functionName, descriptor, usage);
if (!mtlDescriptor)
return nullptr;
RetainPtr<MTLTexture> mtlTexture;
BEGIN_BLOCK_OBJC_EXCEPTIONS;
mtlTexture = adoptNS([device.platformDevice() newTextureWithDescriptor:mtlDescriptor.get()]);
END_BLOCK_OBJC_EXCEPTIONS;
if (!mtlTexture) {
LOG(WebGPU, "%s: Unable to create MTLTexture!", functionName);
return nullptr;
}
return adoptRef(new GPUTexture(WTFMove(mtlTexture), usage));
}
Ref<GPUTexture> GPUTexture::create(RetainPtr<MTLTexture>&& texture, OptionSet<GPUTextureUsage::Flags> usage)
{
return adoptRef(*new GPUTexture(WTFMove(texture), usage));
}
GPUTexture::GPUTexture(RetainPtr<MTLTexture>&& texture, OptionSet<GPUTextureUsage::Flags> usage)
: m_platformTexture(WTFMove(texture))
, m_usage(usage)
{
}
RefPtr<GPUTexture> GPUTexture::tryCreateDefaultTextureView()
{
RetainPtr<MTLTexture> texture;
BEGIN_BLOCK_OBJC_EXCEPTIONS;
texture = adoptNS([m_platformTexture newTextureViewWithPixelFormat:m_platformTexture.get().pixelFormat]);
END_BLOCK_OBJC_EXCEPTIONS;
if (!texture) {
LOG(WebGPU, "GPUTexture::createDefaultTextureView(): Unable to create MTLTexture view!");
return nullptr;
}
return GPUTexture::create(WTFMove(texture), m_usage);
}
} // namespace WebCore
#endif // ENABLE(WEBGPU)