Add getPlatform API to Engine, move functionality into MetalPlatform (#4007)

This change allows access to the Engine's underlying Platform object. This is useful for Metal clients to access a new method on MetalPlatform, createAndEnqueueCommandBuffer.
This commit is contained in:
Ben Doherty
2021-05-24 10:36:56 -07:00
committed by GitHub
parent 786eee4eb9
commit c827004821
10 changed files with 189 additions and 106 deletions

View File

@@ -115,7 +115,7 @@ if (FILAMENT_SUPPORTS_METAL)
src/metal/MetalResourceTracker.cpp
src/metal/MetalState.mm
src/metal/MetalTimerQuery.mm
src/metal/PlatformMetal.mm
src/metal/MetalPlatform.mm
)
list(APPEND SRCS ${METAL_SRCS})

View File

@@ -0,0 +1,66 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* 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 TNT_FILAMENT_DRIVER_PLATFORM_METAL_H
#define TNT_FILAMENT_DRIVER_PLATFORM_METAL_H
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
#import <Metal/Metal.h>
namespace filament {
namespace backend {
class MetalPlatform : public DefaultPlatform {
public:
~MetalPlatform() override;
Driver* createDriver(void* sharedContext) noexcept override;
int getOSVersion() const noexcept override { return 0; }
/**
* Obtain the preferred Metal device object for the backend to use.
*
* On desktop platforms, there may be multiple GPUs suitable for rendering, and this method is
* free to decide which one to use. On mobile systems with a single GPU, implementations should
* simply return the result of MTLCreateSystemDefaultDevice();
*/
virtual id<MTLDevice> createDevice() noexcept;
/**
* Create a command submission queue on the Metal device object.
*
* @param device The device which was returned from createDevice()
*/
virtual id<MTLCommandQueue> createCommandQueue(id<MTLDevice> device) noexcept;
/**
* Obtain a MTLCommandBuffer enqueued on this Platform's MTLCommandQueue. The command buffer is
* guaranteed to execute before all subsequent command buffers created either by Filament, or
* further calls to this method.
*/
id<MTLCommandBuffer> createAndEnqueueCommandBuffer() noexcept;
private:
id<MTLCommandQueue> mCommandQueue = nil;
};
} // namespace backend
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_PLATFORM_METAL_H

View File

@@ -63,7 +63,9 @@
#endif
#if defined (FILAMENT_SUPPORTS_METAL)
#include "metal/PlatformMetal.h"
namespace filament::backend {
filament::backend::DefaultPlatform* createDefaultMetalPlatform();
}
#endif
#include "noop/PlatformNoop.h"
@@ -107,7 +109,7 @@ DefaultPlatform* DefaultPlatform::create(Backend* backend) noexcept {
}
if (*backend == Backend::METAL) {
#if defined(FILAMENT_SUPPORTS_METAL)
return new PlatformMetal();
return createDefaultMetalPlatform();
#else
return nullptr;
#endif

View File

@@ -27,6 +27,8 @@
#include "MetalState.h"
#include "MetalTimerQuery.h"
#include "private/backend/MetalPlatform.h"
#include <CoreVideo/CVMetalTexture.h>
#include <CoreVideo/CVPixelBuffer.h>
#include <Metal/Metal.h>
@@ -56,27 +58,8 @@ MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
mContext(new MetalContext) {
mContext->driver = this;
#if !defined(IOS)
const bool forceIntegrated =
NSProcessInfo.processInfo.environment[@"FILAMENT_FORCE_INTEGRATED_GPU"] != nil;
if (forceIntegrated) {
// Find the first low power device, which is likely the integrated GPU.
NSArray<id<MTLDevice>>* const devices = MTLCopyAllDevices();
for (id<MTLDevice> device in devices) {
if (device.isLowPower) {
mContext->device = device;
break;
}
}
} else
#endif
{
mContext->device = MTLCreateSystemDefaultDevice();
}
utils::slog.i << "Selected physical device '"
<< [mContext->device.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
mContext->device = mPlatform.createDevice();
assert_invariant(mContext->device);
// In order to support texture swizzling, the GPU needs to support it and the system be running
// macOS 10.15+ / iOS 13+.
@@ -102,8 +85,7 @@ MetalDriver::MetalDriver(backend::MetalPlatform* platform) noexcept
}
#endif
mContext->commandQueue = [mContext->device newCommandQueue];
mContext->commandQueue.label = @"Filament";
mContext->commandQueue = mPlatform.createCommandQueue(mContext->device);
mContext->pipelineStateCache.setDevice(mContext->device);
mContext->depthStencilStateCache.setDevice(mContext->device);
mContext->samplerStateCache.setDevice(mContext->device);

View File

@@ -0,0 +1,79 @@
/*
* Copyright (C) 2021 The Android Open Source Project
*
* 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 "private/backend/MetalPlatform.h"
#include "MetalDriverFactory.h"
#include <utils/Log.h>
#import <Foundation/Foundation.h>
namespace filament {
namespace backend {
DefaultPlatform* createDefaultMetalPlatform() {
return new MetalPlatform();
}
MetalPlatform::~MetalPlatform() = default;
Driver* MetalPlatform::createDriver(void* sharedContext) noexcept {
return MetalDriverFactory::create(this);
}
id<MTLDevice> MetalPlatform::createDevice() noexcept {
id<MTLDevice> result;
#if !defined(IOS)
const bool forceIntegrated =
NSProcessInfo.processInfo.environment[@"FILAMENT_FORCE_INTEGRATED_GPU"] != nil;
if (forceIntegrated) {
// Find the first low power device, which is likely the integrated GPU.
NSArray<id<MTLDevice>>* const devices = MTLCopyAllDevices();
for (id<MTLDevice> device in devices) {
if (device.isLowPower) {
result = device;
break;
}
}
} else
#endif
{
result = MTLCreateSystemDefaultDevice();
}
utils::slog.i << "Selected physical device '"
<< [result.name cStringUsingEncoding:NSUTF8StringEncoding] << "'"
<< utils::io::endl;
return result;
}
id<MTLCommandQueue> MetalPlatform::createCommandQueue(id<MTLDevice> device) noexcept {
mCommandQueue = [device newCommandQueue];
mCommandQueue.label = @"Filament";
return mCommandQueue;
}
id<MTLCommandBuffer> MetalPlatform::createAndEnqueueCommandBuffer() noexcept {
id<MTLCommandBuffer> commandBuffer = [mCommandQueue commandBuffer];
[commandBuffer enqueue];
return commandBuffer;
}
} // namespace backend
} // namespace filament

View File

@@ -1,44 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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 TNT_FILAMENT_DRIVER_PLATFORM_METAL_H
#define TNT_FILAMENT_DRIVER_PLATFORM_METAL_H
#include <stdint.h>
#include <backend/DriverEnums.h>
#include <backend/Platform.h>
namespace filament {
namespace backend {
class MetalPlatform : public DefaultPlatform {
public:
~MetalPlatform() override;
};
} // namespace backend
class PlatformMetal final : public backend::MetalPlatform {
public:
backend::Driver* createDriver(void* sharedContext) noexcept override;
int getOSVersion() const noexcept override { return 0; }
~PlatformMetal() override;
};
} // namespace filament
#endif // TNT_FILAMENT_DRIVER_PLATFORM_METAL_H

View File

@@ -1,36 +0,0 @@
/*
* Copyright (C) 2019 The Android Open Source Project
*
* 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 "PlatformMetal.h"
#include "MetalDriverFactory.h"
namespace filament {
namespace backend {
MetalPlatform::~MetalPlatform() = default;
} // namespace backend
using namespace backend;
Driver* PlatformMetal::createDriver(void* sharedContext) noexcept {
return MetalDriverFactory::create(this);
}
PlatformMetal::~PlatformMetal() = default;
} // namespace filament

View File

@@ -459,6 +459,32 @@ public:
*/
Backend getBackend() const noexcept;
/**
* Returns the Platform object that belongs to this Engine.
*
* When Engine::create is called with no platform argument, Filament creates an appropriate
* Platform subclass automatically. The specific subclass created depends on the backend and
* OS. For example, when the OpenGL backend is used, the Platform object will be a descendant of
* OpenGLPlatform.
*
* dynamic_cast should be used to cast the returned Platform object into a specific subclass.
* Note that RTTI must be available to use dynamic_cast.
*
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Platform* platform = engine->getPlatform();
* // static_cast also works, but more dangerous.
* SpecificPlatform* specificPlatform = dynamic_cast<SpecificPlatform*>(platform);
* specificPlatform->platformSpecificMethod();
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* When a custom Platform is passed to Engine::create, Filament will use it instead, and this
* method will return it.
*
* @return A pointer to the Platform object that was provided to Engine::create, or the
* Filament-created one.
*/
Platform* getPlatform() const noexcept;
/**
* Allocate a small amount of memory directly in the command stream. The allocated memory is
* guaranteed to be preserved until the current command buffer is executed

View File

@@ -899,6 +899,10 @@ Backend Engine::getBackend() const noexcept {
return upcast(this)->getBackend();
}
Platform* Engine::getPlatform() const noexcept {
return upcast(this)->getPlatform();
}
Renderer* Engine::createRenderer() noexcept {
return upcast(this)->createRenderer();
}

View File

@@ -210,6 +210,10 @@ public:
return mBackend;
}
Platform* getPlatform() const noexcept {
return mPlatform;
}
ResourceAllocator& getResourceAllocator() noexcept {
assert_invariant(mResourceAllocator);
return *mResourceAllocator;