| // Copyright 2023 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 "VirtioGpuAddressSpaceStream.h" |
| |
| #include "util.h" |
| |
| static bool GetRingParamsFromCapset(enum VirtGpuCapset capset, const VirtGpuCaps& caps, |
| uint32_t& ringSize, uint32_t& bufferSize, |
| uint32_t& blobAlignment) { |
| switch (capset) { |
| case kCapsetGfxStreamVulkan: |
| ringSize = caps.vulkanCapset.ringSize; |
| bufferSize = caps.vulkanCapset.bufferSize; |
| blobAlignment = caps.vulkanCapset.blobAlignment; |
| break; |
| case kCapsetGfxStreamMagma: |
| ringSize = caps.magmaCapset.ringSize; |
| bufferSize = caps.magmaCapset.bufferSize; |
| blobAlignment = caps.magmaCapset.blobAlignment; |
| break; |
| case kCapsetGfxStreamGles: |
| ringSize = caps.glesCapset.ringSize; |
| bufferSize = caps.glesCapset.bufferSize; |
| blobAlignment = caps.glesCapset.blobAlignment; |
| break; |
| case kCapsetGfxStreamComposer: |
| ringSize = caps.composerCapset.ringSize; |
| bufferSize = caps.composerCapset.bufferSize; |
| blobAlignment = caps.composerCapset.blobAlignment; |
| break; |
| default: |
| return false; |
| } |
| |
| return true; |
| } |
| |
| address_space_handle_t virtgpu_address_space_open() { |
| return (address_space_handle_t)(-EINVAL); |
| } |
| |
| void virtgpu_address_space_close(address_space_handle_t) { |
| // Handle opened by VirtioGpuDevice wrapper |
| } |
| |
| bool virtgpu_address_space_ping(address_space_handle_t, struct address_space_ping* info) { |
| int ret; |
| struct VirtGpuExecBuffer exec = {}; |
| VirtGpuDevice* instance = VirtGpuDevice::getInstance(); |
| struct gfxstreamContextPing ping = {}; |
| |
| ping.hdr.opCode = GFXSTREAM_CONTEXT_PING; |
| ping.resourceId = info->resourceId; |
| |
| exec.command = static_cast<void*>(&ping); |
| exec.command_size = sizeof(ping); |
| |
| ret = instance->execBuffer(exec, nullptr); |
| if (ret) |
| return false; |
| |
| return true; |
| } |
| |
| AddressSpaceStream* createVirtioGpuAddressSpaceStream(enum VirtGpuCapset capset, |
| HealthMonitor<>* healthMonitor) { |
| VirtGpuResourcePtr pipe, blob; |
| VirtGpuResourceMappingPtr pipeMapping, blobMapping; |
| struct VirtGpuExecBuffer exec = {}; |
| struct VirtGpuCreateBlob blobCreate = {}; |
| struct gfxstreamContextCreate contextCreate = {}; |
| |
| uint32_t ringSize = 0; |
| uint32_t bufferSize = 0; |
| uint32_t blobAlignment = 0; |
| |
| char* blobAddr, *bufferPtr; |
| int ret; |
| |
| VirtGpuDevice* instance = VirtGpuDevice::getInstance(); |
| auto caps = instance->getCaps(); |
| |
| if (!GetRingParamsFromCapset(capset, caps, ringSize, bufferSize, blobAlignment)) { |
| ALOGE("Failed to get ring parameters"); |
| return nullptr; |
| } |
| |
| blobCreate.blobId = 0; |
| blobCreate.blobMem = kBlobMemHost3d; |
| blobCreate.flags = kBlobFlagMappable; |
| blobCreate.size = ALIGN(ringSize + bufferSize, blobAlignment); |
| blob = instance->createBlob(blobCreate); |
| if (!blob) |
| return nullptr; |
| |
| // Context creation command |
| contextCreate.hdr.opCode = GFXSTREAM_CONTEXT_CREATE; |
| contextCreate.resourceId = blob->getResourceHandle(); |
| |
| exec.command = static_cast<void*>(&contextCreate); |
| exec.command_size = sizeof(contextCreate); |
| |
| ret = instance->execBuffer(exec, blob.get()); |
| if (ret) |
| return nullptr; |
| |
| // Wait occurs on global timeline -- should we use context specific one? |
| ret = blob->wait(); |
| if (ret) |
| return nullptr; |
| |
| blobMapping = blob->createMapping(); |
| if (!blobMapping) |
| return nullptr; |
| |
| blobAddr = reinterpret_cast<char*>(blobMapping->asRawPtr()); |
| |
| bufferPtr = blobAddr + sizeof(struct asg_ring_storage); |
| struct asg_context context = asg_context_create(blobAddr, bufferPtr, bufferSize); |
| |
| context.ring_config->transfer_mode = 1; |
| context.ring_config->host_consumed_pos = 0; |
| context.ring_config->guest_write_pos = 0; |
| |
| struct address_space_ops ops = { |
| .open = virtgpu_address_space_open, |
| .close = virtgpu_address_space_close, |
| .ping = virtgpu_address_space_ping, |
| }; |
| |
| AddressSpaceStream* res = |
| new AddressSpaceStream((address_space_handle_t)(-1), 1, context, 0, 0, ops, healthMonitor); |
| |
| res->setMapping(blobMapping); |
| res->setResourceId(contextCreate.resourceId); |
| return res; |
| } |