// Copyright (C) 2024 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "VirtioGpuRingBlob.h" #include #include "gfxstream/virtio-gpu-gfxstream-renderer.h" namespace gfxstream { namespace host { using android::base::SharedMemory; RingBlob::RingBlob(uint32_t id, uint64_t size, uint64_t alignment, std::variant, std::unique_ptr> memory) : mId(id), mSize(size), mAlignment(alignment), mMemory(std::move(memory)) {} bool RingBlob::isExportable() const { return std::holds_alternative>(mMemory); } android::base::SharedMemory::handle_type RingBlob::releaseHandle() { if (!isExportable()) { return SharedMemory::invalidHandle(); } return std::get>(mMemory)->releaseHandle(); } void* RingBlob::map() { if (std::holds_alternative>(mMemory)) { return std::get>(mMemory)->addr; } else { return std::get>(mMemory)->get(); } } /*static*/ std::unique_ptr RingBlob::CreateWithShmem(uint32_t id, uint64_t size) { const std::string name = "gfxstream-ringblob-shmem-" + std::to_string(id); auto shmem = std::make_unique(name, size); int ret = shmem->create(0600); if (ret) { stream_renderer_error("Failed to allocate ring blob shared memory."); return nullptr; } return std::unique_ptr(new RingBlob(id, size, 1, std::move(shmem))); } /*static*/ std::unique_ptr RingBlob::CreateWithHostMemory(uint32_t id, uint64_t size, uint64_t alignment) { auto memory = std::make_unique(alignment, size); if (memory->addr == nullptr) { stream_renderer_error("Failed to allocate ring blob host memory."); return nullptr; } return std::unique_ptr(new RingBlob(id, size, alignment, std::move(memory))); } #ifdef GFXSTREAM_BUILD_WITH_SNAPSHOT_FRONTEND_SUPPORT using gfxstream::host::snapshot::VirtioGpuRingBlobSnapshot; std::optional RingBlob::Snapshot() { VirtioGpuRingBlobSnapshot snapshot; snapshot.set_id(mId); snapshot.set_size(mSize); snapshot.set_alignment(mAlignment); if (std::holds_alternative>(mMemory)) { snapshot.set_type(VirtioGpuRingBlobSnapshot::TYPE_SHARED_MEMORY); } else { snapshot.set_type(VirtioGpuRingBlobSnapshot::TYPE_HOST_MEMORY); } void* mapped = map(); if (!mapped) { stream_renderer_error("Failed to map ring blob memory for snapshot."); return std::nullopt; } snapshot.set_memory(mapped, mSize); return snapshot; } /*static*/ std::optional> RingBlob::Restore( const VirtioGpuRingBlobSnapshot& snapshot) { std::unique_ptr resource; if (snapshot.type() == VirtioGpuRingBlobSnapshot::TYPE_SHARED_MEMORY) { resource = RingBlob::CreateWithShmem(snapshot.id(), snapshot.size()); } else { resource = RingBlob::CreateWithHostMemory(snapshot.id(), snapshot.size(), snapshot.alignment()); } if (!resource) { return std::nullopt; } void* mapped = resource->map(); if (!mapped) { stream_renderer_error("Failed to map ring blob memory for restore."); return std::nullopt; } std::memcpy(mapped, snapshot.memory().c_str(), snapshot.memory().size()); return resource; } #endif } // namespace host } // namespace gfxstream