From 8dde5b888d3c1c3be42ae88f2ded86222d0db4ee Mon Sep 17 00:00:00 2001 From: Unknown <0.tamas.marton@gmail.com> Date: Sun, 13 May 2018 15:29:43 +0100 Subject: [PATCH] updated modeset, vc4 kernel interface added --- driver/driver.c | 47 ++--- driver/kernelInterface.c | 368 +++++++++++++++++++++++++++++++++++++++ driver/kernelInterface.h | 52 ++++++ driver/modeset.c | 69 +++----- driver/modeset.h | 8 +- 5 files changed, 458 insertions(+), 86 deletions(-) create mode 100644 driver/kernelInterface.c create mode 100644 driver/kernelInterface.h diff --git a/driver/driver.c b/driver/driver.c index f8b025b..fc8aa82 100644 --- a/driver/driver.c +++ b/driver/driver.c @@ -2,28 +2,19 @@ #include "CustomAssert.h" #include #include -#include #include #include -#include -#include -#include -#include -#include - -#include #include #include "vkExt.h" #include "modeset.h" +#include "kernelInterface.h" #include "AlignedAllocator.h" #include "PoolAllocator.h" #include "LinearAllocator.h" -#include "drm/vc4_drm.h" - #ifndef min #define min(a, b) (a < b ? a : b) #endif @@ -32,26 +23,6 @@ #define max(a, b) (a > b ? a : b) #endif -#define DRM_IOCTL_FILE_NAME "/dev/"DRM_NAME - -static int fd = -1; - -int openIoctl() -{ - fd = open(DRM_IOCTL_FILE_NAME, O_RDWR); - if (fd < 0) { - printf("Can't open device file: %s\n", DRM_IOCTL_FILE_NAME); - return -1; - } - - return 0; -} - -void closeIoctl(int fd) -{ - close(fd); -} - VkPhysicalDeviceLimits _limits = { //TODO these values might change @@ -250,7 +221,7 @@ typedef struct VkCommandBuffer_T //Recorded commands include commands to bind pipelines and descriptor sets to the command buffer, commands to modify dynamic state, commands to draw (for graphics rendering), //commands to dispatch (for compute), commands to execute secondary command buffers (for primary command buffers only), commands to copy buffers and images, and other commands - drm_vc4_submit_cl cls[100]; //each cl is a draw call + struct drm_vc4_submit_cl cls[100]; //each cl is a draw call unsigned numClsUsed; commandBufferState state; VkCommandBufferUsageFlags usageFlags; @@ -473,6 +444,11 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance( //TODO ignored for now //pCreateInfo->pApplicationInfo + int ret = openIoctl(); assert(!ret); + + int chip_info = vc4_get_chip_info(renderFd); + int has_tiling = vc4_test_tiling(renderFd); + return VK_SUCCESS; } @@ -666,8 +642,7 @@ VkResult vkCreateRpiSurfaceKHR( //TODO: allocator is ignored for now assert(pAllocator == 0); - int ret = modeset_open("/dev/dri/card0"); assert(!ret); - *pSurface = (VkSurfaceKHR)modeset_create(); + *pSurface = (VkSurfaceKHR)modeset_create(controlFd); return VK_SUCCESS; } @@ -689,8 +664,7 @@ VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR( //TODO: allocator is ignored for now assert(pAllocator == 0); - modeset_destroy((modeset_dev*)surface); - modeset_close(); + modeset_destroy(controlFd, (modeset_dev*)surface); } /* @@ -1330,7 +1304,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkQueuePresentKHR( for(int c = 0; c < pPresentInfo->swapchainCount; ++c) { //TODO - modeset_swapbuffer((modeset_dev*)pPresentInfo->pSwapchains[c], pPresentInfo->pImageIndices[c]); + modeset_swapbuffer(controlFd, (modeset_dev*)pPresentInfo->pSwapchains[c], pPresentInfo->pImageIndices[c]); } return VK_SUCCESS; @@ -1479,5 +1453,6 @@ VKAPI_ATTR void VKAPI_CALL vkDestroyInstance( assert(pAllocator == 0); //TODO + closeIoctl(); } diff --git a/driver/kernelInterface.c b/driver/kernelInterface.c new file mode 100644 index 0000000..1ad1a94 --- /dev/null +++ b/driver/kernelInterface.c @@ -0,0 +1,368 @@ +#define _GNU_SOURCE +#include "kernelInterface.h" + +int controlFd = -1; +int renderFd = -1; + +int openIoctl() +{ + controlFd = open(DRM_IOCTL_CTRL_DEV_FILE_NAME, O_RDWR | O_CLOEXEC); + if (controlFd < 0) { + printf("Can't open device file: %s\n", DRM_IOCTL_CTRL_DEV_FILE_NAME); + return -1; + } + + renderFd = open(DRM_IOCTL_RENDER_DEV_FILE_NAME, O_RDWR | O_CLOEXEC); + if (renderFd < 0) { + printf("Can't open device file: %s\n", DRM_IOCTL_RENDER_DEV_FILE_NAME); + return -1; + } + + return 0; +} + +void closeIoctl() +{ + close(controlFd); + close(renderFd); +} + +int vc4_get_chip_info(int fd) +{ + struct drm_vc4_get_param ident0 = { + .param = DRM_VC4_PARAM_V3D_IDENT0, + }; + struct drm_vc4_get_param ident1 = { + .param = DRM_VC4_PARAM_V3D_IDENT1, + }; + int ret; + + ret = drmIoctl(fd, DRM_IOCTL_VC4_GET_PARAM, &ident0); + if (ret != 0) { + if (errno == EINVAL) { + /* Backwards compatibility with 2835 kernels which + * only do V3D 2.1. + */ + return 21; + } else { + printf("Couldn't get V3D IDENT0: %s\n", + strerror(errno)); + return 0; + } + } + ret = drmIoctl(fd, DRM_IOCTL_VC4_GET_PARAM, &ident1); + if (ret != 0) { + printf("Couldn't get V3D IDENT1: %s\n", + strerror(errno)); + return 0; + } + + uint32_t major = (ident0.value >> 24) & 0xff; + uint32_t minor = (ident1.value >> 0) & 0xf; + uint32_t v3d_ver = major * 10 + minor; + + if (v3d_ver != 21 && v3d_ver != 26) { + printf("V3D %d.%d not supported.\n", + v3d_ver / 10, + v3d_ver % 10); + return 0; + } + + return v3d_ver; +} + +int vc4_has_feature(int fd, uint32_t feature) +{ + struct drm_vc4_get_param p = { + .param = feature, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_GET_PARAM, &p); + + if (ret != 0) + return 0; + + return p.value; +} + +int vc4_test_tiling(int fd) +{ + /* Test if the kernel has GET_TILING; it will return -EINVAL if the + * ioctl does not exist, but -ENOENT if we pass an impossible handle. + * 0 cannot be a valid GEM object, so use that. + */ + struct drm_vc4_get_tiling get_tiling = { + .handle = 0x0, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling); + if (ret == -1 && errno == ENOENT) + { + return 1; + } + + return 0; +} + +uint64_t vc4_bo_get_tiling(int fd, uint32_t bo, uint64_t mod) +{ + struct drm_vc4_get_tiling get_tiling = { + .handle = bo, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_GET_TILING, &get_tiling); + + //TODO + if (ret != 0) { + return DRM_FORMAT_MOD_LINEAR; + } else if (mod == DRM_FORMAT_MOD_INVALID) { + return get_tiling.modifier; + } else if (mod != get_tiling.modifier) { + printf("Modifier 0x%llx vs. tiling (0x%llx) mismatch\n", + (long long)mod, get_tiling.modifier); + return 0; + } +} + +int vc4_bo_set_tiling(int fd, uint32_t bo, uint64_t mod) +{ + struct drm_vc4_set_tiling set_tiling = { + .handle = bo, + .modifier = mod, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_SET_TILING, + &set_tiling); + if (ret != 0) + { + return 0; + } + + return 1; +} + +void* vc4_bo_map_unsynchronized(int fd, uint32_t bo, uint32_t size) +{ + uint64_t offset; + int ret; + + //if (bo->map) + // return bo->map; + + struct drm_vc4_mmap_bo map; + memset(&map, 0, sizeof(map)); + map.handle = bo; + ret = drmIoctl(fd, DRM_IOCTL_VC4_MMAP_BO, &map); + offset = map.offset; + if (ret != 0) { + printf("map ioctl failure\n"); + return 0; + } + + void* mapPtr = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, + fd, offset); + if (mapPtr == MAP_FAILED) { + printf("mmap of bo %d (offset 0x%016llx, size %d) failed\n", + bo, (long long)offset, size); + return 0; + } + //VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, false)); + + return mapPtr; +} + +int vc4_bo_wait_ioctl(int fd, uint32_t handle, uint64_t timeout_ns) +{ + struct drm_vc4_wait_bo wait = { + .handle = handle, + .timeout_ns = timeout_ns, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_WAIT_BO, &wait); + if (ret == -1) + { + printf("bo wait fail: %s", strerror(errno)); + return 0; + } + else + { + return 1; + } +} + +int vc4_seqno_wait_ioctl(int fd, uint64_t seqno, uint64_t timeout_ns) +{ + struct drm_vc4_wait_seqno wait = { + .seqno = seqno, + .timeout_ns = timeout_ns, + }; + int ret = drmIoctl(fd, DRM_IOCTL_VC4_WAIT_SEQNO, &wait); + if (ret == -1) + { + printf("bo wait fail: %s", strerror(errno)); + return 0; + } + else + { + return 1; + } + +} + +int vc4_bo_flink(int fd, uint32_t bo, uint32_t *name) +{ + struct drm_gem_flink flink = { + .handle = bo, + }; + int ret = drmIoctl(fd, DRM_IOCTL_GEM_FLINK, &flink); + if (ret) { + printf("Failed to flink bo %d: %s\n", + bo, strerror(errno)); + //free(bo); + return 0; + } + + //bo->private = false; + *name = flink.name; + + return 1; +} + +uint32_t vc4_bo_alloc_shader(int fd, const void *data, uint32_t* size) +{ + int ret; + + //TODO + uint32_t alignedSize = *size;//align(*size, 4096); + + struct drm_vc4_create_shader_bo create = { + .size = *size, //TODO why isn't this alignedSize? + .data = (uintptr_t)data, + }; + + ret = drmIoctl(fd, DRM_IOCTL_VC4_CREATE_SHADER_BO, + &create); + + if (ret != 0) { + printf("create shader ioctl failure\n"); + return 0; + } + + *size = alignedSize; + + return create.handle; +} + +uint32_t vc4_bo_open_name(int fd, uint32_t name) + //uint32_t winsys_stride) +{ + struct drm_gem_open o = { + .name = name + }; + int ret = drmIoctl(fd, DRM_IOCTL_GEM_OPEN, &o); + if (ret) { + printf("Failed to open bo %d: %s\n", + name, strerror(errno)); + return 0; + } + + //TODO + //return vc4_bo_open_handle(screen, winsys_stride, o.handle, o.size); + return 1; +} + +uint32_t vc4_bo_alloc(int fd, uint32_t size, const char *name) +{ + int cleared_and_retried = 0; + struct drm_vc4_create_bo create; + int ret; + + //TODO + uint32_t alignedSize = size;//align(size, 4096); + + /*bo = vc4_bo_from_cache(screen, size, name); + if (bo) { + if (dump_stats) { + fprintf(stderr, "Allocated %s %dkb from cache:\n", + name, size / 1024); + vc4_bo_dump_stats(screen); + } + return bo; + }*/ + + memset(&create, 0, sizeof(create)); + create.size = alignedSize; + + ret = drmIoctl(fd, DRM_IOCTL_VC4_CREATE_BO, &create); + uint32_t handle = create.handle; + + if (ret != 0) { + /*if (!list_empty(&screen->bo_cache.time_list) && + !cleared_and_retried) { + cleared_and_retried = true; + vc4_bo_cache_free_all(&screen->bo_cache); + goto retry; + } + + free(bo);*/ + return 0; + } + + //TODO + //vc4_bo_label(screen, bo, "%s", name); + + return handle; +} + +void vc4_bo_free(int fd, uint32_t bo, void* mappedAddr, uint32_t size) +{ + if (mappedAddr) { + munmap(mappedAddr, size); + //VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); + } + + struct drm_gem_close c; + memset(&c, 0, sizeof(c)); + c.handle = bo; + int ret = drmIoctl(fd, DRM_IOCTL_GEM_CLOSE, &c); + if (ret != 0) + { + printf("close object %d: %s\n", bo, strerror(errno)); + } +} + +int vc4_bo_unpurgeable(int fd, uint32_t bo, int hasMadvise) +{ + struct drm_vc4_gem_madvise arg = { + .handle = bo, + .madv = VC4_MADV_WILLNEED, + }; + + if (!hasMadvise) + return 1; + + if (drmIoctl(fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg)) + return 0; + + return arg.retained; +} + +void vc4_bo_purgeable(int fd, uint32_t bo, int hasMadvise) +{ + struct drm_vc4_gem_madvise arg = { + .handle = bo, + .madv = VC4_MADV_DONTNEED, + }; + + if (hasMadvise) + { + drmIoctl(fd, DRM_IOCTL_VC4_GEM_MADVISE, &arg); + } +} + +void vc4_bo_label(int fd, uint32_t bo, const char* name) +{ + //TODO don't use in release! + + struct drm_vc4_label_bo label = { + .handle = bo, + .len = strlen(name), + .name = (uintptr_t)name, + }; + drmIoctl(fd, DRM_IOCTL_VC4_LABEL_BO, &label); +} diff --git a/driver/kernelInterface.h b/driver/kernelInterface.h new file mode 100644 index 0000000..bb4696f --- /dev/null +++ b/driver/kernelInterface.h @@ -0,0 +1,52 @@ +#pragma once + +#if defined (__cplusplus) +extern "C" { +#endif + +#include +#include "CustomAssert.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define DRM_IOCTL_CTRL_DEV_FILE_NAME "/dev/dri/card0" +#define DRM_IOCTL_RENDER_DEV_FILE_NAME "/dev/dri/renderD128" //TODO does this need to be dynamic? (eg. iterate through renderDn?) + +extern int controlFd; +extern int renderFd; + +int openIoctl(); +void closeIoctl(); + +int vc4_get_chip_info(int fd); +int vc4_has_feature(int fd, uint32_t feature); +int vc4_test_tiling(int fd); +uint64_t vc4_bo_get_tiling(int fd, uint32_t bo, uint64_t mod); +int vc4_bo_set_tiling(int fd, uint32_t bo, uint64_t mod); +void* vc4_bo_map_unsynchronized(int fd, uint32_t bo, uint32_t size); +int vc4_bo_wait_ioctl(int fd, uint32_t handle, uint64_t timeout_ns); +int vc4_seqno_wait_ioctl(int fd, uint64_t seqno, uint64_t timeout_ns); +int vc4_bo_flink(int fd, uint32_t bo, uint32_t *name); +uint32_t vc4_bo_alloc_shader(int fd, const void *data, uint32_t* size); +uint32_t vc4_bo_open_name(int fd, uint32_t name); +uint32_t vc4_bo_alloc(int fd, uint32_t size, const char *name); +void vc4_bo_free(int fd, uint32_t bo, void* mappedAddr, uint32_t size); +int vc4_bo_unpurgeable(int fd, uint32_t bo, int hasMadvise); +void vc4_bo_purgeable(int fd, uint32_t bo, int hasMadvise); +void vc4_bo_label(int fd, uint32_t bo, const char* name); + +#if defined (__cplusplus) +} +#endif diff --git a/driver/modeset.c b/driver/modeset.c index 1638106..7fa21c7 100644 --- a/driver/modeset.c +++ b/driver/modeset.c @@ -49,13 +49,11 @@ //static struct modeset_dev *modeset_list = NULL; -static int fd = -1; - -static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn, +static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, struct modeset_dev *dev); -static int modeset_create_fb(struct modeset_buf *buf); -static void modeset_destroy_fb(struct modeset_buf *buf); -static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, +static int modeset_create_fb(int fd, struct modeset_buf *buf); +static void modeset_destroy_fb(int fd, struct modeset_buf *buf); +static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, struct modeset_dev *dev); @@ -84,27 +82,7 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, * nvidia, intel, etc. specific code, we depend on DUMB_BUFFERs here. */ -int modeset_open(const char *node) -{ - uint64_t has_dumb; - - fd = open(node, O_RDWR); - if (fd < 0) { - printf("cannot open '%s': %m\n", node); - return -1; - } - - if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) { - printf("drm device '%s' does not support dumb buffers\n", node); - close(fd); - fd = -1; - return -1; - } - - return 0; -} - -modeset_dev* modeset_create() +modeset_dev* modeset_create(int fd) { modeset_dev* ret_dev = 0; drmModeRes *res; @@ -112,6 +90,12 @@ modeset_dev* modeset_create() struct modeset_dev *dev; int ret; + uint64_t has_dumb; + if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0 || !has_dumb) { + printf("drm device does not support dumb buffers\n"); + return 0; + } + // retrieve resources res = drmModeGetResources(fd); if (!res) { @@ -134,7 +118,7 @@ modeset_dev* modeset_create() dev->conn = conn->connector_id; // call helper function to prepare this connector - ret = modeset_setup_dev(res, conn, dev); + ret = modeset_setup_dev(fd, res, conn, dev); if (ret) { if (ret != -ENOENT) { errno = -ret; @@ -177,7 +161,7 @@ modeset_dev* modeset_create() * modeset_create_fb() can use them without requiring a pointer to modeset_dev. */ -static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, +static int modeset_setup_dev(int fd, drmModeRes *res, drmModeConnector *conn, struct modeset_dev *dev) { int ret; @@ -206,7 +190,7 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, conn->connector_id, dev->bufs[0].width, dev->bufs[0].height); // find a crtc for this connector - ret = modeset_find_crtc(res, conn, dev); + ret = modeset_find_crtc(fd, res, conn, dev); if (ret) { printf("no valid crtc for connector %u\n", conn->connector_id); @@ -214,7 +198,7 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, } // create framebuffer #1 for this CRTC - ret = modeset_create_fb(&dev->bufs[0]); + ret = modeset_create_fb(fd, &dev->bufs[0]); if (ret) { printf("cannot create framebuffer for connector %u\n", conn->connector_id); @@ -222,11 +206,11 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, } // create framebuffer #2 for this CRTC - ret = modeset_create_fb(&dev->bufs[1]); + ret = modeset_create_fb(fd, &dev->bufs[1]); if (ret) { printf("cannot create framebuffer for connector %u\n", conn->connector_id); - modeset_destroy_fb(&dev->bufs[0]); + modeset_destroy_fb(fd, &dev->bufs[0]); return ret; } @@ -237,7 +221,7 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn, * modeset_find_crtc() stays the same. */ -static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn, +static int modeset_find_crtc(int fd, drmModeRes *res, drmModeConnector *conn, modeset_dev *dev) { drmModeEncoder *enc; @@ -321,7 +305,7 @@ static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn, * modeset_setup_dev() so we can use them here. */ -static int modeset_create_fb(struct modeset_buf *buf) +static int modeset_create_fb(int fd, struct modeset_buf *buf) { struct drm_mode_create_dumb creq; struct drm_mode_destroy_dumb dreq; @@ -401,7 +385,7 @@ static int modeset_create_fb(struct modeset_buf *buf) * We simply unmap the buffer, remove the drm-FB and destroy the memory buffer. */ -static void modeset_destroy_fb(struct modeset_buf *buf) +static void modeset_destroy_fb(int fd, struct modeset_buf *buf) { struct drm_mode_destroy_dumb dreq; @@ -451,7 +435,7 @@ static void modeset_destroy_fb(struct modeset_buf *buf) * vertical-sync. */ -void modeset_swapbuffer(modeset_dev* dev, unsigned index) +void modeset_swapbuffer(int fd, modeset_dev* dev, unsigned index) { //TODO use index!! @@ -477,7 +461,7 @@ void modeset_swapbuffer(modeset_dev* dev, unsigned index) * modeset_destroy_fb() instead of accessing the framebuffers directly. */ -void modeset_destroy(modeset_dev* dev) +void modeset_destroy(int fd, modeset_dev* dev) { struct modeset_dev *iter; @@ -498,19 +482,14 @@ void modeset_destroy(modeset_dev* dev) drmModeFreeCrtc(iter->saved_crtc); // destroy framebuffers - modeset_destroy_fb(&iter->bufs[1]); - modeset_destroy_fb(&iter->bufs[0]); + modeset_destroy_fb(fd, &iter->bufs[1]); + modeset_destroy_fb(fd, &iter->bufs[0]); // free allocated memory free(iter); } } -void modeset_close() -{ - close(fd); -} - /* * This was a very short extension to the basic modesetting example that shows * how double-buffering is implemented. Double-buffering is the de-facto diff --git a/driver/modeset.h b/driver/modeset.h index 0732059..65c24a1 100644 --- a/driver/modeset.h +++ b/driver/modeset.h @@ -39,11 +39,9 @@ typedef struct modeset_dev { drmModeCrtc *saved_crtc; } modeset_dev; -int modeset_open(const char* node); -modeset_dev* modeset_create(); -void modeset_swapbuffer(modeset_dev* dev, unsigned index); -void modeset_destroy(modeset_dev* dev); -void modeset_close(); +modeset_dev* modeset_create(int fd); +void modeset_swapbuffer(int fd, modeset_dev* dev, unsigned index); +void modeset_destroy(int fd, modeset_dev* dev); #if defined (__cplusplus) }