blob: f54f5761e58c76aec8bf7d4602682d5686392b88 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "gpu/command_buffer/client/dawn_client_memory_transfer_service.h"
#include "gpu/command_buffer/client/mapped_memory.h"
#include "gpu/command_buffer/common/dawn_memory_transfer_handle.h"
namespace gpu {
namespace webgpu {
class DawnClientMemoryTransferService::ReadHandleImpl
: public dawn_wire::client::MemoryTransferService::ReadHandle {
public:
ReadHandleImpl(void* ptr,
MemoryTransferHandle handle,
DawnClientMemoryTransferService* service)
: ReadHandle(), ptr_(ptr), handle_(handle), service_(service) {}
~ReadHandleImpl() override {
// The shared memory can't be freed until the server consumes it. Add the
// the pointer to a list of blocks to process on the next Flush.
service_->MarkHandleFree(ptr_);
}
// Get the serialization size of SerializeCreate.
size_t SerializeCreateSize() override { return sizeof(MemoryTransferHandle); }
// Serialize the handle into |serialize_pointer| so it can be received by the
// service.
void SerializeCreate(void* serialize_pointer) override {
*reinterpret_cast<MemoryTransferHandle*>(serialize_pointer) = handle_;
}
// Load initial data and open the handle for reading.
// This function takes in the serialized result of
// ReadHandle::SerializeInitialData.
// It writes to |data| and |data_length| the pointer and size
// of the mapped data for reading.
// The allocation must live at least until the ReadHandle is destructed.
bool DeserializeInitialData(const void* deserialize_pointer,
size_t deserialize_size,
const void** data,
size_t* data_length) override {
// No data is deserialized because we're using shared memory.
DCHECK_EQ(deserialize_size, 0u);
DCHECK(data);
DCHECK(data_length);
// Write the pointer and size of the shared memory allocation.
// |data| and |data_length| are provided by the dawn_wire client.
*data = ptr_;
*data_length = handle_.size;
return true;
}
private:
void* ptr_; // Pointer to client-side shared memory.
MemoryTransferHandle handle_;
DawnClientMemoryTransferService* service_;
};
class DawnClientMemoryTransferService::WriteHandleImpl
: public dawn_wire::client::MemoryTransferService::WriteHandle {
public:
WriteHandleImpl(void* ptr,
MemoryTransferHandle handle,
DawnClientMemoryTransferService* service)
: WriteHandle(), ptr_(ptr), handle_(handle), service_(service) {}
~WriteHandleImpl() override {
// The shared memory can't be freed until the server consumes it. Add
// the pointer to a list of blocks to process on the next Flush.
service_->MarkHandleFree(ptr_);
}
// Get the serialization size of SerializeCreate.
size_t SerializeCreateSize() override { return sizeof(MemoryTransferHandle); }
// Serialize the handle into |serialize_pointer| so it can be received by the
// service.
void SerializeCreate(void* serialize_pointer) override {
*reinterpret_cast<MemoryTransferHandle*>(serialize_pointer) = handle_;
}
// Open the handle for writing.
// The data returned must live at least until the WriteHandle is destructed.
std::pair<void*, size_t> Open() override {
return std::make_pair(ptr_, handle_.size);
}
size_t SerializeFlushSize() override {
// No data is serialized because we're using shared memory.
return 0;
}
void SerializeFlush(void* serialize_pointer) override {
// No data is serialized because we're using shared memory.
}
private:
void* ptr_;
MemoryTransferHandle handle_;
DawnClientMemoryTransferService* service_;
};
DawnClientMemoryTransferService::DawnClientMemoryTransferService(
MappedMemoryManager* mapped_memory)
: dawn_wire::client::MemoryTransferService(),
mapped_memory_(mapped_memory) {}
DawnClientMemoryTransferService::~DawnClientMemoryTransferService() = default;
dawn_wire::client::MemoryTransferService::ReadHandle*
DawnClientMemoryTransferService::CreateReadHandle(size_t size) {
MemoryTransferHandle handle = {};
void* ptr = AllocateHandle(size, &handle);
if (ptr == nullptr) {
return nullptr;
}
return new ReadHandleImpl(ptr, handle, this);
}
dawn_wire::client::MemoryTransferService::WriteHandle*
DawnClientMemoryTransferService::CreateWriteHandle(size_t size) {
MemoryTransferHandle handle = {};
void* ptr = AllocateHandle(size, &handle);
if (ptr == nullptr) {
return nullptr;
}
// Zero-initialize the data.
memset(ptr, 0, handle.size);
return new WriteHandleImpl(ptr, handle, this);
}
void* DawnClientMemoryTransferService::AllocateHandle(
size_t size,
MemoryTransferHandle* handle) {
if (size > std::numeric_limits<uint32_t>::max()) {
return nullptr;
}
DCHECK(handle);
handle->size = static_cast<uint32_t>(size);
DCHECK(mapped_memory_);
return mapped_memory_->Alloc(handle->size, &handle->shm_id,
&handle->shm_offset);
}
void DawnClientMemoryTransferService::MarkHandleFree(void* ptr) {
free_blocks_.push_back(ptr);
}
void DawnClientMemoryTransferService::FreeHandlesPendingToken(int32_t token) {
std::vector<void*> to_free = std::move(free_blocks_);
for (void* ptr : to_free) {
mapped_memory_->FreePendingToken(ptr, token);
}
}
} // namespace webgpu
} // namespace gpu