mirror of
https://github.com/encounter/dawn-cmake.git
synced 2025-06-04 13:41:42 +00:00
Metal: Implement the backend connection and adapter.
BUG=dawn:29 Change-Id: Idaca7d2f8ac52d5f46d8030571b5e2da3a573a97 Reviewed-on: https://dawn-review.googlesource.com/c/3940 Commit-Queue: Corentin Wallez <cwallez@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
a27bdb4a5e
commit
978fa65a2c
2
BUILD.gn
2
BUILD.gn
@ -568,6 +568,8 @@ source_set("libdawn_native_sources") {
|
||||
"IOKit.framework",
|
||||
]
|
||||
sources += [
|
||||
"src/dawn_native/metal/BackendMTL.h",
|
||||
"src/dawn_native/metal/BackendMTL.mm",
|
||||
"src/dawn_native/metal/BufferMTL.h",
|
||||
"src/dawn_native/metal/BufferMTL.mm",
|
||||
"src/dawn_native/metal/CommandBufferMTL.h",
|
||||
|
31
src/dawn_native/metal/BackendMTL.h
Normal file
31
src/dawn_native/metal/BackendMTL.h
Normal file
@ -0,0 +1,31 @@
|
||||
// Copyright 2019 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 DAWNNATIVE_METAL_BACKENDMTL_H_
|
||||
#define DAWNNATIVE_METAL_BACKENDMTL_H_
|
||||
|
||||
#include "dawn_native/BackendConnection.h"
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
class Backend : public BackendConnection {
|
||||
public:
|
||||
Backend(InstanceBase* instance);
|
||||
|
||||
std::vector<std::unique_ptr<AdapterBase>> DiscoverDefaultAdapters() override;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
||||
#endif // DAWNNATIVE_METAL_BACKENDMTL_H_
|
161
src/dawn_native/metal/BackendMTL.mm
Normal file
161
src/dawn_native/metal/BackendMTL.mm
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
#include "dawn_native/metal/BackendMTL.h"
|
||||
|
||||
#include "dawn_native/MetalBackend.h"
|
||||
#include "dawn_native/metal/DeviceMTL.h"
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
namespace {
|
||||
// Since CGDisplayIOServicePort was deprecated in macOS 10.9, we need create
|
||||
// an alternative function for getting I/O service port from current display.
|
||||
io_service_t GetDisplayIOServicePort() {
|
||||
// The matching service port (or 0 if none can be found)
|
||||
io_service_t servicePort = 0;
|
||||
|
||||
// Create matching dictionary for display service
|
||||
CFMutableDictionaryRef matchingDict = IOServiceMatching("IODisplayConnect");
|
||||
if (matchingDict == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
io_iterator_t iter;
|
||||
// IOServiceGetMatchingServices look up the default master ports that match a
|
||||
// matching dictionary, and will consume the reference on the matching dictionary,
|
||||
// so we don't need to release the dictionary, but the iterator handle should
|
||||
// be released when its iteration is finished.
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter) !=
|
||||
kIOReturnSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Vendor number and product number of current main display
|
||||
const uint32_t displayVendorNumber = CGDisplayVendorNumber(kCGDirectMainDisplay);
|
||||
const uint32_t displayProductNumber = CGDisplayModelNumber(kCGDirectMainDisplay);
|
||||
|
||||
io_service_t serv;
|
||||
while ((serv = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
|
||||
CFDictionaryRef displayInfo =
|
||||
IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
|
||||
|
||||
CFNumberRef vendorIDRef, productIDRef;
|
||||
Boolean success;
|
||||
// The ownership of CF object follows the 'Get Rule', we don't need to
|
||||
// release these values
|
||||
success = CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayVendorID),
|
||||
(const void**)&vendorIDRef);
|
||||
success &= CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayProductID),
|
||||
(const void**)&productIDRef);
|
||||
if (success) {
|
||||
CFIndex vendorID = 0, productID = 0;
|
||||
CFNumberGetValue(vendorIDRef, kCFNumberSInt32Type, &vendorID);
|
||||
CFNumberGetValue(productIDRef, kCFNumberSInt32Type, &productID);
|
||||
|
||||
if (vendorID == displayVendorNumber && productID == displayProductNumber) {
|
||||
// Check if vendor id and product id match with current display's
|
||||
// If it does, we find the desired service port
|
||||
servicePort = serv;
|
||||
CFRelease(displayInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(displayInfo);
|
||||
IOObjectRelease(serv);
|
||||
}
|
||||
IOObjectRelease(iter);
|
||||
return servicePort;
|
||||
}
|
||||
|
||||
// Get integer property from registry entry.
|
||||
uint32_t GetEntryProperty(io_registry_entry_t entry, CFStringRef name) {
|
||||
uint32_t value = 0;
|
||||
|
||||
// Recursively search registry entry and its parents for property name
|
||||
// The data should release with CFRelease
|
||||
CFDataRef data = static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
|
||||
entry, kIOServicePlane, name, kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents));
|
||||
|
||||
if (data != nullptr) {
|
||||
const uint32_t* valuePtr =
|
||||
reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data));
|
||||
if (valuePtr) {
|
||||
value = *valuePtr;
|
||||
}
|
||||
|
||||
CFRelease(data);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
// The Metal backend's Adapter.
|
||||
|
||||
class Adapter : public AdapterBase {
|
||||
public:
|
||||
Adapter(InstanceBase* instance, id<MTLDevice> device)
|
||||
: AdapterBase(instance, BackendType::Metal), mDevice([device retain]) {
|
||||
mPCIInfo.name = std::string([mDevice.name UTF8String]);
|
||||
// Gather the PCI device and vendor IDs based on which device is rendering to the
|
||||
// main display. This is obviously wrong for systems with multiple devices.
|
||||
// TODO(cwallez@chromium.org): Once Chromium has the macOS 10.13 SDK rolled, we
|
||||
// should use MTLDevice.registryID to gather the information.
|
||||
io_registry_entry_t entry = GetDisplayIOServicePort();
|
||||
if (entry != IO_OBJECT_NULL) {
|
||||
mPCIInfo.vendorId = GetEntryProperty(entry, CFSTR("vendor-id"));
|
||||
mPCIInfo.deviceId = GetEntryProperty(entry, CFSTR("device-id"));
|
||||
IOObjectRelease(entry);
|
||||
}
|
||||
}
|
||||
|
||||
~Adapter() override {
|
||||
[mDevice release];
|
||||
}
|
||||
|
||||
private:
|
||||
ResultOrError<DeviceBase*> CreateDeviceImpl() override {
|
||||
return {new Device(this, mDevice)};
|
||||
}
|
||||
|
||||
id<MTLDevice> mDevice = nil;
|
||||
};
|
||||
|
||||
// Implementation of the Metal backend's BackendConnection
|
||||
|
||||
Backend::Backend(InstanceBase* instance) : BackendConnection(instance, BackendType::Metal) {
|
||||
}
|
||||
|
||||
std::vector<std::unique_ptr<AdapterBase>> Backend::DiscoverDefaultAdapters() {
|
||||
NSArray<id<MTLDevice>>* devices = MTLCopyAllDevices();
|
||||
|
||||
std::vector<std::unique_ptr<AdapterBase>> adapters;
|
||||
for (id<MTLDevice> device in devices) {
|
||||
adapters.push_back(std::make_unique<Adapter>(GetInstance(), device));
|
||||
}
|
||||
|
||||
[devices release];
|
||||
return adapters;
|
||||
}
|
||||
|
||||
BackendConnection* Connect(InstanceBase* instance) {
|
||||
return new Backend(instance);
|
||||
}
|
||||
|
||||
}} // namespace dawn_native::metal
|
@ -34,7 +34,7 @@ namespace dawn_native { namespace metal {
|
||||
|
||||
class Device : public DeviceBase {
|
||||
public:
|
||||
Device();
|
||||
Device(AdapterBase* adapter, id<MTLDevice> mtlDevice);
|
||||
~Device();
|
||||
|
||||
CommandBufferBase* CreateCommandBuffer(CommandBufferBuilder* builder) override;
|
||||
@ -47,8 +47,6 @@ namespace dawn_native { namespace metal {
|
||||
Serial GetLastSubmittedCommandSerial() const final override;
|
||||
void TickImpl() override;
|
||||
|
||||
const dawn_native::PCIInfo& GetPCIInfo() const override;
|
||||
|
||||
id<MTLDevice> GetMTLDevice();
|
||||
|
||||
id<MTLCommandBuffer> GetPendingCommandBuffer();
|
||||
@ -85,7 +83,6 @@ namespace dawn_native { namespace metal {
|
||||
ResultOrError<TextureViewBase*> CreateTextureViewImpl(
|
||||
TextureBase* texture,
|
||||
const TextureViewDescriptor* descriptor) override;
|
||||
void CollectPCIInfo();
|
||||
|
||||
void OnCompletedHandler();
|
||||
|
||||
@ -97,8 +94,6 @@ namespace dawn_native { namespace metal {
|
||||
Serial mCompletedSerial = 0;
|
||||
Serial mLastSubmittedSerial = 0;
|
||||
id<MTLCommandBuffer> mPendingCommands = nil;
|
||||
|
||||
dawn_native::PCIInfo mPCIInfo;
|
||||
};
|
||||
|
||||
}} // namespace dawn_native::metal
|
||||
|
@ -32,110 +32,15 @@
|
||||
#include "dawn_native/metal/SwapChainMTL.h"
|
||||
#include "dawn_native/metal/TextureMTL.h"
|
||||
|
||||
#include <IOKit/graphics/IOGraphicsLib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
namespace {
|
||||
// Since CGDisplayIOServicePort was deprecated in macOS 10.9, we need create
|
||||
// an alternative function for getting I/O service port from current display.
|
||||
io_service_t GetDisplayIOServicePort() {
|
||||
// The matching service port (or 0 if none can be found)
|
||||
io_service_t servicePort = 0;
|
||||
|
||||
// Create matching dictionary for display service
|
||||
CFMutableDictionaryRef matchingDict = IOServiceMatching("IODisplayConnect");
|
||||
if (matchingDict == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
io_iterator_t iter;
|
||||
// IOServiceGetMatchingServices look up the default master ports that match a
|
||||
// matching dictionary, and will consume the reference on the matching dictionary,
|
||||
// so we don't need to release the dictionary, but the iterator handle should
|
||||
// be released when its iteration is finished.
|
||||
if (IOServiceGetMatchingServices(kIOMasterPortDefault, matchingDict, &iter) !=
|
||||
kIOReturnSuccess) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Vendor number and product number of current main display
|
||||
const uint32_t displayVendorNumber = CGDisplayVendorNumber(kCGDirectMainDisplay);
|
||||
const uint32_t displayProductNumber = CGDisplayModelNumber(kCGDirectMainDisplay);
|
||||
|
||||
io_service_t serv;
|
||||
while ((serv = IOIteratorNext(iter)) != IO_OBJECT_NULL) {
|
||||
CFDictionaryRef displayInfo =
|
||||
IODisplayCreateInfoDictionary(serv, kIODisplayOnlyPreferredName);
|
||||
|
||||
CFNumberRef vendorIDRef, productIDRef;
|
||||
Boolean success;
|
||||
// The ownership of CF object follows the 'Get Rule', we don't need to
|
||||
// release these values
|
||||
success = CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayVendorID),
|
||||
(const void**)&vendorIDRef);
|
||||
success &= CFDictionaryGetValueIfPresent(displayInfo, CFSTR(kDisplayProductID),
|
||||
(const void**)&productIDRef);
|
||||
if (success) {
|
||||
CFIndex vendorID = 0, productID = 0;
|
||||
CFNumberGetValue(vendorIDRef, kCFNumberSInt32Type, &vendorID);
|
||||
CFNumberGetValue(productIDRef, kCFNumberSInt32Type, &productID);
|
||||
|
||||
if (vendorID == displayVendorNumber && productID == displayProductNumber) {
|
||||
// Check if vendor id and product id match with current display's
|
||||
// If it does, we find the desired service port
|
||||
servicePort = serv;
|
||||
CFRelease(displayInfo);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CFRelease(displayInfo);
|
||||
IOObjectRelease(serv);
|
||||
}
|
||||
IOObjectRelease(iter);
|
||||
return servicePort;
|
||||
}
|
||||
|
||||
// Get integer property from registry entry.
|
||||
uint32_t GetEntryProperty(io_registry_entry_t entry, CFStringRef name) {
|
||||
uint32_t value = 0;
|
||||
|
||||
// Recursively search registry entry and its parents for property name
|
||||
// The data should release with CFRelease
|
||||
CFDataRef data = static_cast<CFDataRef>(IORegistryEntrySearchCFProperty(
|
||||
entry, kIOServicePlane, name, kCFAllocatorDefault,
|
||||
kIORegistryIterateRecursively | kIORegistryIterateParents));
|
||||
|
||||
if (data != nullptr) {
|
||||
const uint32_t* valuePtr =
|
||||
reinterpret_cast<const uint32_t*>(CFDataGetBytePtr(data));
|
||||
if (valuePtr) {
|
||||
value = *valuePtr;
|
||||
}
|
||||
|
||||
CFRelease(data);
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
} // anonymous namespace
|
||||
|
||||
BackendConnection* Connect(InstanceBase* instance) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Device
|
||||
|
||||
Device::Device()
|
||||
: DeviceBase(nullptr),
|
||||
mMtlDevice(MTLCreateSystemDefaultDevice()),
|
||||
Device::Device(AdapterBase* adapter, id<MTLDevice> mtlDevice)
|
||||
: DeviceBase(adapter),
|
||||
mMtlDevice([mtlDevice retain]),
|
||||
mMapTracker(new MapRequestTracker(this)),
|
||||
mResourceUploader(new ResourceUploader(this)) {
|
||||
[mMtlDevice retain];
|
||||
mCommandQueue = [mMtlDevice newCommandQueue];
|
||||
CollectPCIInfo();
|
||||
}
|
||||
|
||||
Device::~Device() {
|
||||
@ -155,11 +60,11 @@ namespace dawn_native { namespace metal {
|
||||
mMapTracker = nullptr;
|
||||
mResourceUploader = nullptr;
|
||||
|
||||
[mMtlDevice release];
|
||||
mMtlDevice = nil;
|
||||
|
||||
[mCommandQueue release];
|
||||
mCommandQueue = nil;
|
||||
|
||||
[mMtlDevice release];
|
||||
mMtlDevice = nil;
|
||||
}
|
||||
|
||||
ResultOrError<BindGroupBase*> Device::CreateBindGroupImpl(
|
||||
@ -243,10 +148,6 @@ namespace dawn_native { namespace metal {
|
||||
}
|
||||
}
|
||||
|
||||
const dawn_native::PCIInfo& Device::GetPCIInfo() const {
|
||||
return mPCIInfo;
|
||||
}
|
||||
|
||||
id<MTLDevice> Device::GetMTLDevice() {
|
||||
return mMtlDevice;
|
||||
}
|
||||
@ -287,17 +188,6 @@ namespace dawn_native { namespace metal {
|
||||
return mResourceUploader.get();
|
||||
}
|
||||
|
||||
void Device::CollectPCIInfo() {
|
||||
io_registry_entry_t entry = GetDisplayIOServicePort();
|
||||
if (entry != IO_OBJECT_NULL) {
|
||||
mPCIInfo.vendorId = GetEntryProperty(entry, CFSTR("vendor-id"));
|
||||
mPCIInfo.deviceId = GetEntryProperty(entry, CFSTR("device-id"));
|
||||
IOObjectRelease(entry);
|
||||
}
|
||||
|
||||
mPCIInfo.name = std::string([mMtlDevice.name UTF8String]);
|
||||
}
|
||||
|
||||
ResultOrError<std::unique_ptr<StagingBufferBase>> Device::CreateStagingBuffer(size_t size) {
|
||||
return DAWN_UNIMPLEMENTED_ERROR("Device unable to create staging buffer.");
|
||||
}
|
||||
|
@ -21,10 +21,6 @@
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
|
||||
dawnDevice CreateDevice() {
|
||||
return reinterpret_cast<dawnDevice>(new Device());
|
||||
}
|
||||
|
||||
id<MTLDevice> GetMetalDevice(dawnDevice cDevice) {
|
||||
Device* device = reinterpret_cast<Device*>(cDevice);
|
||||
return device->GetMTLDevice();
|
||||
|
@ -15,15 +15,12 @@
|
||||
#ifndef DAWNNATIVE_METALBACKEND_H_
|
||||
#define DAWNNATIVE_METALBACKEND_H_
|
||||
|
||||
#include <dawn/dawn.h>
|
||||
#include <dawn/dawn_wsi.h>
|
||||
#include <dawn_native/dawn_native_export.h>
|
||||
#include <dawn_native/DawnNative.h>
|
||||
|
||||
#import <Metal/Metal.h>
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
namespace dawn_native { namespace metal {
|
||||
DAWN_NATIVE_EXPORT dawnDevice CreateDevice();
|
||||
DAWN_NATIVE_EXPORT id<MTLDevice> GetMetalDevice(dawnDevice device);
|
||||
}} // namespace dawn_native::metal
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
#include "GLFW/glfw3.h"
|
||||
#include "GLFW/glfw3native.h"
|
||||
|
||||
#import <QuartzCore/CAMetalLayer.h>
|
||||
|
||||
namespace utils {
|
||||
class SwapChainImplMTL {
|
||||
public:
|
||||
@ -113,9 +115,21 @@ namespace utils {
|
||||
}
|
||||
|
||||
dawnDevice CreateDevice() override {
|
||||
dawnDevice device = dawn_native::metal::CreateDevice();
|
||||
mMetalDevice = dawn_native::metal::GetMetalDevice(device);
|
||||
return device;
|
||||
// Make an instance and find a Metal adapter
|
||||
mInstance = std::make_unique<dawn_native::Instance>();
|
||||
mInstance->DiscoverDefaultAdapters();
|
||||
|
||||
std::vector<dawn_native::Adapter> adapters = mInstance->GetAdapters();
|
||||
for (dawn_native::Adapter adapter : adapters) {
|
||||
if (adapter.GetBackendType() == dawn_native::BackendType::Metal) {
|
||||
dawnDevice device = adapter.CreateDevice();
|
||||
mMetalDevice = dawn_native::metal::GetMetalDevice(device);
|
||||
return device;
|
||||
}
|
||||
}
|
||||
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
uint64_t GetSwapChainImplementation() override {
|
||||
@ -131,6 +145,7 @@ namespace utils {
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<dawn_native::Instance> mInstance;
|
||||
id<MTLDevice> mMetalDevice = nil;
|
||||
dawnSwapChainImplementation mSwapchainImpl = {};
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user