Skip to content

Commit bcf1180

Browse files
Add a Metal implementation.
1 parent 6c5b5e5 commit bcf1180

3 files changed

Lines changed: 60 additions & 1 deletion

File tree

lib/API/MTL/MTLDevice.cpp

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,29 @@ class MTLQueue : public offloadtest::Queue {
8484
}
8585
};
8686

87+
class MTLFence : public offloadtest::Fence {
88+
public:
89+
std::string Name;
90+
MTL::SharedEvent *Event;
91+
92+
uint64_t getFenceValue() override { return Event->signaledValue(); }
93+
94+
llvm::Error waitForCompletion(uint64_t SignalValue) override {
95+
if (!Event->waitUntilSignaledValue(SignalValue, UINT64_MAX))
96+
return llvm::createStringError(std::errc::timed_out,
97+
"Timed out waiting on shared event.");
98+
return llvm::Error::success();
99+
}
100+
101+
MTLFence(MTL::SharedEvent *Event, llvm::StringRef Name)
102+
: Name(Name), Event(Event) {}
103+
104+
~MTLFence() {
105+
if (Event)
106+
Event->release();
107+
}
108+
};
109+
87110
class MTLBuffer : public offloadtest::Buffer {
88111
public:
89112
MTL::Buffer *Buf;
@@ -131,6 +154,7 @@ class MTLDevice : public offloadtest::Device {
131154
llvm::SmallVector<MTL::Buffer *> Buffers;
132155
MTL::Texture *FrameBufferTexture = nullptr;
133156
MTL::CommandBuffer *CmdBuffer = nullptr;
157+
std::shared_ptr<offloadtest::Fence> Fence;
134158
};
135159

136160
llvm::Error setupVertexShader(InvocationState &IS, const Pipeline &P,
@@ -488,14 +512,23 @@ class MTLDevice : public offloadtest::Device {
488512
}
489513

490514
llvm::Error executeCommands(InvocationState &IS) {
515+
// This is a hack but it works since this is all single threaded code.
516+
static uint64_t FenceCounter = 0;
517+
const uint64_t CurrentCounter = FenceCounter + 1;
518+
auto *F = static_cast<MTLFence *>(IS.Fence.get());
519+
520+
IS.CmdBuffer->encodeSignalEvent(F->Event, CurrentCounter);
491521
IS.CmdBuffer->commit();
492-
IS.CmdBuffer->waitUntilCompleted();
522+
523+
if (auto Err = IS.Fence->waitForCompletion(CurrentCounter))
524+
return Err;
493525

494526
// Check and surface any errors that occurred during execution.
495527
NS::Error *CBErr = IS.CmdBuffer->error();
496528
if (CBErr)
497529
return toError(CBErr);
498530

531+
FenceCounter = CurrentCounter;
499532
return llvm::Error::success();
500533
}
501534

@@ -567,6 +600,15 @@ class MTLDevice : public offloadtest::Device {
567600
return std::static_pointer_cast<Queue>(GraphicsQueue);
568601
}
569602

603+
llvm::Expected<std::shared_ptr<offloadtest::Fence>>
604+
createFence(llvm::StringRef Name) override {
605+
MTL::SharedEvent *Event = Device->newSharedEvent();
606+
if (!Event)
607+
return llvm::createStringError(std::errc::device_or_resource_busy,
608+
"Failed to create shared event.");
609+
return std::make_shared<MTLFence>(Event, Name);
610+
}
611+
570612
llvm::Expected<std::shared_ptr<offloadtest::Buffer>>
571613
createBuffer(llvm::StringRef Name, BufferCreateDesc &Desc,
572614
size_t SizeInBytes) override {
@@ -591,6 +633,11 @@ class MTLDevice : public offloadtest::Device {
591633
llvm::Error executeProgram(Pipeline &P) override {
592634
InvocationState IS;
593635

636+
auto FenceOrErr = this->createFence("Fence");
637+
if (!FenceOrErr)
638+
return FenceOrErr.takeError();
639+
IS.Fence = *FenceOrErr;
640+
594641
if (auto Err = createBuffers(P, IS))
595642
return Err;
596643

third-party/metal-cpp/Metal/MTLEvent.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ class SharedEvent : public NS::Referencing<SharedEvent, Event> {
6060

6161
uint64_t signaledValue() const;
6262
void setSignaledValue(uint64_t signaledValue);
63+
64+
bool waitUntilSignaledValue(uint64_t value, uint64_t timeoutMS);
6365
};
6466

6567
class SharedEventHandle : public NS::SecureCoding<SharedEventHandle> {
@@ -136,6 +138,14 @@ _MTL_INLINE void MTL::SharedEvent::setSignaledValue(uint64_t signaledValue) {
136138
signaledValue);
137139
}
138140

141+
// method: waitUntilSignaledValue:timeoutMS:
142+
_MTL_INLINE bool MTL::SharedEvent::waitUntilSignaledValue(uint64_t value,
143+
uint64_t timeoutMS) {
144+
return Object::sendMessage<bool>(
145+
this, _MTL_PRIVATE_SEL(waitUntilSignaledValue_timeoutMS_), value,
146+
timeoutMS);
147+
}
148+
139149
// static method: alloc
140150
_MTL_INLINE MTL::SharedEventHandle *MTL::SharedEventHandle::alloc() {
141151
return NS::Object::alloc<MTL::SharedEventHandle>(

third-party/metal-cpp/Metal/MTLHeaderBridge.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1844,6 +1844,8 @@ _MTL_PRIVATE_DEF_SEL(waitForFence_, "waitForFence:");
18441844
_MTL_PRIVATE_DEF_SEL(waitForFence_beforeStages_, "waitForFence:beforeStages:");
18451845
_MTL_PRIVATE_DEF_SEL(waitUntilCompleted, "waitUntilCompleted");
18461846
_MTL_PRIVATE_DEF_SEL(waitUntilScheduled, "waitUntilScheduled");
1847+
_MTL_PRIVATE_DEF_SEL(waitUntilSignaledValue_timeoutMS_,
1848+
"waitUntilSignaledValue:timeoutMS:");
18471849
_MTL_PRIVATE_DEF_SEL(width, "width");
18481850
_MTL_PRIVATE_DEF_SEL(
18491851
writeCompactedAccelerationStructureSize_toBuffer_offset_,

0 commit comments

Comments
 (0)