Path: blob/21.2-virgl/src/freedreno/vulkan/tu_kgsl.c
4565 views
/*1* Copyright © 2020 Google, Inc.2*3* Permission is hereby granted, free of charge, to any person obtaining a4* copy of this software and associated documentation files (the "Software"),5* to deal in the Software without restriction, including without limitation6* the rights to use, copy, modify, merge, publish, distribute, sublicense,7* and/or sell copies of the Software, and to permit persons to whom the8* Software is furnished to do so, subject to the following conditions:9*10* The above copyright notice and this permission notice (including the next11* paragraph) shall be included in all copies or substantial portions of the12* Software.13*14* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR15* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,16* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL17* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER18* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING19* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER20* DEALINGS IN THE SOFTWARE.21*/2223#include "tu_private.h"2425#include <errno.h>26#include <fcntl.h>27#include <stdint.h>28#include <sys/ioctl.h>29#include <sys/mman.h>3031#include "msm_kgsl.h"32#include "vk_util.h"3334struct tu_syncobj {35struct vk_object_base base;36uint32_t timestamp;37bool timestamp_valid;38};3940static int41safe_ioctl(int fd, unsigned long request, void *arg)42{43int ret;4445do {46ret = ioctl(fd, request, arg);47} while (ret == -1 && (errno == EINTR || errno == EAGAIN));4849return ret;50}5152int53tu_drm_submitqueue_new(const struct tu_device *dev,54int priority,55uint32_t *queue_id)56{57struct kgsl_drawctxt_create req = {58.flags = KGSL_CONTEXT_SAVE_GMEM |59KGSL_CONTEXT_NO_GMEM_ALLOC |60KGSL_CONTEXT_PREAMBLE,61};6263int ret = safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_CREATE, &req);64if (ret)65return ret;6667*queue_id = req.drawctxt_id;6869return 0;70}7172void73tu_drm_submitqueue_close(const struct tu_device *dev, uint32_t queue_id)74{75struct kgsl_drawctxt_destroy req = {76.drawctxt_id = queue_id,77};7879safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_DRAWCTXT_DESTROY, &req);80}8182VkResult83tu_bo_init_new(struct tu_device *dev, struct tu_bo *bo, uint64_t size,84enum tu_bo_alloc_flags flags)85{86struct kgsl_gpumem_alloc_id req = {87.size = size,88};8990if (flags & TU_BO_ALLOC_GPU_READ_ONLY)91req.flags |= KGSL_MEMFLAGS_GPUREADONLY;9293int ret;9495ret = safe_ioctl(dev->physical_device->local_fd,96IOCTL_KGSL_GPUMEM_ALLOC_ID, &req);97if (ret) {98return vk_errorf(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY,99"GPUMEM_ALLOC_ID failed (%s)", strerror(errno));100}101102*bo = (struct tu_bo) {103.gem_handle = req.id,104.size = req.mmapsize,105.iova = req.gpuaddr,106};107108return VK_SUCCESS;109}110111VkResult112tu_bo_init_dmabuf(struct tu_device *dev,113struct tu_bo *bo,114uint64_t size,115int fd)116{117struct kgsl_gpuobj_import_dma_buf import_dmabuf = {118.fd = fd,119};120struct kgsl_gpuobj_import req = {121.priv = (uintptr_t)&import_dmabuf,122.priv_len = sizeof(import_dmabuf),123.flags = 0,124.type = KGSL_USER_MEM_TYPE_DMABUF,125};126int ret;127128ret = safe_ioctl(dev->physical_device->local_fd,129IOCTL_KGSL_GPUOBJ_IMPORT, &req);130if (ret)131return vk_errorf(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY,132"Failed to import dma-buf (%s)\n", strerror(errno));133134struct kgsl_gpuobj_info info_req = {135.id = req.id,136};137138ret = safe_ioctl(dev->physical_device->local_fd,139IOCTL_KGSL_GPUOBJ_INFO, &info_req);140if (ret)141return vk_errorf(dev->instance, VK_ERROR_OUT_OF_DEVICE_MEMORY,142"Failed to get dma-buf info (%s)\n", strerror(errno));143144*bo = (struct tu_bo) {145.gem_handle = req.id,146.size = info_req.size,147.iova = info_req.gpuaddr,148};149150return VK_SUCCESS;151}152153int154tu_bo_export_dmabuf(struct tu_device *dev, struct tu_bo *bo)155{156tu_stub();157158return -1;159}160161VkResult162tu_bo_map(struct tu_device *dev, struct tu_bo *bo)163{164if (bo->map)165return VK_SUCCESS;166167uint64_t offset = bo->gem_handle << 12;168void *map = mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,169dev->physical_device->local_fd, offset);170if (map == MAP_FAILED)171return vk_error(dev->instance, VK_ERROR_MEMORY_MAP_FAILED);172173bo->map = map;174175return VK_SUCCESS;176}177178void179tu_bo_finish(struct tu_device *dev, struct tu_bo *bo)180{181assert(bo->gem_handle);182183if (bo->map)184munmap(bo->map, bo->size);185186struct kgsl_gpumem_free_id req = {187.id = bo->gem_handle188};189190safe_ioctl(dev->physical_device->local_fd, IOCTL_KGSL_GPUMEM_FREE_ID, &req);191}192193static VkResult194get_kgsl_prop(int fd, unsigned int type, void *value, size_t size)195{196struct kgsl_device_getproperty getprop = {197.type = type,198.value = value,199.sizebytes = size,200};201202return safe_ioctl(fd, IOCTL_KGSL_DEVICE_GETPROPERTY, &getprop);203}204205VkResult206tu_enumerate_devices(struct tu_instance *instance)207{208static const char path[] = "/dev/kgsl-3d0";209int fd;210211struct tu_physical_device *device = &instance->physical_devices[0];212213if (instance->vk.enabled_extensions.KHR_display)214return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,215"I can't KHR_display");216217fd = open(path, O_RDWR | O_CLOEXEC);218if (fd < 0) {219instance->physical_device_count = 0;220return vk_errorf(instance, VK_ERROR_INCOMPATIBLE_DRIVER,221"failed to open device %s", path);222}223224struct kgsl_devinfo info;225if (get_kgsl_prop(fd, KGSL_PROP_DEVICE_INFO, &info, sizeof(info)))226goto fail;227228uint64_t gmem_iova;229if (get_kgsl_prop(fd, KGSL_PROP_UCHE_GMEM_VADDR, &gmem_iova, sizeof(gmem_iova)))230goto fail;231232/* kgsl version check? */233234if (instance->debug_flags & TU_DEBUG_STARTUP)235mesa_logi("Found compatible device '%s'.", path);236237device->instance = instance;238device->master_fd = -1;239device->local_fd = fd;240241device->gpu_id =242((info.chip_id >> 24) & 0xff) * 100 +243((info.chip_id >> 16) & 0xff) * 10 +244((info.chip_id >> 8) & 0xff);245device->gmem_size = info.gmem_sizebytes;246device->gmem_base = gmem_iova;247248device->heap.size = tu_get_system_heap_size();249device->heap.used = 0u;250device->heap.flags = VK_MEMORY_HEAP_DEVICE_LOCAL_BIT;251252if (tu_physical_device_init(device, instance) != VK_SUCCESS)253goto fail;254255instance->physical_device_count = 1;256257return VK_SUCCESS;258259fail:260close(fd);261return VK_ERROR_INITIALIZATION_FAILED;262}263264static int265timestamp_to_fd(struct tu_queue *queue, uint32_t timestamp)266{267int fd;268struct kgsl_timestamp_event event = {269.type = KGSL_TIMESTAMP_EVENT_FENCE,270.context_id = queue->msm_queue_id,271.timestamp = timestamp,272.priv = &fd,273.len = sizeof(fd),274};275276int ret = safe_ioctl(queue->device->fd, IOCTL_KGSL_TIMESTAMP_EVENT, &event);277if (ret)278return -1;279280return fd;281}282283/* return true if timestamp a is greater (more recent) then b284* this relies on timestamps never having a difference > (1<<31)285*/286static inline bool287timestamp_cmp(uint32_t a, uint32_t b)288{289return (int32_t) (a - b) >= 0;290}291292static uint32_t293max_ts(uint32_t a, uint32_t b)294{295return timestamp_cmp(a, b) ? a : b;296}297298static uint32_t299min_ts(uint32_t a, uint32_t b)300{301return timestamp_cmp(a, b) ? b : a;302}303304static struct tu_syncobj305sync_merge(const VkSemaphore *syncobjs, uint32_t count, bool wait_all, bool reset)306{307struct tu_syncobj ret;308309ret.timestamp_valid = false;310311for (uint32_t i = 0; i < count; ++i) {312TU_FROM_HANDLE(tu_syncobj, sync, syncobjs[i]);313314/* TODO: this means the fence is unsignaled and will never become signaled */315if (!sync->timestamp_valid)316continue;317318if (!ret.timestamp_valid)319ret.timestamp = sync->timestamp;320else if (wait_all)321ret.timestamp = max_ts(ret.timestamp, sync->timestamp);322else323ret.timestamp = min_ts(ret.timestamp, sync->timestamp);324325ret.timestamp_valid = true;326if (reset)327sync->timestamp_valid = false;328329}330return ret;331}332333VKAPI_ATTR VkResult VKAPI_CALL334tu_QueueSubmit(VkQueue _queue,335uint32_t submitCount,336const VkSubmitInfo *pSubmits,337VkFence _fence)338{339TU_FROM_HANDLE(tu_queue, queue, _queue);340TU_FROM_HANDLE(tu_syncobj, fence, _fence);341VkResult result = VK_SUCCESS;342343uint32_t max_entry_count = 0;344for (uint32_t i = 0; i < submitCount; ++i) {345const VkSubmitInfo *submit = pSubmits + i;346347const VkPerformanceQuerySubmitInfoKHR *perf_info =348vk_find_struct_const(pSubmits[i].pNext,349PERFORMANCE_QUERY_SUBMIT_INFO_KHR);350351uint32_t entry_count = 0;352for (uint32_t j = 0; j < submit->commandBufferCount; ++j) {353TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);354entry_count += cmdbuf->cs.entry_count;355if (perf_info)356entry_count++;357}358359max_entry_count = MAX2(max_entry_count, entry_count);360}361362struct kgsl_command_object *cmds =363vk_alloc(&queue->device->vk.alloc,364sizeof(cmds[0]) * max_entry_count, 8,365VK_SYSTEM_ALLOCATION_SCOPE_COMMAND);366if (cmds == NULL)367return vk_error(queue->device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);368369for (uint32_t i = 0; i < submitCount; ++i) {370const VkSubmitInfo *submit = pSubmits + i;371uint32_t entry_idx = 0;372const VkPerformanceQuerySubmitInfoKHR *perf_info =373vk_find_struct_const(pSubmits[i].pNext,374PERFORMANCE_QUERY_SUBMIT_INFO_KHR);375376377for (uint32_t j = 0; j < submit->commandBufferCount; j++) {378TU_FROM_HANDLE(tu_cmd_buffer, cmdbuf, submit->pCommandBuffers[j]);379struct tu_cs *cs = &cmdbuf->cs;380381if (perf_info) {382struct tu_cs_entry *perf_cs_entry =383&cmdbuf->device->perfcntrs_pass_cs_entries[perf_info->counterPassIndex];384385cmds[entry_idx++] = (struct kgsl_command_object) {386.offset = perf_cs_entry->offset,387.gpuaddr = perf_cs_entry->bo->iova,388.size = perf_cs_entry->size,389.flags = KGSL_CMDLIST_IB,390.id = perf_cs_entry->bo->gem_handle,391};392}393394for (unsigned k = 0; k < cs->entry_count; k++) {395cmds[entry_idx++] = (struct kgsl_command_object) {396.offset = cs->entries[k].offset,397.gpuaddr = cs->entries[k].bo->iova,398.size = cs->entries[k].size,399.flags = KGSL_CMDLIST_IB,400.id = cs->entries[k].bo->gem_handle,401};402}403}404405struct tu_syncobj s = sync_merge(submit->pWaitSemaphores,406submit->waitSemaphoreCount,407true, true);408409struct kgsl_cmd_syncpoint_timestamp ts = {410.context_id = queue->msm_queue_id,411.timestamp = s.timestamp,412};413struct kgsl_command_syncpoint sync = {414.type = KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP,415.size = sizeof(ts),416.priv = (uintptr_t) &ts,417};418419struct kgsl_gpu_command req = {420.flags = KGSL_CMDBATCH_SUBMIT_IB_LIST,421.context_id = queue->msm_queue_id,422.cmdlist = (uint64_t) (uintptr_t) cmds,423.numcmds = entry_idx,424.cmdsize = sizeof(struct kgsl_command_object),425.synclist = (uintptr_t) &sync,426.syncsize = sizeof(struct kgsl_command_syncpoint),427.numsyncs = s.timestamp_valid ? 1 : 0,428};429430int ret = safe_ioctl(queue->device->physical_device->local_fd,431IOCTL_KGSL_GPU_COMMAND, &req);432if (ret) {433result = tu_device_set_lost(queue->device,434"submit failed: %s\n", strerror(errno));435goto fail;436}437438for (uint32_t i = 0; i < submit->signalSemaphoreCount; i++) {439TU_FROM_HANDLE(tu_syncobj, sem, submit->pSignalSemaphores[i]);440sem->timestamp = req.timestamp;441sem->timestamp_valid = true;442}443444/* no need to merge fences as queue execution is serialized */445if (i == submitCount - 1) {446int fd = timestamp_to_fd(queue, req.timestamp);447if (fd < 0) {448result = tu_device_set_lost(queue->device,449"Failed to create sync file for timestamp: %s\n",450strerror(errno));451goto fail;452}453454if (queue->fence >= 0)455close(queue->fence);456queue->fence = fd;457458if (fence) {459fence->timestamp = req.timestamp;460fence->timestamp_valid = true;461}462}463}464fail:465vk_free(&queue->device->vk.alloc, cmds);466467return result;468}469470static VkResult471sync_create(VkDevice _device,472bool signaled,473bool fence,474const VkAllocationCallbacks *pAllocator,475void **p_sync)476{477TU_FROM_HANDLE(tu_device, device, _device);478479struct tu_syncobj *sync =480vk_object_alloc(&device->vk, pAllocator, sizeof(*sync),481fence ? VK_OBJECT_TYPE_FENCE : VK_OBJECT_TYPE_SEMAPHORE);482if (!sync)483return vk_error(device->instance, VK_ERROR_OUT_OF_HOST_MEMORY);484485if (signaled)486tu_finishme("CREATE FENCE SIGNALED");487488sync->timestamp_valid = false;489*p_sync = sync;490491return VK_SUCCESS;492}493494VKAPI_ATTR VkResult VKAPI_CALL495tu_ImportSemaphoreFdKHR(VkDevice _device,496const VkImportSemaphoreFdInfoKHR *pImportSemaphoreFdInfo)497{498tu_finishme("ImportSemaphoreFdKHR");499return VK_SUCCESS;500}501502VKAPI_ATTR VkResult VKAPI_CALL503tu_GetSemaphoreFdKHR(VkDevice _device,504const VkSemaphoreGetFdInfoKHR *pGetFdInfo,505int *pFd)506{507tu_finishme("GetSemaphoreFdKHR");508return VK_SUCCESS;509}510511VKAPI_ATTR VkResult VKAPI_CALL512tu_CreateSemaphore(VkDevice device,513const VkSemaphoreCreateInfo *pCreateInfo,514const VkAllocationCallbacks *pAllocator,515VkSemaphore *pSemaphore)516{517return sync_create(device, false, false, pAllocator, (void**) pSemaphore);518}519520VKAPI_ATTR void VKAPI_CALL521tu_DestroySemaphore(VkDevice _device,522VkSemaphore semaphore,523const VkAllocationCallbacks *pAllocator)524{525TU_FROM_HANDLE(tu_device, device, _device);526TU_FROM_HANDLE(tu_syncobj, sync, semaphore);527528if (!sync)529return;530531vk_object_free(&device->vk, pAllocator, sync);532}533534VKAPI_ATTR VkResult VKAPI_CALL535tu_ImportFenceFdKHR(VkDevice _device,536const VkImportFenceFdInfoKHR *pImportFenceFdInfo)537{538tu_stub();539540return VK_SUCCESS;541}542543VKAPI_ATTR VkResult VKAPI_CALL544tu_GetFenceFdKHR(VkDevice _device,545const VkFenceGetFdInfoKHR *pGetFdInfo,546int *pFd)547{548tu_stub();549550return VK_SUCCESS;551}552553VKAPI_ATTR VkResult VKAPI_CALL554tu_CreateFence(VkDevice device,555const VkFenceCreateInfo *info,556const VkAllocationCallbacks *pAllocator,557VkFence *pFence)558{559return sync_create(device, info->flags & VK_FENCE_CREATE_SIGNALED_BIT, true,560pAllocator, (void**) pFence);561}562563VKAPI_ATTR void VKAPI_CALL564tu_DestroyFence(VkDevice _device, VkFence fence, const VkAllocationCallbacks *pAllocator)565{566TU_FROM_HANDLE(tu_device, device, _device);567TU_FROM_HANDLE(tu_syncobj, sync, fence);568569if (!sync)570return;571572vk_object_free(&device->vk, pAllocator, sync);573}574575VKAPI_ATTR VkResult VKAPI_CALL576tu_WaitForFences(VkDevice _device,577uint32_t count,578const VkFence *pFences,579VkBool32 waitAll,580uint64_t timeout)581{582TU_FROM_HANDLE(tu_device, device, _device);583struct tu_syncobj s = sync_merge((const VkSemaphore*) pFences, count, waitAll, false);584585if (!s.timestamp_valid)586return VK_SUCCESS;587588int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,589&(struct kgsl_device_waittimestamp_ctxtid) {590.context_id = device->queues[0]->msm_queue_id,591.timestamp = s.timestamp,592.timeout = timeout / 1000000,593});594if (ret) {595assert(errno == ETIME);596return VK_TIMEOUT;597}598599return VK_SUCCESS;600}601602VKAPI_ATTR VkResult VKAPI_CALL603tu_ResetFences(VkDevice _device, uint32_t count, const VkFence *pFences)604{605for (uint32_t i = 0; i < count; i++) {606TU_FROM_HANDLE(tu_syncobj, sync, pFences[i]);607sync->timestamp_valid = false;608}609return VK_SUCCESS;610}611612VKAPI_ATTR VkResult VKAPI_CALL613tu_GetFenceStatus(VkDevice _device, VkFence _fence)614{615TU_FROM_HANDLE(tu_device, device, _device);616TU_FROM_HANDLE(tu_syncobj, sync, _fence);617618if (!sync->timestamp_valid)619return VK_NOT_READY;620621int ret = ioctl(device->fd, IOCTL_KGSL_DEVICE_WAITTIMESTAMP_CTXTID,622&(struct kgsl_device_waittimestamp_ctxtid) {623.context_id = device->queues[0]->msm_queue_id,624.timestamp = sync->timestamp,625.timeout = 0,626});627if (ret) {628assert(errno == ETIME);629return VK_NOT_READY;630}631632return VK_SUCCESS;633}634635int636tu_signal_fences(struct tu_device *device, struct tu_syncobj *fence1, struct tu_syncobj *fence2)637{638tu_finishme("tu_signal_fences");639return 0;640}641642int643tu_syncobj_to_fd(struct tu_device *device, struct tu_syncobj *sync)644{645tu_finishme("tu_syncobj_to_fd");646return -1;647}648649VkResult650tu_device_submit_deferred_locked(struct tu_device *dev)651{652tu_finishme("tu_device_submit_deferred_locked");653654return VK_SUCCESS;655}656657#ifdef ANDROID658VKAPI_ATTR VkResult VKAPI_CALL659tu_QueueSignalReleaseImageANDROID(VkQueue _queue,660uint32_t waitSemaphoreCount,661const VkSemaphore *pWaitSemaphores,662VkImage image,663int *pNativeFenceFd)664{665TU_FROM_HANDLE(tu_queue, queue, _queue);666if (!pNativeFenceFd)667return VK_SUCCESS;668669struct tu_syncobj s = sync_merge(pWaitSemaphores, waitSemaphoreCount, true, true);670671if (!s.timestamp_valid) {672*pNativeFenceFd = -1;673return VK_SUCCESS;674}675676*pNativeFenceFd = timestamp_to_fd(queue, s.timestamp);677678return VK_SUCCESS;679}680#endif681682683