blob: 14422056eb697e10916260d035e3f9a205d3dbb0 [file] [log] [blame]
// Copyright 2016 The Fuchsia 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 "anv_magma.h"
#include "anv_private.h"
#include "msd_intel_gen_query.h"
#include "magma_util/dlog.h"
static magma_connection_t magma_connection(struct anv_device* device)
{
assert(device);
assert(device->connection);
return device->connection->connection;
}
int anv_gem_connect(struct anv_device* device)
{
magma_connection_t connection;
magma_status_t status = magma_create_connection2(device->fd, &connection);
if (status != MAGMA_STATUS_OK || !connection) {
DLOG("magma_create_connection failed: %d", status);
return -1;
}
device->connection = AnvMagmaCreateConnection(connection);
DLOG("created magma connection");
return 0;
}
void anv_gem_disconnect(struct anv_device* device)
{
AnvMagmaReleaseConnection(device->connection);
DLOG("released magma connection");
}
// Return handle, or 0 on failure. Gem handles are never 0.
anv_buffer_handle_t anv_gem_create(struct anv_device* device, size_t size)
{
magma_buffer_t buffer;
uint64_t magma_size = size;
magma_status_t status = magma_create_buffer(magma_connection(device), magma_size, &magma_size, &buffer);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_create_buffer failed (%d) size 0x%zx", status, magma_size);
return 0;
}
DLOG("magma_create_buffer size 0x%zx returning buffer 0x%lx", magma_size, buffer);
assert(buffer != 0);
return buffer;
}
void anv_gem_close(struct anv_device* device, anv_buffer_handle_t handle)
{
DLOG("anv_gem_close handle 0x%lx", handle);
magma_release_buffer(magma_connection(device), handle);
}
void* anv_gem_mmap(struct anv_device* device, anv_buffer_handle_t handle, uint64_t offset, uint64_t size,
uint32_t flags)
{
assert(flags == 0);
void* addr;
magma_status_t status = magma_map(magma_connection(device), handle, &addr);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_map failed: status %d", status);
return MAP_FAILED;
}
DLOG("magma_system_map handle 0x%lx size 0x%zx returning %p", handle, size, addr);
return (uint8_t*) addr + offset;
}
void anv_gem_munmap(struct anv_device* device, anv_buffer_handle_t gem_handle, void* addr, uint64_t size)
{
if (!addr)
return;
if (magma_unmap(magma_connection(device), gem_handle) != 0) {
DLOG("magma_unmap failed");
return;
}
DLOG("magma_unmap handle 0x%lx", gem_handle);
}
uint32_t anv_gem_userptr(struct anv_device* device, void* mem, size_t size)
{
DLOG("anv_gem_userptr - STUB");
assert(false);
return 0;
}
int anv_gem_set_caching(struct anv_device* device, anv_buffer_handle_t gem_handle, uint32_t caching)
{
DLOG("anv_get_set_caching - STUB");
return 0;
}
int anv_gem_set_domain(struct anv_device* device, anv_buffer_handle_t gem_handle, uint32_t read_domains,
uint32_t write_domain)
{
DLOG("anv_gem_set_domain - STUB");
return 0;
}
/**
* On error, \a timeout_ns holds the remaining time.
*/
int anv_gem_wait(struct anv_device* device, anv_buffer_handle_t handle, int64_t* timeout_ns)
{
DLOG("anv_gem_wait buffer_id %lu timeout_ns %lu", magma_get_buffer_id(handle), *timeout_ns);
uint64_t buffer_id = magma_get_buffer_id(handle);
AnvMagmaConnectionWait(device->connection, buffer_id, timeout_ns);
return 0;
}
/**
* Returns 0, 1, or negative to indicate error
*/
int anv_gem_busy(struct anv_device* device, anv_buffer_handle_t handle)
{
DLOG("anv_gem_busy");
return AnvMagmaConnectionIsBusy(device->connection, magma_get_buffer_id(handle));
}
bool anv_gem_supports_48b_addresses(int fd)
{
uint64_t gtt_size;
magma_status_t status = magma_query(fd, kMsdIntelGenQueryGttSize, &gtt_size);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_query failed: %d", status);
return false;
}
return gtt_size >= 1ul << 48;
}
int anv_gem_get_context_param(int fd, int context, uint32_t param, uint64_t* value)
{
magma_status_t status;
switch (param) {
case I915_CONTEXT_PARAM_GTT_SIZE:
status = magma_query(fd, kMsdIntelGenQueryGttSize, value);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_query failed: %d", status);
return -1;
}
return 0;
default:
DLOG("anv_gem_get_context_param: unhandled param 0x%x", param);
return -1;
}
}
int anv_gem_execbuffer(struct anv_device* device, struct drm_i915_gem_execbuffer2* execbuf)
{
DLOG("anv_gem_execbuffer");
return AnvMagmaConnectionExec(device->connection, device->context_id, execbuf);
}
int anv_gem_set_tiling(struct anv_device* device, anv_buffer_handle_t gem_handle, uint32_t stride,
uint32_t tiling)
{
DLOG("anv_gem_set_tiling - STUB");
return 0;
}
int anv_gem_get_param(int fd, uint32_t param)
{
magma_status_t status = MAGMA_STATUS_OK;
uint64_t value;
switch (param) {
case I915_PARAM_CHIPSET_ID:
status = magma_query(fd, MAGMA_QUERY_DEVICE_ID, &value);
break;
case I915_PARAM_SUBSLICE_TOTAL:
status = magma_query(fd, kMsdIntelGenQuerySubsliceAndEuTotal, &value);
value >>= 32;
break;
case I915_PARAM_EU_TOTAL:
status = magma_query(fd, kMsdIntelGenQuerySubsliceAndEuTotal, &value);
value = (uint32_t) value;
break;
case I915_PARAM_HAS_WAIT_TIMEOUT:
case I915_PARAM_HAS_EXECBUF2:
value = 1;
break;
case I915_PARAM_HAS_EXEC_FENCE_ARRAY: // Used for semaphores
value = 1;
break;
default:
status = MAGMA_STATUS_INVALID_ARGS;
}
if (status != MAGMA_STATUS_OK)
value = 0;
uint32_t result = (uint32_t) value;
assert(result == value);
DLOG("anv_gem_get_param(%u, %u) returning %d", fd, param, result);
return result;
}
bool anv_gem_get_bit6_swizzle(int fd, uint32_t tiling)
{
DLOG("anv_gem_get_bit6_swizzle - STUB");
return 0;
}
int anv_gem_create_context(struct anv_device* device)
{
uint32_t context_id;
magma_create_context(magma_connection(device), &context_id);
DLOG("magma_create_context returned context_id %u", context_id);
return context_id;
}
int anv_gem_destroy_context(struct anv_device* device, int context_id)
{
magma_release_context(magma_connection(device), context_id);
return 0;
}
int anv_gem_get_aperture(int fd, uint64_t* size)
{
DLOG("anv_gem_get_aperture - STUB");
return 0;
}
int anv_gem_handle_to_fd(struct anv_device* device, anv_buffer_handle_t gem_handle)
{
assert(false);
return -1;
}
anv_buffer_handle_t anv_gem_fd_to_handle(struct anv_device* device, int fd)
{
assert(false);
return 0;
}
int anv_gem_gpu_get_reset_stats(struct anv_device* device, uint32_t* active, uint32_t* pending)
{
DLOG("anv_gem_gpu_get_reset_stats - STUB");
*active = 0;
*pending = 0;
return 0;
}
int anv_gem_import_fuchsia_buffer(struct anv_device* device, uint32_t handle,
anv_buffer_handle_t* buffer_out, uint64_t* size_out)
{
magma_status_t status = magma_import(magma_connection(device), handle, buffer_out);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_import failed: %d", status);
return -EINVAL;
}
*size_out = magma_get_buffer_size(*buffer_out);
return 0;
}
#if VK_USE_PLATFORM_FUCHSIA
VkResult anv_GetMemoryFuchsiaHandleKHR(VkDevice vk_device,
const VkMemoryGetFuchsiaHandleInfoKHR* pGetFuchsiaHandleInfo,
uint32_t* pHandle)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_device_memory, memory, pGetFuchsiaHandleInfo->memory);
assert(pGetFuchsiaHandleInfo->sType == VK_STRUCTURE_TYPE_MEMORY_GET_FUCHSIA_HANDLE_INFO_KHR);
assert(pGetFuchsiaHandleInfo->handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR);
magma_status_t status = magma_export(magma_connection(device), memory->bo->gem_handle, pHandle);
assert(status == MAGMA_STATUS_OK);
return VK_SUCCESS;
}
VkResult anv_GetMemoryFuchsiaHandlePropertiesKHR(
VkDevice vk_device, VkExternalMemoryHandleTypeFlagBitsKHR handleType, uint32_t handle,
VkMemoryFuchsiaHandlePropertiesKHR* pMemoryFuchsiaHandleProperties)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
assert(handleType == VK_EXTERNAL_MEMORY_HANDLE_TYPE_FUCHSIA_VMO_BIT_KHR);
assert(pMemoryFuchsiaHandleProperties->sType ==
VK_STRUCTURE_TYPE_MEMORY_FUCHSIA_HANDLE_PROPERTIES_KHR);
struct anv_physical_device* pdevice = &device->instance->physicalDevice;
// All memory types supported
pMemoryFuchsiaHandleProperties->memoryTypeBits = (1ull << pdevice->memory.type_count) - 1;
return VK_SUCCESS;
}
/* Similar to anv_ImportSemaphoreFdKHR */
VkResult anv_ImportSemaphoreFuchsiaHandleKHR(VkDevice vk_device,
const VkImportSemaphoreFuchsiaHandleInfoKHR* info)
{
assert(info->sType == VK_STRUCTURE_TYPE_IMPORT_SEMAPHORE_FUCHSIA_HANDLE_INFO_KHR);
assert(info->handleType == VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FUCHSIA_FENCE_BIT_KHR);
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_semaphore, semaphore, info->semaphore);
magma_semaphore_t magma_semaphore;
magma_status_t status =
magma_import_semaphore(magma_connection(device), info->handle, &magma_semaphore);
if (status != MAGMA_STATUS_OK)
return vk_error(VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR);
struct anv_semaphore_impl new_impl = {.type = ANV_SEMAPHORE_TYPE_DRM_SYNCOBJ};
new_impl.syncobj = magma_semaphore;
if (info->flags & VK_SEMAPHORE_IMPORT_TEMPORARY_BIT_KHR) {
anv_semaphore_impl_cleanup(device, &semaphore->temporary);
semaphore->temporary = new_impl;
} else {
anv_semaphore_impl_cleanup(device, &semaphore->permanent);
semaphore->permanent = new_impl;
}
return VK_SUCCESS;
}
/* Similar to anv_GetSemaphoreFdKHR */
VkResult anv_GetSemaphoreFuchsiaHandleKHR(VkDevice vk_device,
const VkSemaphoreGetFuchsiaHandleInfoKHR* info,
uint32_t* pFuchsiaHandle)
{
ANV_FROM_HANDLE(anv_device, device, vk_device);
ANV_FROM_HANDLE(anv_semaphore, semaphore, info->semaphore);
assert(info->sType == VK_STRUCTURE_TYPE_SEMAPHORE_GET_FUCHSIA_HANDLE_INFO_KHR);
if (info->handleType != VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_FUCHSIA_FENCE_BIT_KHR)
return VK_SUCCESS;
struct anv_semaphore_impl* impl = semaphore->temporary.type != ANV_SEMAPHORE_TYPE_NONE
? &semaphore->temporary
: &semaphore->permanent;
uint32_t handle;
magma_status_t status =
magma_export_semaphore(magma_connection(device), impl->syncobj, &handle);
if (status != MAGMA_STATUS_OK)
return vk_error(VK_ERROR_TOO_MANY_OBJECTS);
/* From the Vulkan 1.0.53 spec:
*
* "Export operations have the same transference as the specified handle
* type’s import operations. [...] If the semaphore was using a
* temporarily imported payload, the semaphore’s prior permanent payload
* will be restored.
*/
anv_semaphore_reset_temporary(device, semaphore);
*pFuchsiaHandle = handle;
return VK_SUCCESS;
}
#endif // VK_USE_PLATFORM_FUCHSIA
bool anv_gem_supports_syncobj_wait(int fd) { return true; }
anv_syncobj_handle_t anv_gem_syncobj_create(struct anv_device* device, uint32_t flags)
{
magma_semaphore_t semaphore;
magma_status_t status = magma_create_semaphore(magma_connection(device), &semaphore);
if (status != MAGMA_STATUS_OK) {
DLOG("magma_create_semaphore failed: %d", status);
return 0;
}
if (flags & DRM_SYNCOBJ_CREATE_SIGNALED)
magma_signal_semaphore(semaphore);
return semaphore;
}
void anv_gem_syncobj_destroy(struct anv_device* device, anv_syncobj_handle_t semaphore)
{
magma_release_semaphore(magma_connection(device), semaphore);
}
void anv_gem_syncobj_reset(struct anv_device* device, anv_syncobj_handle_t fence)
{
magma_reset_semaphore(fence);
}
static uint64_t gettime_ns(void)
{
struct timespec current;
clock_gettime(CLOCK_MONOTONIC, &current);
#define NSEC_PER_SEC 1000000000
return (uint64_t)current.tv_sec * NSEC_PER_SEC + current.tv_nsec;
#undef NSEC_PER_SEC
}
static int64_t anv_get_relative_timeout(uint64_t abs_timeout)
{
uint64_t now = gettime_ns();
if (abs_timeout < now)
return 0;
return abs_timeout - now;
}
static inline uint64_t ns_to_ms(uint64_t ns) { return ns / 1000000ull; }
int anv_gem_syncobj_wait(struct anv_device* device, anv_syncobj_handle_t* fences, uint32_t fence_count,
int64_t abs_timeout_ns, bool wait_all)
{
int64_t timeout_ns = anv_get_relative_timeout(abs_timeout_ns);
magma_status_t status =
magma_wait_semaphores(fences, fence_count, ns_to_ms(timeout_ns), wait_all);
switch (status) {
case MAGMA_STATUS_OK:
break;
case MAGMA_STATUS_TIMED_OUT:
errno = ETIME;
// fall through
default:
return -1;
}
return 0;
}
anv_syncobj_handle_t anv_gem_syncobj_fd_to_handle(struct anv_device* device, int fd)
{
assert(false);
return 0;
}
int anv_gem_syncobj_handle_to_fd(struct anv_device* device, anv_syncobj_handle_t handle)
{
assert(false);
return -1;
}
int anv_gem_syncobj_export_sync_file(struct anv_device* device, anv_syncobj_handle_t handle)
{
assert(false);
return -1;
}
int anv_gem_syncobj_import_sync_file(struct anv_device* device, anv_syncobj_handle_t handle, int fd)
{
assert(false);
return -1;
}
int anv_gem_sync_file_merge(struct anv_device* device, int fd1, int fd2)
{
assert(false);
return -1;
}
int anv_gem_set_context_param(int fd, int context, uint32_t param, uint64_t value)
{
assert(false);
return -1;
}
bool anv_gem_has_context_priority(int fd)
{
return false;
}