blob: 03acca8875945634e149dde0cdf8ebdec06963be [file] [log] [blame]
// 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;
}