Cycles: Metal graphics interop
This is trivial with unified memory, and avoids one memory copy. Pull Request: https://projects.blender.org/blender/blender/pulls/137363
This commit is contained in:
@@ -98,6 +98,8 @@ set(SRC_METAL
|
||||
metal/device.h
|
||||
metal/device_impl.mm
|
||||
metal/device_impl.h
|
||||
metal/graphics_interop.mm
|
||||
metal/graphics_interop.h
|
||||
metal/kernel.mm
|
||||
metal/kernel.h
|
||||
metal/queue.mm
|
||||
|
||||
@@ -1122,6 +1122,7 @@ bool CUDADevice::should_use_graphics_interop(const GraphicsInteropDevice &intero
|
||||
|
||||
return found;
|
||||
}
|
||||
case GraphicsInteropDevice::METAL:
|
||||
case GraphicsInteropDevice::NONE: {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -86,6 +86,7 @@ void CUDADeviceGraphicsInterop::set_buffer(const GraphicsInteropBuffer &interop_
|
||||
cu_external_memory_ptr_ = external_memory_device_ptr;
|
||||
break;
|
||||
}
|
||||
case GraphicsInteropDevice::METAL:
|
||||
case GraphicsInteropDevice::NONE:
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1069,6 +1069,7 @@ bool HIPDevice::should_use_graphics_interop(const GraphicsInteropDevice &interop
|
||||
return found;
|
||||
}
|
||||
case GraphicsInteropDevice::VULKAN:
|
||||
case GraphicsInteropDevice::METAL:
|
||||
case GraphicsInteropDevice::NONE:
|
||||
/* TODO: Implement Vulkan support. */
|
||||
return false;
|
||||
|
||||
@@ -56,9 +56,10 @@ void HIPDeviceGraphicsInterop::set_buffer(const GraphicsInteropBuffer &interop_b
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* TODO: implement vulkan support. */
|
||||
case GraphicsInteropDevice::VULKAN:
|
||||
case GraphicsInteropDevice::METAL:
|
||||
case GraphicsInteropDevice::NONE:
|
||||
/* TODO: implement vulkan support. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
# include "scene/scene.h"
|
||||
|
||||
# include "session/display_driver.h"
|
||||
|
||||
# include "util/debug.h"
|
||||
# include "util/md5.h"
|
||||
# include "util/path.h"
|
||||
@@ -1360,11 +1362,11 @@ unique_ptr<DeviceQueue> MetalDevice::gpu_queue_create()
|
||||
return make_unique<MetalDeviceQueue>(this);
|
||||
}
|
||||
|
||||
bool MetalDevice::should_use_graphics_interop(const GraphicsInteropDevice & /*interop_device*/,
|
||||
bool MetalDevice::should_use_graphics_interop(const GraphicsInteropDevice &interop_device,
|
||||
const bool /*log*/)
|
||||
{
|
||||
/* METAL_WIP - provide fast interop */
|
||||
return false;
|
||||
/* Always supported with unified memory. */
|
||||
return interop_device.type == GraphicsInteropDevice::METAL;
|
||||
}
|
||||
|
||||
void *MetalDevice::get_native_buffer(device_ptr ptr)
|
||||
|
||||
46
intern/cycles/device/metal/graphics_interop.h
Normal file
46
intern/cycles/device/metal/graphics_interop.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_METAL
|
||||
|
||||
# include "device/graphics_interop.h"
|
||||
# include "session/display_driver.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
class MetalDevice;
|
||||
class MetalDeviceQueue;
|
||||
|
||||
class MetalDeviceGraphicsInterop : public DeviceGraphicsInterop {
|
||||
public:
|
||||
explicit MetalDeviceGraphicsInterop(MetalDeviceQueue *queue);
|
||||
|
||||
MetalDeviceGraphicsInterop(const MetalDeviceGraphicsInterop &other) = delete;
|
||||
MetalDeviceGraphicsInterop(MetalDeviceGraphicsInterop &&other) noexcept = delete;
|
||||
|
||||
~MetalDeviceGraphicsInterop() override;
|
||||
|
||||
MetalDeviceGraphicsInterop &operator=(const MetalDeviceGraphicsInterop &other) = delete;
|
||||
MetalDeviceGraphicsInterop &operator=(MetalDeviceGraphicsInterop &&other) = delete;
|
||||
|
||||
void set_buffer(const GraphicsInteropBuffer &interop_buffer) override;
|
||||
|
||||
device_ptr map() override;
|
||||
void unmap() override;
|
||||
|
||||
protected:
|
||||
MetalDeviceQueue *queue_ = nullptr;
|
||||
MetalDevice *device_ = nullptr;
|
||||
|
||||
/* Native handle. */
|
||||
void *buffer_ = nullptr;
|
||||
size_t size_ = 0;
|
||||
|
||||
/* The destination was requested to be cleared. */
|
||||
bool need_clear_ = false;
|
||||
};
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
43
intern/cycles/device/metal/graphics_interop.mm
Normal file
43
intern/cycles/device/metal/graphics_interop.mm
Normal file
@@ -0,0 +1,43 @@
|
||||
/* SPDX-FileCopyrightText: 2025 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0 */
|
||||
|
||||
#ifdef WITH_METAL
|
||||
|
||||
# include "device/metal/graphics_interop.h"
|
||||
|
||||
# include "device/metal/device_impl.h"
|
||||
|
||||
CCL_NAMESPACE_BEGIN
|
||||
|
||||
MetalDeviceGraphicsInterop::MetalDeviceGraphicsInterop(MetalDeviceQueue *queue)
|
||||
: queue_(queue), device_(static_cast<MetalDevice *>(queue->device))
|
||||
{
|
||||
}
|
||||
|
||||
MetalDeviceGraphicsInterop::~MetalDeviceGraphicsInterop() = default;
|
||||
|
||||
void MetalDeviceGraphicsInterop::set_buffer(const GraphicsInteropBuffer &interop_buffer)
|
||||
{
|
||||
/* Trivial implementation due to unified memory. */
|
||||
if (interop_buffer.type == GraphicsInteropDevice::METAL) {
|
||||
need_clear_ |= interop_buffer.need_clear;
|
||||
buffer_ = reinterpret_cast<void *>(interop_buffer.handle);
|
||||
size_ = interop_buffer.width * interop_buffer.height * sizeof(half4);
|
||||
}
|
||||
}
|
||||
|
||||
device_ptr MetalDeviceGraphicsInterop::map()
|
||||
{
|
||||
if (buffer_ && need_clear_) {
|
||||
memset(buffer_, 0, size_);
|
||||
}
|
||||
|
||||
return device_ptr(buffer_);
|
||||
}
|
||||
|
||||
void MetalDeviceGraphicsInterop::unmap() {}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif
|
||||
@@ -44,6 +44,8 @@ class MetalDeviceQueue : public DeviceQueue {
|
||||
|
||||
void *native_queue() override;
|
||||
|
||||
unique_ptr<DeviceGraphicsInterop> graphics_interop_create() override;
|
||||
|
||||
protected:
|
||||
void setup_capture();
|
||||
void update_capture(DeviceKernel kernel);
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
# include "device/metal/queue.h"
|
||||
|
||||
# include "device/metal/device_impl.h"
|
||||
# include "device/metal/graphics_interop.h"
|
||||
# include "device/metal/kernel.h"
|
||||
|
||||
# include "util/path.h"
|
||||
@@ -857,6 +858,11 @@ void *MetalDeviceQueue::native_queue()
|
||||
return mtlCommandQueue_;
|
||||
}
|
||||
|
||||
unique_ptr<DeviceGraphicsInterop> MetalDeviceQueue::graphics_interop_create()
|
||||
{
|
||||
return make_unique<MetalDeviceGraphicsInterop>(this);
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* WITH_METAL */
|
||||
|
||||
@@ -18,6 +18,7 @@ class GraphicsInteropDevice {
|
||||
NONE,
|
||||
OPENGL,
|
||||
VULKAN,
|
||||
METAL,
|
||||
};
|
||||
|
||||
Type type = NONE;
|
||||
@@ -39,7 +40,8 @@ class GraphicsInteropBuffer {
|
||||
/* The handle is expected to be:
|
||||
* - OpenGL: pixel buffer object ID.
|
||||
* - Vulkan on Windows: opaque handle for VkBuffer.
|
||||
* - Vulkan on Unix: opaque file descriptor for VkBuffer. */
|
||||
* - Vulkan on Unix: opaque file descriptor for VkBuffer.
|
||||
* - Metal: pixel buffer unified memory pointer. */
|
||||
GraphicsInteropDevice::Type type = GraphicsInteropDevice::NONE;
|
||||
int64_t handle = 0;
|
||||
|
||||
|
||||
@@ -2649,11 +2649,15 @@ GPUPixelBufferNativeHandle MTLPixelBuffer::get_native_handle()
|
||||
{
|
||||
GPUPixelBufferNativeHandle native_handle;
|
||||
|
||||
if (buffer_ == nil) {
|
||||
/* Only spported with unified memory currently. */
|
||||
MTLContext *ctx = MTLContext::get();
|
||||
BLI_assert(ctx);
|
||||
if (![ctx->device hasUnifiedMemory]) {
|
||||
return native_handle;
|
||||
}
|
||||
|
||||
native_handle.handle = reinterpret_cast<int64_t>(buffer_);
|
||||
/* Just get pointer to unified memory. No need to unmap. */
|
||||
native_handle.handle = reinterpret_cast<int64_t>(map());
|
||||
native_handle.size = size_;
|
||||
|
||||
return native_handle;
|
||||
|
||||
Reference in New Issue
Block a user