Metal: Wrap NS classes and protocols in NSRef.
This makes refcounting of these objects more automatic to try and prevent leaks or use-after-frees in the future. Also removes operator* from RefBase (and Ref) because it is never used and cannot work in a normal way for ObjectiveC protocols that cannot be dereferenced. Bug: dawn:89 Change-Id: I2e3fbfd638e2ba76d8c563f30bc489a384152552 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/32161 Reviewed-by: Austin Eng <enga@chromium.org> Reviewed-by: Stephen White <senorblanco@chromium.org> Commit-Queue: Corentin Wallez <cwallez@chromium.org>
This commit is contained in:
parent
1805e46a15
commit
0055d95fa7
|
@ -167,6 +167,7 @@ if (is_win || is_linux || is_chromeos || is_mac || is_fuchsia || is_android) {
|
|||
"Log.h",
|
||||
"Math.cpp",
|
||||
"Math.h",
|
||||
"NSRef.h",
|
||||
"PlacementAllocated.h",
|
||||
"Platform.h",
|
||||
"RefBase.h",
|
||||
|
|
|
@ -29,6 +29,7 @@ target_sources(dawn_common PRIVATE
|
|||
"Log.h"
|
||||
"Math.cpp"
|
||||
"Math.h"
|
||||
"NSRef.h"
|
||||
"PlacementAllocated.h"
|
||||
"Platform.h"
|
||||
"RefBase.h"
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
// Copyright 2020 The Dawn Authors
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#ifndef COMMON_NSREF_H_
|
||||
#define COMMON_NSREF_H_
|
||||
|
||||
#include "common/RefBase.h"
|
||||
|
||||
#import <Foundation/NSObject.h>
|
||||
|
||||
#if !defined(__OBJC__)
|
||||
# error "NSRef can only be used in Objective C/C++ code."
|
||||
#endif
|
||||
|
||||
// This file contains smart pointers that automatically reference and release Objective C objects
|
||||
// and prototocals in a manner very similar to Ref<>. Note that NSRef<> and NSPRef's constructor add
|
||||
// a reference to the object by default, so the pattern to get a reference for a newly created
|
||||
// NSObject is the following:
|
||||
//
|
||||
// NSRef<NSFoo> foo = AcquireNSRef([NSFoo alloc]);
|
||||
//
|
||||
// NSRef overloads -> and * but these operators don't work extremely well with Objective C's
|
||||
// features. For example automatic dereferencing when doing the following doesn't work:
|
||||
//
|
||||
// NSFoo* foo;
|
||||
// foo.member = 1;
|
||||
// someVar = foo.member;
|
||||
//
|
||||
// Instead use the message passing syntax:
|
||||
//
|
||||
// NSRef<NSFoo> foo;
|
||||
// [*foo setMember: 1];
|
||||
// someVar = [*foo member];
|
||||
//
|
||||
// Also did you notive the extra '*' in the example above? That's because Objective C's message
|
||||
// passing doesn't automatically call a C++ operator to dereference smart pointers (like -> does) so
|
||||
// we have to dereference manually using '*'. In some cases the extra * or message passing syntax
|
||||
// can get a bit annoying so instead a local "naked" pointer can be borrowed from the NSRef. This
|
||||
// would change the syntax overload in the following:
|
||||
//
|
||||
// NSRef<NSFoo> foo;
|
||||
// [*foo setA:1];
|
||||
// [*foo setB:2];
|
||||
// [*foo setC:3];
|
||||
//
|
||||
// Into (note access to members of ObjC classes referenced via pointer is done with . and not ->):
|
||||
//
|
||||
// NSRef<NSFoo> fooRef;
|
||||
// NSFoo* foo = fooRef.Get();
|
||||
// foo.a = 1;
|
||||
// foo.b = 2;
|
||||
// boo.c = 3;
|
||||
//
|
||||
// Which can be subjectively easier to read.
|
||||
|
||||
template <typename T>
|
||||
struct NSRefTraits {
|
||||
static constexpr T kNullValue = nullptr;
|
||||
static void Reference(T value) {
|
||||
[value retain];
|
||||
}
|
||||
static void Release(T value) {
|
||||
[value release];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class NSRef : public RefBase<T*, NSRefTraits<T*>> {
|
||||
public:
|
||||
using RefBase<T*, NSRefTraits<T*>>::RefBase;
|
||||
|
||||
const T* operator*() const {
|
||||
return this->Get();
|
||||
}
|
||||
|
||||
T* operator*() {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NSRef<T> AcquireNSRef(T* pointee) {
|
||||
NSRef<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
// This is a RefBase<> for an Objective C protocol (hence the P). Objective C protocols must always
|
||||
// be referenced with id<ProtocolName> and not just ProtocolName* so they cannot use NSRef<>
|
||||
// itself. That's what the P in NSPRef stands for: Protocol.
|
||||
template <typename T>
|
||||
class NSPRef : public RefBase<T, NSRefTraits<T>> {
|
||||
public:
|
||||
using RefBase<T, NSRefTraits<T>>::RefBase;
|
||||
|
||||
const T operator*() const {
|
||||
return this->Get();
|
||||
}
|
||||
|
||||
T operator*() {
|
||||
return this->Get();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
NSPRef<T> AcquireNSPRef(T pointee) {
|
||||
NSPRef<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
#endif // COMMON_NSREF_H_
|
|
@ -137,14 +137,6 @@ class RefBase {
|
|||
return mValue != kNullValue;
|
||||
}
|
||||
|
||||
// Operator * and -> to act like a pointer.
|
||||
const typename Traits::PointedType& operator*() const {
|
||||
return *mValue;
|
||||
}
|
||||
typename Traits::PointedType& operator*() {
|
||||
return *mValue;
|
||||
}
|
||||
|
||||
const T operator->() const {
|
||||
return mValue;
|
||||
}
|
||||
|
@ -166,6 +158,11 @@ class RefBase {
|
|||
return value;
|
||||
}
|
||||
|
||||
void Acquire(T value) {
|
||||
Release();
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
private:
|
||||
// Friend is needed so that instances of RefBase<U> can call Reference and Release on
|
||||
// RefBase<T>.
|
||||
|
|
|
@ -42,7 +42,6 @@ class RefCounted {
|
|||
|
||||
template <typename T>
|
||||
struct RefCountedTraits {
|
||||
using PointedType = T;
|
||||
static constexpr T* kNullValue = nullptr;
|
||||
static void Reference(T* value) {
|
||||
value->Reference();
|
||||
|
@ -60,8 +59,8 @@ class Ref : public RefBase<T*, RefCountedTraits<T>> {
|
|||
|
||||
template <typename T>
|
||||
Ref<T> AcquireRef(T* pointee) {
|
||||
Ref<T> ref(pointee);
|
||||
ref->Release();
|
||||
Ref<T> ref;
|
||||
ref.Acquire(pointee);
|
||||
return ref;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "dawn_native/metal/BackendMTL.h"
|
||||
|
||||
#include "common/GPUInfo.h"
|
||||
#include "common/NSRef.h"
|
||||
#include "common/Platform.h"
|
||||
#include "dawn_native/Instance.h"
|
||||
#include "dawn_native/MetalBackend.h"
|
||||
|
@ -176,8 +177,8 @@ namespace dawn_native { namespace metal {
|
|||
class Adapter : public AdapterBase {
|
||||
public:
|
||||
Adapter(InstanceBase* instance, id<MTLDevice> device)
|
||||
: AdapterBase(instance, wgpu::BackendType::Metal), mDevice([device retain]) {
|
||||
mPCIInfo.name = std::string([mDevice.name UTF8String]);
|
||||
: AdapterBase(instance, wgpu::BackendType::Metal), mDevice(device) {
|
||||
mPCIInfo.name = std::string([[*mDevice name] UTF8String]);
|
||||
|
||||
PCIIDs ids;
|
||||
if (!instance->ConsumedError(GetDevicePCIInfo(device, &ids))) {
|
||||
|
@ -206,10 +207,6 @@ namespace dawn_native { namespace metal {
|
|||
InitializeSupportedExtensions();
|
||||
}
|
||||
|
||||
~Adapter() override {
|
||||
[mDevice release];
|
||||
}
|
||||
|
||||
private:
|
||||
ResultOrError<DeviceBase*> CreateDeviceImpl(const DeviceDescriptor* descriptor) override {
|
||||
return Device::Create(this, mDevice, descriptor);
|
||||
|
@ -217,14 +214,14 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
void InitializeSupportedExtensions() {
|
||||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
if ([mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
|
||||
if ([*mDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v1]) {
|
||||
mSupportedExtensions.EnableExtension(Extension::TextureCompressionBC);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (@available(macOS 10.15, iOS 14.0, *)) {
|
||||
if ([mDevice supportsFamily:MTLGPUFamilyMac2] ||
|
||||
[mDevice supportsFamily:MTLGPUFamilyApple5]) {
|
||||
if ([*mDevice supportsFamily:MTLGPUFamilyMac2] ||
|
||||
[*mDevice supportsFamily:MTLGPUFamilyApple5]) {
|
||||
mSupportedExtensions.EnableExtension(Extension::PipelineStatisticsQuery);
|
||||
mSupportedExtensions.EnableExtension(Extension::TimestampQuery);
|
||||
}
|
||||
|
@ -233,7 +230,7 @@ namespace dawn_native { namespace metal {
|
|||
mSupportedExtensions.EnableExtension(Extension::ShaderFloat16);
|
||||
}
|
||||
|
||||
id<MTLDevice> mDevice = nil;
|
||||
NSPRef<id<MTLDevice>> mDevice;
|
||||
};
|
||||
|
||||
// Implementation of the Metal backend's BackendConnection
|
||||
|
@ -251,13 +248,12 @@ namespace dawn_native { namespace metal {
|
|||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
if (@available(macOS 10.11, *)) {
|
||||
supportedVersion = YES;
|
||||
NSArray<id<MTLDevice>>* devices = MTLCopyAllDevices();
|
||||
|
||||
for (id<MTLDevice> device in devices) {
|
||||
NSRef<NSArray<id<MTLDevice>>> devices = AcquireNSRef(MTLCopyAllDevices());
|
||||
|
||||
for (id<MTLDevice> device in devices.Get()) {
|
||||
adapters.push_back(std::make_unique<Adapter>(GetInstance(), device));
|
||||
}
|
||||
|
||||
[devices release];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#ifndef DAWNNATIVE_METAL_BUFFERMTL_H_
|
||||
#define DAWNNATIVE_METAL_BUFFERMTL_H_
|
||||
|
||||
#include "common/NSRef.h"
|
||||
#include "common/SerialQueue.h"
|
||||
#include "dawn_native/Buffer.h"
|
||||
|
||||
|
@ -53,7 +54,7 @@ namespace dawn_native { namespace metal {
|
|||
void InitializeToZero(CommandRecordingContext* commandContext);
|
||||
void ClearBuffer(CommandRecordingContext* commandContext, uint8_t clearValue);
|
||||
|
||||
id<MTLBuffer> mMtlBuffer = nil;
|
||||
NSPRef<id<MTLBuffer>> mMtlBuffer;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -84,9 +84,10 @@ namespace dawn_native { namespace metal {
|
|||
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation is too large");
|
||||
}
|
||||
|
||||
mMtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:currentSize
|
||||
options:storageMode];
|
||||
if (mMtlBuffer == nil) {
|
||||
mMtlBuffer.Acquire([ToBackend(GetDevice())->GetMTLDevice()
|
||||
newBufferWithLength:currentSize
|
||||
options:storageMode]);
|
||||
if (mMtlBuffer == nullptr) {
|
||||
return DAWN_OUT_OF_MEMORY_ERROR("Buffer allocation failed");
|
||||
}
|
||||
|
||||
|
@ -107,7 +108,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
id<MTLBuffer> Buffer::GetMTLBuffer() const {
|
||||
return mMtlBuffer;
|
||||
return mMtlBuffer.Get();
|
||||
}
|
||||
|
||||
bool Buffer::IsCPUWritableAtCreation() const {
|
||||
|
@ -128,7 +129,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
void* Buffer::GetMappedPointerImpl() {
|
||||
return [mMtlBuffer contents];
|
||||
return [*mMtlBuffer contents];
|
||||
}
|
||||
|
||||
void Buffer::UnmapImpl() {
|
||||
|
@ -136,8 +137,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
void Buffer::DestroyImpl() {
|
||||
[mMtlBuffer release];
|
||||
mMtlBuffer = nil;
|
||||
mMtlBuffer = nullptr;
|
||||
}
|
||||
|
||||
void Buffer::EnsureDataInitialized(CommandRecordingContext* commandContext) {
|
||||
|
@ -196,7 +196,7 @@ namespace dawn_native { namespace metal {
|
|||
return;
|
||||
}
|
||||
|
||||
[commandContext->EnsureBlit() fillBuffer:mMtlBuffer
|
||||
[commandContext->EnsureBlit() fillBuffer:mMtlBuffer.Get()
|
||||
range:NSMakeRange(0, GetSize())
|
||||
value:clearValue];
|
||||
}
|
||||
|
|
|
@ -53,9 +53,12 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
// Creates an autoreleased MTLRenderPassDescriptor matching desc
|
||||
MTLRenderPassDescriptor* CreateMTLRenderPassDescriptor(BeginRenderPassCmd* renderPass) {
|
||||
MTLRenderPassDescriptor* descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
NSRef<MTLRenderPassDescriptor> CreateMTLRenderPassDescriptor(
|
||||
BeginRenderPassCmd* renderPass) {
|
||||
// Note that this creates a descriptor that's autoreleased so we don't use AcquireNSRef
|
||||
NSRef<MTLRenderPassDescriptor> descriptorRef =
|
||||
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||
MTLRenderPassDescriptor* descriptor = descriptorRef.Get();
|
||||
|
||||
for (ColorAttachmentIndex attachment :
|
||||
IterateBitSet(renderPass->attachmentState->GetColorAttachmentsMask())) {
|
||||
|
@ -167,7 +170,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
return descriptor;
|
||||
return descriptorRef;
|
||||
}
|
||||
|
||||
// Helper function for Toggle EmulateStoreAndMSAAResolve
|
||||
|
@ -175,10 +178,13 @@ namespace dawn_native { namespace metal {
|
|||
CommandRecordingContext* commandContext,
|
||||
const MTLRenderPassDescriptor* mtlRenderPass,
|
||||
const std::array<id<MTLTexture>, kMaxColorAttachments>& resolveTextures) {
|
||||
MTLRenderPassDescriptor* mtlRenderPassForResolve =
|
||||
// Note that this creates a descriptor that's autoreleased so we don't use AcquireNSRef
|
||||
NSRef<MTLRenderPassDescriptor> mtlRenderPassForResolveRef =
|
||||
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||
MTLRenderPassDescriptor* mtlRenderPassForResolve = mtlRenderPassForResolveRef.Get();
|
||||
|
||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||
if (resolveTextures[i] == nil) {
|
||||
if (resolveTextures[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -199,11 +205,13 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
// Helper functions for Toggle AlwaysResolveIntoZeroLevelAndLayer
|
||||
id<MTLTexture> CreateResolveTextureForWorkaround(Device* device,
|
||||
MTLPixelFormat mtlFormat,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
MTLTextureDescriptor* mtlDesc = [MTLTextureDescriptor new];
|
||||
NSPRef<id<MTLTexture>> CreateResolveTextureForWorkaround(Device* device,
|
||||
MTLPixelFormat mtlFormat,
|
||||
uint32_t width,
|
||||
uint32_t height) {
|
||||
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
||||
|
||||
mtlDesc.textureType = MTLTextureType2D;
|
||||
mtlDesc.usage = MTLTextureUsageRenderTarget;
|
||||
mtlDesc.pixelFormat = mtlFormat;
|
||||
|
@ -214,10 +222,8 @@ namespace dawn_native { namespace metal {
|
|||
mtlDesc.arrayLength = 1;
|
||||
mtlDesc.storageMode = MTLStorageModePrivate;
|
||||
mtlDesc.sampleCount = 1;
|
||||
id<MTLTexture> resolveTexture =
|
||||
[device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
||||
[mtlDesc release];
|
||||
return resolveTexture;
|
||||
|
||||
return AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc]);
|
||||
}
|
||||
|
||||
void CopyIntoTrueResolveTarget(CommandRecordingContext* commandContext,
|
||||
|
@ -350,11 +356,11 @@ namespace dawn_native { namespace metal {
|
|||
group->GetLayout()->GetBindingInfo(bindingIndex);
|
||||
|
||||
bool hasVertStage =
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Vertex && render != nil;
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Vertex && render != nullptr;
|
||||
bool hasFragStage =
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Fragment && render != nil;
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Fragment && render != nullptr;
|
||||
bool hasComputeStage =
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Compute && compute != nil;
|
||||
bindingInfo.visibility & wgpu::ShaderStage::Compute && compute != nullptr;
|
||||
|
||||
uint32_t vertIndex = 0;
|
||||
uint32_t fragIndex = 0;
|
||||
|
@ -461,12 +467,12 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
template <typename... Args>
|
||||
void ApplyBindGroup(id<MTLRenderCommandEncoder> encoder, Args&&... args) {
|
||||
ApplyBindGroupImpl(encoder, nil, std::forward<Args&&>(args)...);
|
||||
ApplyBindGroupImpl(encoder, nullptr, std::forward<Args&&>(args)...);
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
void ApplyBindGroup(id<MTLComputeCommandEncoder> encoder, Args&&... args) {
|
||||
ApplyBindGroupImpl(nil, encoder, std::forward<Args&&>(args)...);
|
||||
ApplyBindGroupImpl(nullptr, encoder, std::forward<Args&&>(args)...);
|
||||
}
|
||||
|
||||
StorageBufferLengthTracker* mLengthTracker;
|
||||
|
@ -578,8 +584,9 @@ namespace dawn_native { namespace metal {
|
|||
commandContext->EndBlit();
|
||||
|
||||
LazyClearRenderPassAttachments(cmd);
|
||||
MTLRenderPassDescriptor* descriptor = CreateMTLRenderPassDescriptor(cmd);
|
||||
DAWN_TRY(EncodeRenderPass(commandContext, descriptor, cmd->width, cmd->height));
|
||||
NSRef<MTLRenderPassDescriptor> descriptor = CreateMTLRenderPassDescriptor(cmd);
|
||||
DAWN_TRY(EncodeRenderPass(commandContext, descriptor.Get(), cmd->width,
|
||||
cmd->height));
|
||||
|
||||
nextPassNumber++;
|
||||
break;
|
||||
|
@ -792,9 +799,9 @@ namespace dawn_native { namespace metal {
|
|||
char* label = mCommands.NextData<char>(cmd->length + 1);
|
||||
|
||||
if (@available(macos 10.13, *)) {
|
||||
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
|
||||
[commandContext->GetCommands() pushDebugGroup:mtlLabel];
|
||||
[mtlLabel release];
|
||||
NSRef<NSString> mtlLabel =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:label]);
|
||||
[commandContext->GetCommands() pushDebugGroup:mtlLabel.Get()];
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -876,10 +883,9 @@ namespace dawn_native { namespace metal {
|
|||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = mCommands.NextCommand<InsertDebugMarkerCmd>();
|
||||
char* label = mCommands.NextData<char>(cmd->length + 1);
|
||||
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
|
||||
|
||||
[encoder insertDebugSignpost:mtlLabel];
|
||||
[mtlLabel release];
|
||||
NSRef<NSString> mtlLabel =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:label]);
|
||||
[encoder insertDebugSignpost:mtlLabel.Get()];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -893,10 +899,9 @@ namespace dawn_native { namespace metal {
|
|||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = mCommands.NextCommand<PushDebugGroupCmd>();
|
||||
char* label = mCommands.NextData<char>(cmd->length + 1);
|
||||
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
|
||||
|
||||
[encoder pushDebugGroup:mtlLabel];
|
||||
[mtlLabel release];
|
||||
NSRef<NSString> mtlLabel =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:label]);
|
||||
[encoder pushDebugGroup:mtlLabel.Get()];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -944,9 +949,9 @@ namespace dawn_native { namespace metal {
|
|||
// Use temporary resolve texture on the resolve targets with non-zero resolveLevel or
|
||||
// resolveSlice.
|
||||
bool useTemporaryResolveTexture = false;
|
||||
std::array<id<MTLTexture>, kMaxColorAttachments> temporaryResolveTextures = {};
|
||||
std::array<NSPRef<id<MTLTexture>>, kMaxColorAttachments> temporaryResolveTextures = {};
|
||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||
if (mtlRenderPass.colorAttachments[i].resolveTexture == nil) {
|
||||
if (mtlRenderPass.colorAttachments[i].resolveTexture == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -963,7 +968,8 @@ namespace dawn_native { namespace metal {
|
|||
temporaryResolveTextures[i] =
|
||||
CreateResolveTextureForWorkaround(device, mtlFormat, width, height);
|
||||
|
||||
mtlRenderPass.colorAttachments[i].resolveTexture = temporaryResolveTextures[i];
|
||||
mtlRenderPass.colorAttachments[i].resolveTexture =
|
||||
temporaryResolveTextures[i].Get();
|
||||
mtlRenderPass.colorAttachments[i].resolveLevel = 0;
|
||||
mtlRenderPass.colorAttachments[i].resolveSlice = 0;
|
||||
useTemporaryResolveTexture = true;
|
||||
|
@ -974,16 +980,14 @@ namespace dawn_native { namespace metal {
|
|||
if (useTemporaryResolveTexture) {
|
||||
DAWN_TRY(EncodeRenderPass(commandContext, mtlRenderPass, width, height));
|
||||
for (uint32_t i = 0; i < kMaxColorAttachments; ++i) {
|
||||
if (trueResolveTextures[i] == nil) {
|
||||
if (trueResolveTextures[i] == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ASSERT(temporaryResolveTextures[i] != nil);
|
||||
ASSERT(temporaryResolveTextures[i] != nullptr);
|
||||
CopyIntoTrueResolveTarget(commandContext, trueResolveTextures[i],
|
||||
trueResolveLevels[i], trueResolveSlices[i],
|
||||
temporaryResolveTextures[i], width, height);
|
||||
[temporaryResolveTextures[i] release];
|
||||
temporaryResolveTextures[i] = nil;
|
||||
temporaryResolveTextures[i].Get(), width, height);
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
@ -1002,7 +1006,7 @@ namespace dawn_native { namespace metal {
|
|||
resolveTextures[i] = mtlRenderPass.colorAttachments[i].resolveTexture;
|
||||
|
||||
mtlRenderPass.colorAttachments[i].storeAction = MTLStoreActionStore;
|
||||
mtlRenderPass.colorAttachments[i].resolveTexture = nil;
|
||||
mtlRenderPass.colorAttachments[i].resolveTexture = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1024,7 +1028,7 @@ namespace dawn_native { namespace metal {
|
|||
uint32_t height) {
|
||||
bool enableVertexPulling = GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling);
|
||||
RenderPipeline* lastPipeline = nullptr;
|
||||
id<MTLBuffer> indexBuffer = nil;
|
||||
id<MTLBuffer> indexBuffer = nullptr;
|
||||
uint32_t indexBufferBaseOffset = 0;
|
||||
wgpu::IndexFormat indexBufferFormat = wgpu::IndexFormat::Undefined;
|
||||
StorageBufferLengthTracker storageBufferLengths = {};
|
||||
|
@ -1148,10 +1152,9 @@ namespace dawn_native { namespace metal {
|
|||
case Command::InsertDebugMarker: {
|
||||
InsertDebugMarkerCmd* cmd = iter->NextCommand<InsertDebugMarkerCmd>();
|
||||
char* label = iter->NextData<char>(cmd->length + 1);
|
||||
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
|
||||
|
||||
[encoder insertDebugSignpost:mtlLabel];
|
||||
[mtlLabel release];
|
||||
NSRef<NSString> mtlLabel =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:label]);
|
||||
[encoder insertDebugSignpost:mtlLabel.Get()];
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -1165,10 +1168,9 @@ namespace dawn_native { namespace metal {
|
|||
case Command::PushDebugGroup: {
|
||||
PushDebugGroupCmd* cmd = iter->NextCommand<PushDebugGroupCmd>();
|
||||
char* label = iter->NextData<char>(cmd->length + 1);
|
||||
NSString* mtlLabel = [[NSString alloc] initWithUTF8String:label];
|
||||
|
||||
[encoder pushDebugGroup:mtlLabel];
|
||||
[mtlLabel release];
|
||||
NSRef<NSString> mtlLabel =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:label]);
|
||||
[encoder pushDebugGroup:mtlLabel.Get()];
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#ifndef DAWNNATIVE_METAL_COMMANDRECORDINGCONTEXT_H_
|
||||
#define DAWNNATIVE_METAL_COMMANDRECORDINGCONTEXT_H_
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -23,7 +25,7 @@ namespace dawn_native { namespace metal {
|
|||
class CommandRecordingContext {
|
||||
public:
|
||||
CommandRecordingContext();
|
||||
CommandRecordingContext(id<MTLCommandBuffer> commands);
|
||||
CommandRecordingContext(NSPRef<id<MTLCommandBuffer>> commands);
|
||||
|
||||
CommandRecordingContext(const CommandRecordingContext& rhs) = delete;
|
||||
CommandRecordingContext& operator=(const CommandRecordingContext& rhs) = delete;
|
||||
|
@ -35,7 +37,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
id<MTLCommandBuffer> GetCommands();
|
||||
|
||||
id<MTLCommandBuffer> AcquireCommands();
|
||||
NSPRef<id<MTLCommandBuffer>> AcquireCommands();
|
||||
|
||||
id<MTLBlitCommandEncoder> EnsureBlit();
|
||||
void EndBlit();
|
||||
|
@ -47,10 +49,10 @@ namespace dawn_native { namespace metal {
|
|||
void EndRender();
|
||||
|
||||
private:
|
||||
id<MTLCommandBuffer> mCommands = nil;
|
||||
id<MTLBlitCommandEncoder> mBlit = nil;
|
||||
id<MTLComputeCommandEncoder> mCompute = nil;
|
||||
id<MTLRenderCommandEncoder> mRender = nil;
|
||||
NSPRef<id<MTLCommandBuffer>> mCommands;
|
||||
NSPRef<id<MTLBlitCommandEncoder>> mBlit;
|
||||
NSPRef<id<MTLComputeCommandEncoder>> mCompute;
|
||||
NSPRef<id<MTLRenderCommandEncoder>> mRender;
|
||||
bool mInEncoder = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
CommandRecordingContext::CommandRecordingContext() = default;
|
||||
|
||||
CommandRecordingContext::CommandRecordingContext(id<MTLCommandBuffer> commands)
|
||||
: mCommands(commands) {
|
||||
CommandRecordingContext::CommandRecordingContext(NSPRef<id<MTLCommandBuffer>> commands)
|
||||
: mCommands(std::move(commands)) {
|
||||
}
|
||||
|
||||
CommandRecordingContext::CommandRecordingContext(CommandRecordingContext&& rhs)
|
||||
|
@ -35,90 +35,87 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
CommandRecordingContext::~CommandRecordingContext() {
|
||||
// Commands must be acquired.
|
||||
ASSERT(mCommands == nil);
|
||||
ASSERT(mCommands == nullptr);
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> CommandRecordingContext::GetCommands() {
|
||||
return mCommands;
|
||||
return mCommands.Get();
|
||||
}
|
||||
|
||||
id<MTLCommandBuffer> CommandRecordingContext::AcquireCommands() {
|
||||
if (mCommands == nil) {
|
||||
return nil;
|
||||
NSPRef<id<MTLCommandBuffer>> CommandRecordingContext::AcquireCommands() {
|
||||
// A blit encoder can be left open from WriteBuffer, make sure we close it.
|
||||
if (mCommands != nullptr) {
|
||||
EndBlit();
|
||||
}
|
||||
|
||||
// A blit encoder can be left open from WriteBuffer, make sure we close it.
|
||||
EndBlit();
|
||||
|
||||
ASSERT(!mInEncoder);
|
||||
id<MTLCommandBuffer> commands = mCommands;
|
||||
mCommands = nil;
|
||||
return commands;
|
||||
return std::move(mCommands);
|
||||
}
|
||||
|
||||
id<MTLBlitCommandEncoder> CommandRecordingContext::EnsureBlit() {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
|
||||
if (mBlit == nil) {
|
||||
if (mBlit == nullptr) {
|
||||
ASSERT(!mInEncoder);
|
||||
mInEncoder = true;
|
||||
// The autorelease pool may drain before the encoder is ended. Retain so it stays alive.
|
||||
mBlit = [[mCommands blitCommandEncoder] retain];
|
||||
|
||||
// The encoder is created autoreleased. Retain it to avoid the autoreleasepool from
|
||||
// draining from under us.
|
||||
mBlit = [*mCommands blitCommandEncoder];
|
||||
}
|
||||
return mBlit;
|
||||
return mBlit.Get();
|
||||
}
|
||||
|
||||
void CommandRecordingContext::EndBlit() {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
|
||||
if (mBlit != nil) {
|
||||
[mBlit endEncoding];
|
||||
[mBlit release];
|
||||
mBlit = nil;
|
||||
if (mBlit != nullptr) {
|
||||
[*mBlit endEncoding];
|
||||
mBlit = nullptr;
|
||||
mInEncoder = false;
|
||||
}
|
||||
}
|
||||
|
||||
id<MTLComputeCommandEncoder> CommandRecordingContext::BeginCompute() {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mCompute == nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
ASSERT(mCompute == nullptr);
|
||||
ASSERT(!mInEncoder);
|
||||
|
||||
mInEncoder = true;
|
||||
// The autorelease pool may drain before the encoder is ended. Retain so it stays alive.
|
||||
mCompute = [[mCommands computeCommandEncoder] retain];
|
||||
return mCompute;
|
||||
// The encoder is created autoreleased. Retain it to avoid the autoreleasepool from draining
|
||||
// from under us.
|
||||
mCompute = [*mCommands computeCommandEncoder];
|
||||
return mCompute.Get();
|
||||
}
|
||||
|
||||
void CommandRecordingContext::EndCompute() {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mCompute != nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
ASSERT(mCompute != nullptr);
|
||||
|
||||
[mCompute endEncoding];
|
||||
[mCompute release];
|
||||
mCompute = nil;
|
||||
[*mCompute endEncoding];
|
||||
mCompute = nullptr;
|
||||
mInEncoder = false;
|
||||
}
|
||||
|
||||
id<MTLRenderCommandEncoder> CommandRecordingContext::BeginRender(
|
||||
MTLRenderPassDescriptor* descriptor) {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mRender == nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
ASSERT(mRender == nullptr);
|
||||
ASSERT(!mInEncoder);
|
||||
|
||||
mInEncoder = true;
|
||||
// The autorelease pool may drain before the encoder is ended. Retain so it stays alive.
|
||||
mRender = [[mCommands renderCommandEncoderWithDescriptor:descriptor] retain];
|
||||
return mRender;
|
||||
// The encoder is created autoreleased. Retain it to avoid the autoreleasepool from draining
|
||||
// from under us.
|
||||
mRender = [*mCommands renderCommandEncoderWithDescriptor:descriptor];
|
||||
return mRender.Get();
|
||||
}
|
||||
|
||||
void CommandRecordingContext::EndRender() {
|
||||
ASSERT(mCommands != nil);
|
||||
ASSERT(mRender != nil);
|
||||
ASSERT(mCommands != nullptr);
|
||||
ASSERT(mRender != nullptr);
|
||||
|
||||
[mRender endEncoding];
|
||||
[mRender release];
|
||||
mRender = nil;
|
||||
[*mRender endEncoding];
|
||||
mRender = nullptr;
|
||||
mInEncoder = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/ComputePipeline.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -33,11 +35,10 @@ namespace dawn_native { namespace metal {
|
|||
bool RequiresStorageBufferLength() const;
|
||||
|
||||
private:
|
||||
~ComputePipeline() override;
|
||||
using ComputePipelineBase::ComputePipelineBase;
|
||||
MaybeError Initialize(const ComputePipelineDescriptor* descriptor);
|
||||
|
||||
id<MTLComputePipelineState> mMtlComputePipelineState = nil;
|
||||
NSPRef<id<MTLComputePipelineState>> mMtlComputePipelineState;
|
||||
MTLSize mLocalWorkgroupSize;
|
||||
bool mRequiresStorageBufferLength;
|
||||
};
|
||||
|
|
|
@ -37,10 +37,11 @@ namespace dawn_native { namespace metal {
|
|||
DAWN_TRY(computeModule->CreateFunction(computeEntryPoint, SingleShaderStage::Compute,
|
||||
ToBackend(GetLayout()), &computeData));
|
||||
|
||||
NSError* error = nil;
|
||||
mMtlComputePipelineState =
|
||||
[mtlDevice newComputePipelineStateWithFunction:computeData.function error:&error];
|
||||
if (error != nil) {
|
||||
NSError* error = nullptr;
|
||||
mMtlComputePipelineState.Acquire([mtlDevice
|
||||
newComputePipelineStateWithFunction:computeData.function.Get()
|
||||
error:&error]);
|
||||
if (error != nullptr) {
|
||||
NSLog(@" error => %@", error);
|
||||
return DAWN_INTERNAL_ERROR("Error creating pipeline state");
|
||||
}
|
||||
|
@ -53,12 +54,8 @@ namespace dawn_native { namespace metal {
|
|||
return {};
|
||||
}
|
||||
|
||||
ComputePipeline::~ComputePipeline() {
|
||||
[mMtlComputePipelineState release];
|
||||
}
|
||||
|
||||
void ComputePipeline::Encode(id<MTLComputeCommandEncoder> encoder) {
|
||||
[encoder setComputePipelineState:mMtlComputePipelineState];
|
||||
[encoder setComputePipelineState:mMtlComputePipelineState.Get()];
|
||||
}
|
||||
|
||||
MTLSize ComputePipeline::GetLocalWorkGroupSize() const {
|
||||
|
|
|
@ -35,7 +35,7 @@ namespace dawn_native { namespace metal {
|
|||
class Device : public DeviceBase {
|
||||
public:
|
||||
static ResultOrError<Device*> Create(AdapterBase* adapter,
|
||||
id<MTLDevice> mtlDevice,
|
||||
NSPRef<id<MTLDevice>> mtlDevice,
|
||||
const DeviceDescriptor* descriptor);
|
||||
~Device() override;
|
||||
|
||||
|
@ -72,7 +72,9 @@ namespace dawn_native { namespace metal {
|
|||
uint64_t GetOptimalBufferToTextureCopyOffsetAlignment() const override;
|
||||
|
||||
private:
|
||||
Device(AdapterBase* adapter, id<MTLDevice> mtlDevice, const DeviceDescriptor* descriptor);
|
||||
Device(AdapterBase* adapter,
|
||||
NSPRef<id<MTLDevice>> mtlDevice,
|
||||
const DeviceDescriptor* descriptor);
|
||||
|
||||
ResultOrError<BindGroupBase*> CreateBindGroupImpl(
|
||||
const BindGroupDescriptor* descriptor) override;
|
||||
|
@ -108,8 +110,8 @@ namespace dawn_native { namespace metal {
|
|||
MaybeError WaitForIdleForDestruction() override;
|
||||
ExecutionSerial CheckAndUpdateCompletedSerials() override;
|
||||
|
||||
id<MTLDevice> mMtlDevice = nil;
|
||||
id<MTLCommandQueue> mCommandQueue = nil;
|
||||
NSPRef<id<MTLDevice>> mMtlDevice;
|
||||
NSPRef<id<MTLCommandQueue>> mCommandQueue;
|
||||
|
||||
CommandRecordingContext mCommandContext;
|
||||
|
||||
|
@ -120,7 +122,7 @@ namespace dawn_native { namespace metal {
|
|||
// mLastSubmittedCommands will be accessed in a Metal schedule handler that can be fired on
|
||||
// a different thread so we guard access to it with a mutex.
|
||||
std::mutex mLastSubmittedCommandsMutex;
|
||||
id<MTLCommandBuffer> mLastSubmittedCommands = nil;
|
||||
NSPRef<id<MTLCommandBuffer>> mLastSubmittedCommands;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -44,18 +44,17 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
// static
|
||||
ResultOrError<Device*> Device::Create(AdapterBase* adapter,
|
||||
id<MTLDevice> mtlDevice,
|
||||
NSPRef<id<MTLDevice>> mtlDevice,
|
||||
const DeviceDescriptor* descriptor) {
|
||||
Ref<Device> device = AcquireRef(new Device(adapter, mtlDevice, descriptor));
|
||||
Ref<Device> device = AcquireRef(new Device(adapter, std::move(mtlDevice), descriptor));
|
||||
DAWN_TRY(device->Initialize());
|
||||
return device.Detach();
|
||||
}
|
||||
|
||||
Device::Device(AdapterBase* adapter,
|
||||
id<MTLDevice> mtlDevice,
|
||||
NSPRef<id<MTLDevice>> mtlDevice,
|
||||
const DeviceDescriptor* descriptor)
|
||||
: DeviceBase(adapter, descriptor), mMtlDevice([mtlDevice retain]), mCompletedSerial(0) {
|
||||
[mMtlDevice retain];
|
||||
: DeviceBase(adapter, descriptor), mMtlDevice(std::move(mtlDevice)), mCompletedSerial(0) {
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
|
@ -69,7 +68,7 @@ namespace dawn_native { namespace metal {
|
|||
ForceSetToggle(Toggle::MetalEnableVertexPulling, false);
|
||||
}
|
||||
|
||||
mCommandQueue = [mMtlDevice newCommandQueue];
|
||||
mCommandQueue.Acquire([*mMtlDevice newCommandQueue]);
|
||||
|
||||
return DeviceBase::Initialize(new Queue(this));
|
||||
}
|
||||
|
@ -80,18 +79,18 @@ namespace dawn_native { namespace metal {
|
|||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
if (@available(macOS 10.12, *)) {
|
||||
haveStoreAndMSAAResolve =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2];
|
||||
[*mMtlDevice supportsFeatureSet:MTLFeatureSet_macOS_GPUFamily1_v2];
|
||||
}
|
||||
#elif defined(DAWN_PLATFORM_IOS)
|
||||
haveStoreAndMSAAResolve =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2];
|
||||
[*mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v2];
|
||||
#endif
|
||||
// On tvOS, we would need MTLFeatureSet_tvOS_GPUFamily2_v1.
|
||||
SetToggle(Toggle::EmulateStoreAndMSAAResolve, !haveStoreAndMSAAResolve);
|
||||
|
||||
bool haveSamplerCompare = true;
|
||||
#if defined(DAWN_PLATFORM_IOS)
|
||||
haveSamplerCompare = [mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1];
|
||||
haveSamplerCompare = [*mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1];
|
||||
#endif
|
||||
// TODO(crbug.com/dawn/342): Investigate emulation -- possibly expensive.
|
||||
SetToggle(Toggle::MetalDisableSamplerCompare, !haveSamplerCompare);
|
||||
|
@ -99,7 +98,7 @@ namespace dawn_native { namespace metal {
|
|||
bool haveBaseVertexBaseInstance = true;
|
||||
#if defined(DAWN_PLATFORM_IOS)
|
||||
haveBaseVertexBaseInstance =
|
||||
[mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1];
|
||||
[*mMtlDevice supportsFeatureSet:MTLFeatureSet_iOS_GPUFamily3_v1];
|
||||
#endif
|
||||
// TODO(crbug.com/dawn/343): Investigate emulation.
|
||||
SetToggle(Toggle::DisableBaseVertex, !haveBaseVertexBaseInstance);
|
||||
|
@ -187,7 +186,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
MaybeError Device::TickImpl() {
|
||||
if (mCommandContext.GetCommands() != nil) {
|
||||
if (mCommandContext.GetCommands() != nullptr) {
|
||||
SubmitPendingCommandBuffer();
|
||||
}
|
||||
|
||||
|
@ -195,33 +194,33 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
id<MTLDevice> Device::GetMTLDevice() {
|
||||
return mMtlDevice;
|
||||
return mMtlDevice.Get();
|
||||
}
|
||||
|
||||
id<MTLCommandQueue> Device::GetMTLQueue() {
|
||||
return mCommandQueue;
|
||||
return mCommandQueue.Get();
|
||||
}
|
||||
|
||||
CommandRecordingContext* Device::GetPendingCommandContext() {
|
||||
if (mCommandContext.GetCommands() == nil) {
|
||||
if (mCommandContext.GetCommands() == nullptr) {
|
||||
TRACE_EVENT0(GetPlatform(), General, "[MTLCommandQueue commandBuffer]");
|
||||
// The MTLCommandBuffer will be autoreleased by default.
|
||||
// The autorelease pool may drain before the command buffer is submitted. Retain so it
|
||||
// stays alive.
|
||||
mCommandContext = CommandRecordingContext([[mCommandQueue commandBuffer] retain]);
|
||||
mCommandContext = CommandRecordingContext([*mCommandQueue commandBuffer]);
|
||||
}
|
||||
return &mCommandContext;
|
||||
}
|
||||
|
||||
void Device::SubmitPendingCommandBuffer() {
|
||||
if (mCommandContext.GetCommands() == nil) {
|
||||
if (mCommandContext.GetCommands() == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
IncrementLastSubmittedCommandSerial();
|
||||
|
||||
// Acquire the pending command buffer, which is retained. It must be released later.
|
||||
id<MTLCommandBuffer> pendingCommands = mCommandContext.AcquireCommands();
|
||||
NSPRef<id<MTLCommandBuffer>> pendingCommands = mCommandContext.AcquireCommands();
|
||||
|
||||
// Replace mLastSubmittedCommands with the mutex held so we avoid races between the
|
||||
// schedule handler and this code.
|
||||
|
@ -230,12 +229,15 @@ namespace dawn_native { namespace metal {
|
|||
mLastSubmittedCommands = pendingCommands;
|
||||
}
|
||||
|
||||
[pendingCommands addScheduledHandler:^(id<MTLCommandBuffer>) {
|
||||
// Make a local copy of the pointer to the commands because it's not clear how ObjC blocks
|
||||
// handle types with copy / move constructors being referenced in the block..
|
||||
id<MTLCommandBuffer> pendingCommandsPointer = pendingCommands.Get();
|
||||
[*pendingCommands addScheduledHandler:^(id<MTLCommandBuffer>) {
|
||||
// This is DRF because we hold the mutex for mLastSubmittedCommands and pendingCommands
|
||||
// is a local value (and not the member itself).
|
||||
std::lock_guard<std::mutex> lock(mLastSubmittedCommandsMutex);
|
||||
if (this->mLastSubmittedCommands == pendingCommands) {
|
||||
this->mLastSubmittedCommands = nil;
|
||||
if (this->mLastSubmittedCommands.Get() == pendingCommandsPointer) {
|
||||
this->mLastSubmittedCommands = nullptr;
|
||||
}
|
||||
}];
|
||||
|
||||
|
@ -243,7 +245,7 @@ namespace dawn_native { namespace metal {
|
|||
// mLastSubmittedSerial so it is captured by value.
|
||||
ExecutionSerial pendingSerial = GetLastSubmittedCommandSerial();
|
||||
// this ObjC block runs on a different thread
|
||||
[pendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
||||
[*pendingCommands addCompletedHandler:^(id<MTLCommandBuffer>) {
|
||||
TRACE_EVENT_ASYNC_END0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
||||
uint64_t(pendingSerial));
|
||||
ASSERT(uint64_t(pendingSerial) > mCompletedSerial.load());
|
||||
|
@ -252,8 +254,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
TRACE_EVENT_ASYNC_BEGIN0(GetPlatform(), GPUWork, "DeviceMTL::SubmitPendingCommandBuffer",
|
||||
uint64_t(pendingSerial));
|
||||
[pendingCommands commit];
|
||||
[pendingCommands release];
|
||||
[*pendingCommands commit];
|
||||
}
|
||||
|
||||
ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(size_t size) {
|
||||
|
@ -356,11 +357,12 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
void Device::WaitForCommandsToBeScheduled() {
|
||||
SubmitPendingCommandBuffer();
|
||||
[mLastSubmittedCommands waitUntilScheduled];
|
||||
[*mLastSubmittedCommands waitUntilScheduled];
|
||||
}
|
||||
|
||||
MaybeError Device::WaitForIdleForDestruction() {
|
||||
[mCommandContext.AcquireCommands() release];
|
||||
// Forget all pending commands.
|
||||
mCommandContext.AcquireCommands();
|
||||
CheckPassedSerials();
|
||||
|
||||
// Wait for all commands to be finished so we can free resources
|
||||
|
@ -375,13 +377,11 @@ namespace dawn_native { namespace metal {
|
|||
void Device::ShutDownImpl() {
|
||||
ASSERT(GetState() == State::Disconnected);
|
||||
|
||||
[mCommandContext.AcquireCommands() release];
|
||||
// Forget all pending commands.
|
||||
mCommandContext.AcquireCommands();
|
||||
|
||||
[mCommandQueue release];
|
||||
mCommandQueue = nil;
|
||||
|
||||
[mMtlDevice release];
|
||||
mMtlDevice = nil;
|
||||
mCommandQueue = nullptr;
|
||||
mMtlDevice = nullptr;
|
||||
}
|
||||
|
||||
uint32_t Device::GetOptimalBytesPerRowAlignment() const {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/QuerySet.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -40,9 +42,11 @@ namespace dawn_native { namespace metal {
|
|||
// Dawn API
|
||||
void DestroyImpl() override;
|
||||
|
||||
id<MTLBuffer> mVisibilityBuffer = nil;
|
||||
NSPRef<id<MTLBuffer>> mVisibilityBuffer;
|
||||
// Note that mCounterSampleBuffer cannot be an NSRef because the API_AVAILABLE macros don't
|
||||
// propagate nicely through templates.
|
||||
id<MTLCounterSampleBuffer> mCounterSampleBuffer API_AVAILABLE(macos(10.15),
|
||||
ios(14.0)) = nil;
|
||||
ios(14.0)) = nullptr;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -26,7 +26,9 @@ namespace dawn_native { namespace metal {
|
|||
Device* device,
|
||||
MTLCommonCounterSet counterSet,
|
||||
uint32_t count) API_AVAILABLE(macos(10.15), ios(14.0)) {
|
||||
MTLCounterSampleBufferDescriptor* descriptor = [MTLCounterSampleBufferDescriptor new];
|
||||
NSRef<MTLCounterSampleBufferDescriptor> descriptorRef =
|
||||
AcquireNSRef([MTLCounterSampleBufferDescriptor new]);
|
||||
MTLCounterSampleBufferDescriptor* descriptor = descriptorRef.Get();
|
||||
|
||||
// To determine which counters are available from a device, we need to iterate through
|
||||
// the counterSets property of a MTLDevice. Then configure which counters will be
|
||||
|
@ -38,18 +40,19 @@ namespace dawn_native { namespace metal {
|
|||
break;
|
||||
}
|
||||
}
|
||||
ASSERT(descriptor.counterSet != nil);
|
||||
ASSERT(descriptor.counterSet != nullptr);
|
||||
|
||||
descriptor.sampleCount = count;
|
||||
descriptor.storageMode = MTLStorageModePrivate;
|
||||
if (device->IsToggleEnabled(Toggle::MetalUseSharedModeForCounterSampleBuffer)) {
|
||||
descriptor.storageMode = MTLStorageModeShared;
|
||||
}
|
||||
|
||||
NSError* error = nil;
|
||||
NSError* error = nullptr;
|
||||
id<MTLCounterSampleBuffer> counterSampleBuffer =
|
||||
[device->GetMTLDevice() newCounterSampleBufferWithDescriptor:descriptor
|
||||
error:&error];
|
||||
if (error != nil) {
|
||||
if (error != nullptr) {
|
||||
const char* errorString = [error.localizedDescription UTF8String];
|
||||
return DAWN_INTERNAL_ERROR(std::string("Error creating query set: ") + errorString);
|
||||
}
|
||||
|
@ -73,9 +76,9 @@ namespace dawn_native { namespace metal {
|
|||
case wgpu::QueryType::Occlusion: {
|
||||
// Create buffer for writing 64-bit results.
|
||||
NSUInteger bufferSize = static_cast<NSUInteger>(GetQueryCount() * sizeof(uint64_t));
|
||||
mVisibilityBuffer =
|
||||
[device->GetMTLDevice() newBufferWithLength:bufferSize
|
||||
options:MTLResourceStorageModePrivate];
|
||||
mVisibilityBuffer = AcquireNSPRef([device->GetMTLDevice()
|
||||
newBufferWithLength:bufferSize
|
||||
options:MTLResourceStorageModePrivate]);
|
||||
break;
|
||||
}
|
||||
case wgpu::QueryType::PipelineStatistics:
|
||||
|
@ -105,7 +108,7 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
id<MTLBuffer> QuerySet::GetVisibilityBuffer() const {
|
||||
return mVisibilityBuffer;
|
||||
return mVisibilityBuffer.Get();
|
||||
}
|
||||
|
||||
id<MTLCounterSampleBuffer> QuerySet::GetCounterSampleBuffer() const
|
||||
|
@ -118,16 +121,13 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
void QuerySet::DestroyImpl() {
|
||||
if (mVisibilityBuffer != nil) {
|
||||
[mVisibilityBuffer release];
|
||||
mVisibilityBuffer = nil;
|
||||
}
|
||||
mVisibilityBuffer = nullptr;
|
||||
|
||||
// mCounterSampleBuffer isn't an NSRef because API_AVAILABLE doesn't work will with
|
||||
// templates.
|
||||
if (@available(macOS 10.15, iOS 14.0, *)) {
|
||||
if (mCounterSampleBuffer != nil) {
|
||||
[mCounterSampleBuffer release];
|
||||
mCounterSampleBuffer = nil;
|
||||
}
|
||||
[mCounterSampleBuffer release];
|
||||
mCounterSampleBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/RenderPipeline.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -43,7 +45,6 @@ namespace dawn_native { namespace metal {
|
|||
wgpu::ShaderStage GetStagesRequiringStorageBufferLength() const;
|
||||
|
||||
private:
|
||||
~RenderPipeline() override;
|
||||
using RenderPipelineBase::RenderPipelineBase;
|
||||
MaybeError Initialize(const RenderPipelineDescriptor* descriptor);
|
||||
|
||||
|
@ -52,8 +53,8 @@ namespace dawn_native { namespace metal {
|
|||
MTLPrimitiveType mMtlPrimitiveTopology;
|
||||
MTLWinding mMtlFrontFace;
|
||||
MTLCullMode mMtlCullMode;
|
||||
id<MTLRenderPipelineState> mMtlRenderPipelineState = nil;
|
||||
id<MTLDepthStencilState> mMtlDepthStencilState = nil;
|
||||
NSPRef<id<MTLRenderPipelineState>> mMtlRenderPipelineState;
|
||||
NSPRef<id<MTLDepthStencilState>> mMtlDepthStencilState;
|
||||
ityp::array<VertexBufferSlot, uint32_t, kMaxVertexBuffers> mMtlVertexBufferIndices;
|
||||
|
||||
wgpu::ShaderStage mStagesRequiringStorageBufferLength = wgpu::ShaderStage::None;
|
||||
|
|
|
@ -236,17 +236,23 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
MTLDepthStencilDescriptor* MakeDepthStencilDesc(
|
||||
NSRef<MTLDepthStencilDescriptor> MakeDepthStencilDesc(
|
||||
const DepthStencilStateDescriptor* descriptor) {
|
||||
MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = [MTLDepthStencilDescriptor new];
|
||||
NSRef<MTLDepthStencilDescriptor> mtlDepthStencilDescRef =
|
||||
AcquireNSRef([MTLDepthStencilDescriptor new]);
|
||||
MTLDepthStencilDescriptor* mtlDepthStencilDescriptor = mtlDepthStencilDescRef.Get();
|
||||
|
||||
mtlDepthStencilDescriptor.depthCompareFunction =
|
||||
ToMetalCompareFunction(descriptor->depthCompare);
|
||||
mtlDepthStencilDescriptor.depthWriteEnabled = descriptor->depthWriteEnabled;
|
||||
|
||||
if (StencilTestEnabled(descriptor)) {
|
||||
MTLStencilDescriptor* backFaceStencil = [MTLStencilDescriptor new];
|
||||
MTLStencilDescriptor* frontFaceStencil = [MTLStencilDescriptor new];
|
||||
NSRef<MTLStencilDescriptor> backFaceStencilRef =
|
||||
AcquireNSRef([MTLStencilDescriptor new]);
|
||||
MTLStencilDescriptor* backFaceStencil = backFaceStencilRef.Get();
|
||||
NSRef<MTLStencilDescriptor> frontFaceStencilRef =
|
||||
AcquireNSRef([MTLStencilDescriptor new]);
|
||||
MTLStencilDescriptor* frontFaceStencil = frontFaceStencilRef.Get();
|
||||
|
||||
backFaceStencil.stencilCompareFunction =
|
||||
ToMetalCompareFunction(descriptor->stencilBack.compare);
|
||||
|
@ -272,12 +278,9 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
mtlDepthStencilDescriptor.backFaceStencil = backFaceStencil;
|
||||
mtlDepthStencilDescriptor.frontFaceStencil = frontFaceStencil;
|
||||
|
||||
[backFaceStencil release];
|
||||
[frontFaceStencil release];
|
||||
}
|
||||
|
||||
return mtlDepthStencilDescriptor;
|
||||
return mtlDepthStencilDescRef;
|
||||
}
|
||||
|
||||
MTLWinding MTLFrontFace(wgpu::FrontFace face) {
|
||||
|
@ -317,20 +320,19 @@ namespace dawn_native { namespace metal {
|
|||
mMtlCullMode = ToMTLCullMode(GetCullMode());
|
||||
auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice();
|
||||
|
||||
MTLRenderPipelineDescriptor* descriptorMTL = [MTLRenderPipelineDescriptor new];
|
||||
NSRef<MTLRenderPipelineDescriptor> descriptorMTLRef =
|
||||
AcquireNSRef([MTLRenderPipelineDescriptor new]);
|
||||
MTLRenderPipelineDescriptor* descriptorMTL = descriptorMTLRef.Get();
|
||||
|
||||
// TODO: MakeVertexDesc should be const in the future, so we don't need to call it here when
|
||||
// vertex pulling is enabled
|
||||
MTLVertexDescriptor* vertexDesc = MakeVertexDesc();
|
||||
descriptorMTL.vertexDescriptor = vertexDesc;
|
||||
[vertexDesc release];
|
||||
NSRef<MTLVertexDescriptor> vertexDesc = MakeVertexDesc();
|
||||
|
||||
// Calling MakeVertexDesc first is important since it sets indices for packed bindings
|
||||
if (GetDevice()->IsToggleEnabled(Toggle::MetalEnableVertexPulling)) {
|
||||
// Calling MakeVertexDesc first is important since it sets indices for packed bindings
|
||||
MTLVertexDescriptor* emptyVertexDesc = [MTLVertexDescriptor new];
|
||||
descriptorMTL.vertexDescriptor = emptyVertexDesc;
|
||||
[emptyVertexDesc release];
|
||||
vertexDesc = AcquireNSRef([MTLVertexDescriptor new]);
|
||||
}
|
||||
descriptorMTL.vertexDescriptor = vertexDesc.Get();
|
||||
|
||||
ShaderModule* vertexModule = ToBackend(descriptor->vertexStage.module);
|
||||
const char* vertexEntryPoint = descriptor->vertexStage.entryPoint;
|
||||
|
@ -339,7 +341,7 @@ namespace dawn_native { namespace metal {
|
|||
ToBackend(GetLayout()), &vertexData, 0xFFFFFFFF,
|
||||
this));
|
||||
|
||||
descriptorMTL.vertexFunction = vertexData.function;
|
||||
descriptorMTL.vertexFunction = vertexData.function.Get();
|
||||
if (vertexData.needsStorageBufferLength) {
|
||||
mStagesRequiringStorageBufferLength |= wgpu::ShaderStage::Vertex;
|
||||
}
|
||||
|
@ -351,7 +353,7 @@ namespace dawn_native { namespace metal {
|
|||
ToBackend(GetLayout()), &fragmentData,
|
||||
descriptor->sampleMask));
|
||||
|
||||
descriptorMTL.fragmentFunction = fragmentData.function;
|
||||
descriptorMTL.fragmentFunction = fragmentData.function.Get();
|
||||
if (fragmentData.needsStorageBufferLength) {
|
||||
mStagesRequiringStorageBufferLength |= wgpu::ShaderStage::Fragment;
|
||||
}
|
||||
|
@ -384,11 +386,11 @@ namespace dawn_native { namespace metal {
|
|||
descriptorMTL.alphaToCoverageEnabled = descriptor->alphaToCoverageEnabled;
|
||||
|
||||
{
|
||||
NSError* error = nil;
|
||||
mMtlRenderPipelineState = [mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
|
||||
error:&error];
|
||||
[descriptorMTL release];
|
||||
if (error != nil) {
|
||||
NSError* error = nullptr;
|
||||
mMtlRenderPipelineState =
|
||||
AcquireNSPRef([mtlDevice newRenderPipelineStateWithDescriptor:descriptorMTL
|
||||
error:&error]);
|
||||
if (error != nullptr) {
|
||||
NSLog(@" error => %@", error);
|
||||
return DAWN_INTERNAL_ERROR("Error creating rendering pipeline state");
|
||||
}
|
||||
|
@ -397,19 +399,14 @@ namespace dawn_native { namespace metal {
|
|||
// Create depth stencil state and cache it, fetch the cached depth stencil state when we
|
||||
// call setDepthStencilState() for a given render pipeline in CommandEncoder, in order to
|
||||
// improve performance.
|
||||
MTLDepthStencilDescriptor* depthStencilDesc =
|
||||
NSRef<MTLDepthStencilDescriptor> depthStencilDesc =
|
||||
MakeDepthStencilDesc(GetDepthStencilStateDescriptor());
|
||||
mMtlDepthStencilState = [mtlDevice newDepthStencilStateWithDescriptor:depthStencilDesc];
|
||||
[depthStencilDesc release];
|
||||
mMtlDepthStencilState =
|
||||
AcquireNSPRef([mtlDevice newDepthStencilStateWithDescriptor:depthStencilDesc.Get()]);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
RenderPipeline::~RenderPipeline() {
|
||||
[mMtlRenderPipelineState release];
|
||||
[mMtlDepthStencilState release];
|
||||
}
|
||||
|
||||
MTLPrimitiveType RenderPipeline::GetMTLPrimitiveTopology() const {
|
||||
return mMtlPrimitiveTopology;
|
||||
}
|
||||
|
@ -423,11 +420,11 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
void RenderPipeline::Encode(id<MTLRenderCommandEncoder> encoder) {
|
||||
[encoder setRenderPipelineState:mMtlRenderPipelineState];
|
||||
[encoder setRenderPipelineState:mMtlRenderPipelineState.Get()];
|
||||
}
|
||||
|
||||
id<MTLDepthStencilState> RenderPipeline::GetMTLDepthStencilState() {
|
||||
return mMtlDepthStencilState;
|
||||
return mMtlDepthStencilState.Get();
|
||||
}
|
||||
|
||||
uint32_t RenderPipeline::GetMtlVertexBufferIndex(VertexBufferSlot slot) const {
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/Sampler.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -31,9 +33,8 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
private:
|
||||
Sampler(Device* device, const SamplerDescriptor* descriptor);
|
||||
~Sampler() override;
|
||||
|
||||
id<MTLSamplerState> mMtlSamplerState = nil;
|
||||
NSPRef<id<MTLSamplerState>> mMtlSamplerState;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -62,7 +62,8 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
Sampler::Sampler(Device* device, const SamplerDescriptor* descriptor)
|
||||
: SamplerBase(device, descriptor) {
|
||||
MTLSamplerDescriptor* mtlDesc = [MTLSamplerDescriptor new];
|
||||
NSRef<MTLSamplerDescriptor> mtlDescRef = AcquireNSRef([MTLSamplerDescriptor new]);
|
||||
MTLSamplerDescriptor* mtlDesc = mtlDescRef.Get();
|
||||
|
||||
mtlDesc.minFilter = FilterModeToMinMagFilter(descriptor->minFilter);
|
||||
mtlDesc.magFilter = FilterModeToMinMagFilter(descriptor->magFilter);
|
||||
|
@ -83,17 +84,12 @@ namespace dawn_native { namespace metal {
|
|||
// Metal debug device errors.
|
||||
}
|
||||
|
||||
mMtlSamplerState = [device->GetMTLDevice() newSamplerStateWithDescriptor:mtlDesc];
|
||||
|
||||
[mtlDesc release];
|
||||
}
|
||||
|
||||
Sampler::~Sampler() {
|
||||
[mMtlSamplerState release];
|
||||
mMtlSamplerState =
|
||||
AcquireNSPRef([device->GetMTLDevice() newSamplerStateWithDescriptor:mtlDesc]);
|
||||
}
|
||||
|
||||
id<MTLSamplerState> Sampler::GetMTLSamplerState() {
|
||||
return mMtlSamplerState;
|
||||
return mMtlSamplerState.Get();
|
||||
}
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
|
||||
#include "dawn_native/ShaderModule.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
#include "common/NSRef.h"
|
||||
#include "dawn_native/Error.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace spirv_cross {
|
||||
class CompilerMSL;
|
||||
}
|
||||
|
@ -37,11 +38,8 @@ namespace dawn_native { namespace metal {
|
|||
const ShaderModuleDescriptor* descriptor);
|
||||
|
||||
struct MetalFunctionData {
|
||||
id<MTLFunction> function = nil;
|
||||
NSPRef<id<MTLFunction>> function;
|
||||
bool needsStorageBufferLength;
|
||||
~MetalFunctionData() {
|
||||
[function release];
|
||||
}
|
||||
};
|
||||
MaybeError CreateFunction(const char* entryPointName,
|
||||
SingleShaderStage stage,
|
||||
|
|
|
@ -142,7 +142,6 @@ namespace dawn_native { namespace metal {
|
|||
{
|
||||
// SPIRV-Cross also supports re-ordering attributes but it seems to do the correct thing
|
||||
// by default.
|
||||
NSString* mslSource;
|
||||
std::string msl = compiler.compile();
|
||||
|
||||
// Some entry point names are forbidden in MSL so SPIRV-Cross modifies them. Query the
|
||||
|
@ -159,14 +158,17 @@ namespace dawn_native { namespace metal {
|
|||
#pragma clang diagnostic ignored "-Wall"
|
||||
#endif
|
||||
)" + msl;
|
||||
mslSource = [[NSString alloc] initWithUTF8String:msl.c_str()];
|
||||
|
||||
NSRef<NSString> mslSource =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:msl.c_str()]);
|
||||
|
||||
auto mtlDevice = ToBackend(GetDevice())->GetMTLDevice();
|
||||
NSError* error = nil;
|
||||
id<MTLLibrary> library = [mtlDevice newLibraryWithSource:mslSource
|
||||
options:nil
|
||||
error:&error];
|
||||
if (error != nil) {
|
||||
NSError* error = nullptr;
|
||||
NSPRef<id<MTLLibrary>> library =
|
||||
AcquireNSPRef([mtlDevice newLibraryWithSource:mslSource.Get()
|
||||
options:nullptr
|
||||
error:&error]);
|
||||
if (error != nullptr) {
|
||||
if (error.code != MTLLibraryErrorCompileWarning) {
|
||||
const char* errorString = [error.localizedDescription UTF8String];
|
||||
return DAWN_VALIDATION_ERROR(std::string("Unable to create library object: ") +
|
||||
|
@ -174,9 +176,9 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
NSString* name = [[NSString alloc] initWithUTF8String:modifiedEntryPointName.c_str()];
|
||||
out->function = [library newFunctionWithName:name];
|
||||
[library release];
|
||||
NSRef<NSString> name =
|
||||
AcquireNSRef([[NSString alloc] initWithUTF8String:modifiedEntryPointName.c_str()]);
|
||||
out->function = AcquireNSPRef([*library newFunctionWithName:name.Get()]);
|
||||
}
|
||||
|
||||
out->needsStorageBufferLength = compiler.needs_buffer_size_buffer();
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/StagingBuffer.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
@ -26,7 +28,6 @@ namespace dawn_native { namespace metal {
|
|||
class StagingBuffer : public StagingBufferBase {
|
||||
public:
|
||||
StagingBuffer(size_t size, Device* device);
|
||||
~StagingBuffer() override;
|
||||
|
||||
id<MTLBuffer> GetBufferHandle() const;
|
||||
|
||||
|
@ -34,7 +35,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
private:
|
||||
Device* mDevice;
|
||||
id<MTLBuffer> mBuffer = nil;
|
||||
NSPRef<id<MTLBuffer>> mBuffer;
|
||||
};
|
||||
}} // namespace dawn_native::metal
|
||||
|
||||
|
|
|
@ -23,14 +23,15 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
MaybeError StagingBuffer::Initialize() {
|
||||
const size_t bufferSize = GetSize();
|
||||
mBuffer = [mDevice->GetMTLDevice() newBufferWithLength:bufferSize
|
||||
options:MTLResourceStorageModeShared];
|
||||
mBuffer = AcquireNSPRef([mDevice->GetMTLDevice()
|
||||
newBufferWithLength:bufferSize
|
||||
options:MTLResourceStorageModeShared]);
|
||||
|
||||
if (mBuffer == nil) {
|
||||
if (mBuffer == nullptr) {
|
||||
return DAWN_OUT_OF_MEMORY_ERROR("Unable to allocate buffer.");
|
||||
}
|
||||
|
||||
mMappedPointer = [mBuffer contents];
|
||||
mMappedPointer = [*mBuffer contents];
|
||||
if (mMappedPointer == nullptr) {
|
||||
return DAWN_INTERNAL_ERROR("Unable to map staging buffer.");
|
||||
}
|
||||
|
@ -38,13 +39,8 @@ namespace dawn_native { namespace metal {
|
|||
return {};
|
||||
}
|
||||
|
||||
StagingBuffer::~StagingBuffer() {
|
||||
[mBuffer release];
|
||||
mBuffer = nil;
|
||||
}
|
||||
|
||||
id<MTLBuffer> StagingBuffer::GetBufferHandle() const {
|
||||
return mBuffer;
|
||||
return mBuffer.Get();
|
||||
}
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
|
||||
#include "dawn_native/SwapChain.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
|
||||
@class CAMetalLayer;
|
||||
@protocol CAMetalDrawable;
|
||||
|
||||
|
@ -47,9 +49,9 @@ namespace dawn_native { namespace metal {
|
|||
using NewSwapChainBase::NewSwapChainBase;
|
||||
MaybeError Initialize(NewSwapChainBase* previousSwapChain);
|
||||
|
||||
CAMetalLayer* mLayer = nullptr;
|
||||
NSRef<CAMetalLayer> mLayer;
|
||||
|
||||
id<CAMetalDrawable> mCurrentDrawable = nil;
|
||||
NSPRef<id<CAMetalDrawable>> mCurrentDrawable;
|
||||
Ref<Texture> mTexture;
|
||||
|
||||
MaybeError PresentImpl() override;
|
||||
|
|
|
@ -92,15 +92,15 @@ namespace dawn_native { namespace metal {
|
|||
CGSize size = {};
|
||||
size.width = GetWidth();
|
||||
size.height = GetHeight();
|
||||
[mLayer setDrawableSize:size];
|
||||
[*mLayer setDrawableSize:size];
|
||||
|
||||
[mLayer setFramebufferOnly:(GetUsage() == wgpu::TextureUsage::RenderAttachment)];
|
||||
[mLayer setDevice:ToBackend(GetDevice())->GetMTLDevice()];
|
||||
[mLayer setPixelFormat:MetalPixelFormat(GetFormat())];
|
||||
[*mLayer setFramebufferOnly:(GetUsage() == wgpu::TextureUsage::RenderAttachment)];
|
||||
[*mLayer setDevice:ToBackend(GetDevice())->GetMTLDevice()];
|
||||
[*mLayer setPixelFormat:MetalPixelFormat(GetFormat())];
|
||||
|
||||
#if defined(DAWN_PLATFORM_MACOS)
|
||||
if (@available(macos 10.13, *)) {
|
||||
[mLayer setDisplaySyncEnabled:(GetPresentMode() != wgpu::PresentMode::Immediate)];
|
||||
[*mLayer setDisplaySyncEnabled:(GetPresentMode() != wgpu::PresentMode::Immediate)];
|
||||
}
|
||||
#endif // defined(DAWN_PLATFORM_MACOS)
|
||||
|
||||
|
@ -110,40 +110,36 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
MaybeError SwapChain::PresentImpl() {
|
||||
ASSERT(mCurrentDrawable != nil);
|
||||
[mCurrentDrawable present];
|
||||
ASSERT(mCurrentDrawable != nullptr);
|
||||
[*mCurrentDrawable present];
|
||||
|
||||
mTexture->Destroy();
|
||||
mTexture = nullptr;
|
||||
|
||||
[mCurrentDrawable release];
|
||||
mCurrentDrawable = nil;
|
||||
mCurrentDrawable = nullptr;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
ResultOrError<TextureViewBase*> SwapChain::GetCurrentTextureViewImpl() {
|
||||
ASSERT(mCurrentDrawable == nil);
|
||||
mCurrentDrawable = [mLayer nextDrawable];
|
||||
[mCurrentDrawable retain];
|
||||
ASSERT(mCurrentDrawable == nullptr);
|
||||
mCurrentDrawable = [*mLayer nextDrawable];
|
||||
|
||||
TextureDescriptor textureDesc = GetSwapChainBaseTextureDescriptor(this);
|
||||
|
||||
// mTexture will add a reference to mCurrentDrawable.texture to keep it alive.
|
||||
mTexture =
|
||||
AcquireRef(new Texture(ToBackend(GetDevice()), &textureDesc, mCurrentDrawable.texture));
|
||||
mTexture = AcquireRef(
|
||||
new Texture(ToBackend(GetDevice()), &textureDesc, [*mCurrentDrawable texture]));
|
||||
return mTexture->CreateView(nullptr);
|
||||
}
|
||||
|
||||
void SwapChain::DetachFromSurfaceImpl() {
|
||||
ASSERT((mTexture.Get() == nullptr) == (mCurrentDrawable == nil));
|
||||
ASSERT((mTexture.Get() == nullptr) == (mCurrentDrawable == nullptr));
|
||||
|
||||
if (mTexture.Get() != nullptr) {
|
||||
mTexture->Destroy();
|
||||
mTexture = nullptr;
|
||||
|
||||
[mCurrentDrawable release];
|
||||
mCurrentDrawable = nil;
|
||||
mCurrentDrawable = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -17,9 +17,11 @@
|
|||
|
||||
#include "dawn_native/Texture.h"
|
||||
|
||||
#include "common/NSRef.h"
|
||||
#include "dawn_native/DawnNative.h"
|
||||
|
||||
#include <IOSurface/IOSurfaceRef.h>
|
||||
#import <Metal/Metal.h>
|
||||
#include "dawn_native/DawnNative.h"
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
|
@ -34,7 +36,9 @@ namespace dawn_native { namespace metal {
|
|||
class Texture final : public TextureBase {
|
||||
public:
|
||||
Texture(Device* device, const TextureDescriptor* descriptor);
|
||||
Texture(Device* device, const TextureDescriptor* descriptor, id<MTLTexture> mtlTexture);
|
||||
Texture(Device* device,
|
||||
const TextureDescriptor* descriptor,
|
||||
NSPRef<id<MTLTexture>> mtlTexture);
|
||||
Texture(Device* device,
|
||||
const ExternalImageDescriptor* descriptor,
|
||||
IOSurfaceRef ioSurface,
|
||||
|
@ -51,7 +55,7 @@ namespace dawn_native { namespace metal {
|
|||
|
||||
MaybeError ClearTexture(const SubresourceRange& range, TextureBase::ClearValue clearValue);
|
||||
|
||||
id<MTLTexture> mMtlTexture = nil;
|
||||
NSPRef<id<MTLTexture>> mMtlTexture;
|
||||
};
|
||||
|
||||
class TextureView final : public TextureViewBase {
|
||||
|
@ -61,9 +65,7 @@ namespace dawn_native { namespace metal {
|
|||
id<MTLTexture> GetMTLTexture();
|
||||
|
||||
private:
|
||||
~TextureView() override;
|
||||
|
||||
id<MTLTexture> mMtlTextureView = nil;
|
||||
NSPRef<id<MTLTexture>> mMtlTextureView;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -298,9 +298,10 @@ namespace dawn_native { namespace metal {
|
|||
return {};
|
||||
}
|
||||
|
||||
MTLTextureDescriptor* CreateMetalTextureDescriptor(DeviceBase* device,
|
||||
const TextureDescriptor* descriptor) {
|
||||
MTLTextureDescriptor* mtlDesc = [MTLTextureDescriptor new];
|
||||
NSRef<MTLTextureDescriptor> CreateMetalTextureDescriptor(DeviceBase* device,
|
||||
const TextureDescriptor* descriptor) {
|
||||
NSRef<MTLTextureDescriptor> mtlDescRef = AcquireNSRef([MTLTextureDescriptor new]);
|
||||
MTLTextureDescriptor* mtlDesc = mtlDescRef.Get();
|
||||
|
||||
mtlDesc.width = descriptor->size.width;
|
||||
mtlDesc.height = descriptor->size.height;
|
||||
|
@ -338,14 +339,14 @@ namespace dawn_native { namespace metal {
|
|||
UNREACHABLE();
|
||||
}
|
||||
|
||||
return mtlDesc;
|
||||
return mtlDescRef;
|
||||
}
|
||||
|
||||
Texture::Texture(Device* device, const TextureDescriptor* descriptor)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedInternal) {
|
||||
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
|
||||
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc];
|
||||
[mtlDesc release];
|
||||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(device, descriptor);
|
||||
mMtlTexture =
|
||||
AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()]);
|
||||
|
||||
if (device->IsToggleEnabled(Toggle::NonzeroClearResourcesOnCreationForTesting)) {
|
||||
device->ConsumedError(
|
||||
|
@ -353,9 +354,11 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
}
|
||||
|
||||
Texture::Texture(Device* device, const TextureDescriptor* descriptor, id<MTLTexture> mtlTexture)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedInternal), mMtlTexture(mtlTexture) {
|
||||
[mMtlTexture retain];
|
||||
Texture::Texture(Device* device,
|
||||
const TextureDescriptor* descriptor,
|
||||
NSPRef<id<MTLTexture>> mtlTexture)
|
||||
: TextureBase(device, descriptor, TextureState::OwnedInternal),
|
||||
mMtlTexture(std::move(mtlTexture)) {
|
||||
}
|
||||
|
||||
Texture::Texture(Device* device,
|
||||
|
@ -365,13 +368,13 @@ namespace dawn_native { namespace metal {
|
|||
: TextureBase(device,
|
||||
reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor),
|
||||
TextureState::OwnedInternal) {
|
||||
MTLTextureDescriptor* mtlDesc = CreateMetalTextureDescriptor(
|
||||
NSRef<MTLTextureDescriptor> mtlDesc = CreateMetalTextureDescriptor(
|
||||
device, reinterpret_cast<const TextureDescriptor*>(descriptor->cTextureDescriptor));
|
||||
mtlDesc.storageMode = kIOSurfaceStorageMode;
|
||||
mMtlTexture = [device->GetMTLDevice() newTextureWithDescriptor:mtlDesc
|
||||
iosurface:ioSurface
|
||||
plane:plane];
|
||||
[mtlDesc release];
|
||||
[*mtlDesc setStorageMode:kIOSurfaceStorageMode];
|
||||
|
||||
mMtlTexture = AcquireNSPRef([device->GetMTLDevice() newTextureWithDescriptor:mtlDesc.Get()
|
||||
iosurface:ioSurface
|
||||
plane:plane]);
|
||||
|
||||
SetIsSubresourceContentInitialized(descriptor->isInitialized, GetAllSubresources());
|
||||
}
|
||||
|
@ -381,14 +384,11 @@ namespace dawn_native { namespace metal {
|
|||
}
|
||||
|
||||
void Texture::DestroyImpl() {
|
||||
if (GetTextureState() == TextureState::OwnedInternal) {
|
||||
[mMtlTexture release];
|
||||
mMtlTexture = nil;
|
||||
}
|
||||
mMtlTexture = nullptr;
|
||||
}
|
||||
|
||||
id<MTLTexture> Texture::GetMTLTexture() {
|
||||
return mMtlTexture;
|
||||
return mMtlTexture.Get();
|
||||
}
|
||||
|
||||
MaybeError Texture::ClearTexture(const SubresourceRange& range,
|
||||
|
@ -419,8 +419,11 @@ namespace dawn_native { namespace metal {
|
|||
continue;
|
||||
}
|
||||
|
||||
MTLRenderPassDescriptor* descriptor =
|
||||
// Note that this creates a descriptor that's autoreleased so we don't use
|
||||
// AcquireNSRef
|
||||
NSRef<MTLRenderPassDescriptor> descriptorRef =
|
||||
[MTLRenderPassDescriptor renderPassDescriptor];
|
||||
MTLRenderPassDescriptor* descriptor = descriptorRef.Get();
|
||||
|
||||
// At least one aspect needs clearing. Iterate the aspects individually to
|
||||
// determine which to clear.
|
||||
|
@ -462,7 +465,7 @@ namespace dawn_native { namespace metal {
|
|||
// Create multiple render passes with each subresource as a color attachment to
|
||||
// clear them all. Only do this for array layers to ensure all attachments have
|
||||
// the same size.
|
||||
MTLRenderPassDescriptor* descriptor = nil;
|
||||
NSRef<MTLRenderPassDescriptor> descriptor;
|
||||
uint32_t attachment = 0;
|
||||
|
||||
for (uint32_t arrayLayer = range.baseArrayLayer;
|
||||
|
@ -474,30 +477,33 @@ namespace dawn_native { namespace metal {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (descriptor == nil) {
|
||||
if (descriptor == nullptr) {
|
||||
// Note that this creates a descriptor that's autoreleased so we don't
|
||||
// use AcquireNSRef
|
||||
descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
|
||||
}
|
||||
|
||||
descriptor.colorAttachments[attachment].texture = GetMTLTexture();
|
||||
descriptor.colorAttachments[attachment].loadAction = MTLLoadActionClear;
|
||||
descriptor.colorAttachments[attachment].storeAction = MTLStoreActionStore;
|
||||
descriptor.colorAttachments[attachment].clearColor =
|
||||
[*descriptor colorAttachments][attachment].texture = GetMTLTexture();
|
||||
[*descriptor colorAttachments][attachment].loadAction = MTLLoadActionClear;
|
||||
[*descriptor colorAttachments][attachment].storeAction =
|
||||
MTLStoreActionStore;
|
||||
[*descriptor colorAttachments][attachment].clearColor =
|
||||
MTLClearColorMake(dClearColor, dClearColor, dClearColor, dClearColor);
|
||||
descriptor.colorAttachments[attachment].level = level;
|
||||
descriptor.colorAttachments[attachment].slice = arrayLayer;
|
||||
[*descriptor colorAttachments][attachment].level = level;
|
||||
[*descriptor colorAttachments][attachment].slice = arrayLayer;
|
||||
|
||||
attachment++;
|
||||
|
||||
if (attachment == kMaxColorAttachments) {
|
||||
attachment = 0;
|
||||
commandContext->BeginRender(descriptor);
|
||||
commandContext->BeginRender(descriptor.Get());
|
||||
commandContext->EndRender();
|
||||
descriptor = nil;
|
||||
descriptor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptor != nil) {
|
||||
commandContext->BeginRender(descriptor);
|
||||
if (descriptor != nullptr) {
|
||||
commandContext->BeginRender(descriptor.Get());
|
||||
commandContext->EndRender();
|
||||
}
|
||||
}
|
||||
|
@ -591,9 +597,9 @@ namespace dawn_native { namespace metal {
|
|||
id<MTLTexture> mtlTexture = ToBackend(texture)->GetMTLTexture();
|
||||
|
||||
if (!UsageNeedsTextureView(texture->GetUsage())) {
|
||||
mMtlTextureView = nil;
|
||||
mMtlTextureView = nullptr;
|
||||
} else if (!RequiresCreatingNewTextureView(texture, descriptor)) {
|
||||
mMtlTextureView = [mtlTexture retain];
|
||||
mMtlTextureView = mtlTexture;
|
||||
} else {
|
||||
MTLPixelFormat format = MetalPixelFormat(descriptor->format);
|
||||
if (descriptor->aspect == wgpu::TextureAspect::StencilOnly) {
|
||||
|
@ -616,19 +622,16 @@ namespace dawn_native { namespace metal {
|
|||
auto arrayLayerRange =
|
||||
NSMakeRange(descriptor->baseArrayLayer, descriptor->arrayLayerCount);
|
||||
|
||||
mMtlTextureView = [mtlTexture newTextureViewWithPixelFormat:format
|
||||
mMtlTextureView =
|
||||
AcquireNSPRef([mtlTexture newTextureViewWithPixelFormat:format
|
||||
textureType:textureViewType
|
||||
levels:mipLevelRange
|
||||
slices:arrayLayerRange];
|
||||
slices:arrayLayerRange]);
|
||||
}
|
||||
}
|
||||
|
||||
TextureView::~TextureView() {
|
||||
[mMtlTextureView release];
|
||||
}
|
||||
|
||||
id<MTLTexture> TextureView::GetMTLTexture() {
|
||||
ASSERT(mMtlTextureView != nil);
|
||||
return mMtlTextureView;
|
||||
ASSERT(mMtlTextureView != nullptr);
|
||||
return mMtlTextureView.Get();
|
||||
}
|
||||
}} // namespace dawn_native::metal
|
||||
|
|
|
@ -118,7 +118,6 @@ TEST(Ref, Gets) {
|
|||
test->Release();
|
||||
|
||||
EXPECT_EQ(test.Get(), original);
|
||||
EXPECT_EQ(&*test, original);
|
||||
EXPECT_EQ(test->GetThis(), original);
|
||||
}
|
||||
|
||||
|
@ -127,7 +126,6 @@ TEST(Ref, DefaultsToNull) {
|
|||
Ref<RCTest> test;
|
||||
|
||||
EXPECT_EQ(test.Get(), nullptr);
|
||||
EXPECT_EQ(&*test, nullptr);
|
||||
EXPECT_EQ(test->GetThis(), nullptr);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue