Metal: Implement BufferMapRead

This commit is contained in:
Corentin Wallez 2017-06-16 17:24:59 -04:00 committed by Corentin Wallez
parent 6cb33ef24e
commit ef199c0310
4 changed files with 77 additions and 4 deletions

View File

@ -16,12 +16,15 @@
#define BACKEND_METAL_BUFFERMTL_H_ #define BACKEND_METAL_BUFFERMTL_H_
#include "common/Buffer.h" #include "common/Buffer.h"
#include "common/SerialQueue.h"
#import <Metal/Metal.h> #import <Metal/Metal.h>
namespace backend { namespace backend {
namespace metal { namespace metal {
class Device;
class Buffer : public BufferBase { class Buffer : public BufferBase {
public: public:
Buffer(BufferBuilder* builder); Buffer(BufferBuilder* builder);
@ -29,6 +32,8 @@ namespace metal {
id<MTLBuffer> GetMTLBuffer(); id<MTLBuffer> GetMTLBuffer();
void OnMapReadCommandSerialFinished(uint32_t mapSerial, uint32_t offset);
private: private:
void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override; void SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) override;
void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override; void MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) override;
@ -43,6 +48,25 @@ namespace metal {
BufferView(BufferViewBuilder* builder); BufferView(BufferViewBuilder* builder);
}; };
class MapReadRequestTracker {
public:
MapReadRequestTracker(Device* device);
~MapReadRequestTracker();
void Track(Buffer* buffer, uint32_t mapSerial, uint32_t offset);
void Tick(Serial finishedSerial);
private:
Device* device;
struct Request {
Ref<Buffer> buffer;
uint32_t mapSerial;
uint32_t offset;
};
SerialQueue<Request> inflightRequests;
};
} }
} }

View File

@ -22,8 +22,16 @@ namespace metal {
Buffer::Buffer(BufferBuilder* builder) Buffer::Buffer(BufferBuilder* builder)
: BufferBase(builder) { : BufferBase(builder) {
MTLResourceOptions storageMode;
if (GetAllowedUsage() & (nxt::BufferUsageBit::MapRead | nxt::BufferUsageBit::MapWrite)) {
storageMode = MTLResourceStorageModeShared;
} else {
storageMode = MTLResourceStorageModePrivate;
}
mtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:GetSize() mtlBuffer = [ToBackend(GetDevice())->GetMTLDevice() newBufferWithLength:GetSize()
options:MTLResourceStorageModePrivate]; options:storageMode];
} }
Buffer::~Buffer() { Buffer::~Buffer() {
@ -35,17 +43,23 @@ namespace metal {
return mtlBuffer; return mtlBuffer;
} }
void Buffer::OnMapReadCommandSerialFinished(uint32_t mapSerial, uint32_t offset) {
const char* data = reinterpret_cast<const char*>([mtlBuffer contents]);
CallMapReadCallback(mapSerial, NXT_BUFFER_MAP_READ_STATUS_SUCCESS, data + offset);
}
void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) { void Buffer::SetSubDataImpl(uint32_t start, uint32_t count, const uint32_t* data) {
auto* uploader = ToBackend(GetDevice())->GetResourceUploader(); auto* uploader = ToBackend(GetDevice())->GetResourceUploader();
uploader->BufferSubData(mtlBuffer, start * sizeof(uint32_t), count * sizeof(uint32_t), data); uploader->BufferSubData(mtlBuffer, start * sizeof(uint32_t), count * sizeof(uint32_t), data);
} }
void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) { void Buffer::MapReadAsyncImpl(uint32_t serial, uint32_t start, uint32_t count) {
// TODO(cwallez@chromium.org): Implement Map Read for the metal backend MapReadRequestTracker* tracker = ToBackend(GetDevice())->GetMapReadTracker();
tracker->Track(this, serial, start);
} }
void Buffer::UnmapImpl() { void Buffer::UnmapImpl() {
// TODO(cwallez@chromium.org): Implement Map Read for the metal backend // Nothing to do, Metal StorageModeShared buffers are always mapped.
} }
void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) { void Buffer::TransitionUsageImpl(nxt::BufferUsageBit currentUsage, nxt::BufferUsageBit targetUsage) {
@ -55,5 +69,28 @@ namespace metal {
: BufferViewBase(builder) { : BufferViewBase(builder) {
} }
MapReadRequestTracker::MapReadRequestTracker(Device* device)
: device(device) {
}
MapReadRequestTracker::~MapReadRequestTracker() {
ASSERT(inflightRequests.Empty());
}
void MapReadRequestTracker::Track(Buffer* buffer, uint32_t mapSerial, uint32_t offset) {
Request request;
request.buffer = buffer;
request.mapSerial = mapSerial;
request.offset = offset;
inflightRequests.Enqueue(std::move(request), device->GetPendingCommandSerial());
}
void MapReadRequestTracker::Tick(Serial finishedSerial) {
for (auto& request : inflightRequests.IterateUpTo(finishedSerial)) {
request.buffer->OnMapReadCommandSerialFinished(request.mapSerial, request.offset);
}
inflightRequests.ClearUpTo(finishedSerial);
}
} }
} }

View File

@ -75,6 +75,7 @@ namespace metal {
return ToBackendBase<MetalBackendTraits>(common); return ToBackendBase<MetalBackendTraits>(common);
} }
class MapReadRequestTracker;
class ResourceUploader; class ResourceUploader;
class Device : public DeviceBase { class Device : public DeviceBase {
@ -112,6 +113,7 @@ namespace metal {
void SubmitPendingCommandBuffer(); void SubmitPendingCommandBuffer();
Serial GetPendingCommandSerial(); Serial GetPendingCommandSerial();
MapReadRequestTracker* GetMapReadTracker() const;
ResourceUploader* GetResourceUploader() const; ResourceUploader* GetResourceUploader() const;
// NXT API // NXT API
@ -123,6 +125,7 @@ namespace metal {
id<MTLDevice> mtlDevice = nil; id<MTLDevice> mtlDevice = nil;
id<MTLCommandQueue> commandQueue = nil; id<MTLCommandQueue> commandQueue = nil;
MapReadRequestTracker* mapReadTracker;
ResourceUploader* resourceUploader; ResourceUploader* resourceUploader;
id<CAMetalDrawable> currentDrawable = nil; id<CAMetalDrawable> currentDrawable = nil;

View File

@ -52,7 +52,8 @@ namespace metal {
// Device // Device
Device::Device(id<MTLDevice> mtlDevice) Device::Device(id<MTLDevice> mtlDevice)
: mtlDevice(mtlDevice), resourceUploader(new ResourceUploader(this)) { : mtlDevice(mtlDevice), mapReadTracker(new MapReadRequestTracker(this)),
resourceUploader(new ResourceUploader(this)) {
[mtlDevice retain]; [mtlDevice retain];
commandQueue = [mtlDevice newCommandQueue]; commandQueue = [mtlDevice newCommandQueue];
} }
@ -61,6 +62,9 @@ namespace metal {
[pendingCommands release]; [pendingCommands release];
pendingCommands = nil; pendingCommands = nil;
delete mapReadTracker;
mapReadTracker = nullptr;
delete resourceUploader; delete resourceUploader;
resourceUploader = nullptr; resourceUploader = nullptr;
@ -128,6 +132,7 @@ namespace metal {
void Device::TickImpl() { void Device::TickImpl() {
resourceUploader->Tick(finishedCommandSerial); resourceUploader->Tick(finishedCommandSerial);
mapReadTracker->Tick(finishedCommandSerial);
// Code above might have added GPU work, submit it. This also makes sure // Code above might have added GPU work, submit it. This also makes sure
// that even when no GPU work is happening, the serial number keeps incrementing. // that even when no GPU work is happening, the serial number keeps incrementing.
@ -230,6 +235,10 @@ namespace metal {
return pendingCommandSerial; return pendingCommandSerial;
} }
MapReadRequestTracker* Device::GetMapReadTracker() const {
return mapReadTracker;
}
ResourceUploader* Device::GetResourceUploader() const { ResourceUploader* Device::GetResourceUploader() const {
return resourceUploader; return resourceUploader;
} }