blob: 067b81697b3c7010c1745b14d1549d5b8e41b5e9 [file] [log] [blame]
// Copyright (C) 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 "host/magma/DrmBuffer.h"
#include <errno.h>
#include <i915_drm.h>
#include <sys/mman.h>
#include "host-common/logging.h"
#include "host/ExternalObjectManager.h"
namespace gfxstream {
namespace magma {
std::atomic_uint64_t DrmBuffer::mIdNext = 1000001;
DrmBuffer::DrmBuffer(DrmBuffer&& other) noexcept
: mDevice(other.mDevice),
mContextId(other.mContextId),
mGemHandle(other.mGemHandle),
mSize(other.mSize),
mHva(other.mHva),
mId(other.mId) {
// Clear the GEM handle to indicate the object is in an invalid state.
other.mGemHandle = 0;
}
DrmBuffer::~DrmBuffer() {
if (mGemHandle == 0) {
// Moved-from object. Return immediately.
return;
}
if (mHva) {
ExternalObjectManager::get()->removeMapping(mContextId, mId);
}
drm_gem_close params{.handle = mGemHandle};
int result = mDevice.ioctl(DRM_IOCTL_GEM_CLOSE, &params);
if (result) {
ERR("DRM_IOCTL_GEM_CLOSE(%d) failed: %d", mGemHandle, errno);
}
}
std::unique_ptr<DrmBuffer> DrmBuffer::create(DrmDevice& device, uint32_t context_id,
uint64_t size) {
// Create a new GEM buffer.
drm_i915_gem_create create_params{.size = size};
int result = device.ioctl(DRM_IOCTL_I915_GEM_CREATE, &create_params);
if (result) {
ERR("DRM_IOCTL_I915_GEM_CREATE failed: %d", errno);
return nullptr;
}
// Create the container to save the various returned handles.
std::unique_ptr<DrmBuffer> buffer(new DrmBuffer(device));
buffer->mContextId = context_id;
buffer->mSize = create_params.size; // Parameter adjusted by ioctl.
buffer->mGemHandle = create_params.handle;
INFO("Created DrmBuffer size %" PRIu64 " gem %" PRIu32, buffer->mSize, buffer->mGemHandle);
return buffer;
}
uint32_t DrmBuffer::getHandle() { return mGemHandle; }
uint64_t DrmBuffer::size() { return mSize; }
void* DrmBuffer::map() {
if (mHva) {
return mHva;
}
// Map the buffer.
drm_i915_gem_mmap mmap_params{.handle = mGemHandle, .size = mSize};
int result = mDevice.ioctl(DRM_IOCTL_I915_GEM_MMAP, &mmap_params);
if (result) {
ERR("DRM_IOCTL_I915_GEM_MMAP failed: %d", errno);
return nullptr;
}
// Save the mapped address and assign the next free ID.
mHva = reinterpret_cast<void*>(mmap_params.addr_ptr);
mId = mIdNext.fetch_add(1);
// Add the mapping entry.
ExternalObjectManager::get()->addMapping(mContextId, mId, mHva, MAP_CACHE_CACHED);
INFO("Mapped DrmBuffer size %" PRIu64 " gem %" PRIu32 " to addr %p mid %" PRIu64, mSize,
mGemHandle, mHva, mId);
return mHva;
}
uint64_t DrmBuffer::getId() {
map();
return mId;
}
DrmBuffer::DrmBuffer(DrmDevice& device) : mDevice(device) {}
} // namespace magma
} // namespace gfxstream