Metal: Implement BufferMapRead
This commit is contained in:
parent
6cb33ef24e
commit
ef199c0310
|
@ -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;
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue