1
0
mirror of https://github.com/Yours3lf/rpi-vk-driver.git synced 2025-01-30 22:52:14 +01:00

added surface creator extension

This commit is contained in:
Unknown 2018-05-07 16:13:39 +01:00
parent c28f79e87a
commit 1e73f44f50
6 changed files with 293 additions and 107 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
CMakeLists.txt.user
build-debug

View File

@ -15,6 +15,9 @@
#include <drm/vc4_drm.h>
#include <vulkan/vulkan.h>
#include "vkExt.h"
#include "modeset.h"
#ifndef min
#define min(a, b) (a < b ? a : b)
@ -56,8 +59,39 @@ typedef struct VkPhysicalDevice_T
int dummy;
} _physicalDevice;
typedef struct VkDevice_T
{
int dummy;
} _device;
typedef struct VkQueue_T
{
int familyIndex;
} _queue;
VkQueueFamilyProperties _queueFamilyProperties[] =
{
{
//TODO maybe sparse textures later?
.queueFlags = VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT,
.queueCount = 1,
.timestampValidBits = 32, //TODO dunno, 32 for now
.minImageTransferGranularity = {1, 1, 1}
}
};
const int numQueueFamilies = sizeof(_queueFamilyProperties)/sizeof(VkQueueFamilyProperties);
_queue _queuesByFamily[][1] =
{
{
{
.familyIndex = 0
}
}
};
/*
* https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#vkCreateInstance
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateInstance
* There is no global state in Vulkan and all per-application state is stored in a VkInstance object. Creating a VkInstance object initializes the Vulkan library
* vkCreateInstance verifies that the requested layers exist. If not, vkCreateInstance will return VK_ERROR_LAYER_NOT_PRESENT. Next vkCreateInstance verifies that
* the requested extensions are supported (e.g. in the implementation or in any enabled instance layer) and if any requested extension is not supported,
@ -70,6 +104,7 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
VkInstance* pInstance)
{
*pInstance = malloc(sizeof(_instance));
assert(pInstance);
//TODO: allocator is ignored for now
assert(pAllocator == 0);
@ -79,12 +114,14 @@ VKAPI_ATTR VkResult VKAPI_CALL vkCreateInstance(
//TODO: need to check here that the requested
//extensions are supported
//eg.
//VK_KHR_surface
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#devsandqueues-physical-device-enumeration
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#devsandqueues-physical-device-enumeration
* If pPhysicalDevices is NULL, then the number of physical devices available is returned in pPhysicalDeviceCount. Otherwise, pPhysicalDeviceCount must point to a
* variable set by the user to the number of elements in the pPhysicalDevices array, and on return the variable is overwritten with the number of handles actually
* written to pPhysicalDevices. If pPhysicalDeviceCount is less than the number of physical devices available, at most pPhysicalDeviceCount structures will be written.
@ -96,6 +133,8 @@ VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
uint32_t* pPhysicalDeviceCount,
VkPhysicalDevice* pPhysicalDevices)
{
assert(instance);
//TODO is there a way to check if there's a gpu (and it's the rPi)?
int gpuExists = access( "/dev/dri/card0", F_OK ) != -1;
@ -114,7 +153,9 @@ VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
for(int c = 0; c < elementsWritten; ++c)
{
//TODO no allocator, we probably shouldn't allocate
pPhysicalDevices[c] = malloc(sizeof(_physicalDevice));
assert(pPhysicalDevices[c]);
}
*pPhysicalDeviceCount = elementsWritten;
@ -130,15 +171,191 @@ VKAPI_ATTR VkResult VKAPI_CALL vkEnumeratePhysicalDevices(
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.0/html/vkspec.html#vkGetPhysicalDeviceQueueFamilyProperties
*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceQueueFamilyProperties
* If pQueueFamilyProperties is NULL, then the number of queue families available is returned in pQueueFamilyPropertyCount.
* Otherwise, pQueueFamilyPropertyCount must point to a variable set by the user to the number of elements in the pQueueFamilyProperties array,
* and on return the variable is overwritten with the number of structures actually written to pQueueFamilyProperties. If pQueueFamilyPropertyCount
* is less than the number of queue families available, at most pQueueFamilyPropertyCount structures will be written.
*/
VKAPI_ATTR void VKAPI_CALL vkGetPhysicalDeviceQueueFamilyProperties(
VkPhysicalDevice physicalDevice,
uint32_t* pQueueFamilyPropertyCount,
VkQueueFamilyProperties* pQueueFamilyProperties)
{
assert(physicalDevice);
assert(pQueueFamilyPropertyCount);
if(!pQueueFamilyProperties)
{
*pQueueFamilyPropertyCount = 1;
return;
}
int arraySize = *pQueueFamilyPropertyCount;
int elementsWritten = min(numQueueFamilies, arraySize);
for(int c = 0; c < elementsWritten; ++c)
{
pQueueFamilyProperties[c] = _queueFamilyProperties[c];
}
*pQueueFamilyPropertyCount = elementsWritten;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfaceSupportKHR
* does this queue family support presentation to this surface?
*/
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
VkSurfaceKHR surface,
VkBool32* pSupported)
{
assert(pSupported);
assert(surface);
assert(physicalDevice);
assert(queueFamilyIndex < numQueueFamilies);
*pSupported = VK_TRUE; //TODO suuure for now, but we should verify if queue supports presenting to surface
return VK_SUCCESS;
}
/*
* Implementation of our RPI specific "extension"
*/
VkResult vkCreateRpiSurfaceKHR(
VkInstance instance,
const VkRpiSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface)
{
assert(pSurface);
//TODO: allocator is ignored for now
assert(pAllocator == 0);
int ret = modeset_open("/dev/dri/card0"); assert(!ret);
*pSurface = (VkSurfaceKHR)modeset_create();
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkDestroySurfaceKHR
* Destroying a VkSurfaceKHR merely severs the connection between Vulkan and the native surface,
* and does not imply destroying the native surface, closing a window, or similar behavior
* (but we'll do so anyways...)
*/
VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(
VkInstance instance,
VkSurfaceKHR surface,
const VkAllocationCallbacks* pAllocator)
{
assert(instance);
assert(surface);
//TODO: allocator is ignored for now
assert(pAllocator == 0);
modeset_destroy((modeset_dev*)surface);
modeset_close();
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateDevice
* vkCreateDevice verifies that extensions and features requested in the ppEnabledExtensionNames and pEnabledFeatures
* members of pCreateInfo, respectively, are supported by the implementation. If any requested extension is not supported,
* vkCreateDevice must return VK_ERROR_EXTENSION_NOT_PRESENT. If any requested feature is not supported, vkCreateDevice must return
* VK_ERROR_FEATURE_NOT_PRESENT. Support for extensions can be checked before creating a device by querying vkEnumerateDeviceExtensionProperties
* After verifying and enabling the extensions the VkDevice object is created and returned to the application.
* If a requested extension is only supported by a layer, both the layer and the extension need to be specified at vkCreateInstance
* time for the creation to succeed. Multiple logical devices can be created from the same physical device. Logical device creation may
* fail due to lack of device-specific resources (in addition to the other errors). If that occurs, vkCreateDevice will return VK_ERROR_TOO_MANY_OBJECTS.
*/
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice)
{
assert(physicalDevice);
assert(pDevice);
//TODO verify extensions, features
//TODO: allocator is ignored for now
assert(pAllocator == 0);
*pDevice = malloc(sizeof(_device));
if(!pDevice)
{
return VK_ERROR_TOO_MANY_OBJECTS;
}
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetDeviceQueue
* vkGetDeviceQueue must only be used to get queues that were created with the flags parameter of VkDeviceQueueCreateInfo set to zero.
* To get queues that were created with a non-zero flags parameter use vkGetDeviceQueue2.
*/
VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
VkDevice device,
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue)
{
assert(device);
assert(pQueue);
assert(queueFamilyIndex < numQueueFamilies);
assert(queueIndex < _queueFamilyProperties[queueFamilyIndex].queueCount);
*pQueue = &_queuesByFamily[queueFamilyIndex][queueIndex];
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkCreateSemaphore
* Semaphores are a synchronization primitive that can be used to insert a dependency between batches submitted to queues.
* Semaphores have two states - signaled and unsignaled. The state of a semaphore can be signaled after execution of a batch of commands is completed.
* A batch can wait for a semaphore to become signaled before it begins execution, and the semaphore is also unsignaled before the batch begins execution.
* As with most objects in Vulkan, semaphores are an interface to internal data which is typically opaque to applications.
* This internal data is referred to as a semaphores payload. However, in order to enable communication with agents outside of the current device,
* it is necessary to be able to export that payload to a commonly understood format, and subsequently import from that format as well.
* The internal data of a semaphore may include a reference to any resources and pending work associated with signal or unsignal operations performed on that semaphore object.
* Mechanisms to import and export that internal data to and from semaphores are provided below.
* These mechanisms indirectly enable applications to share semaphore state between two or more semaphores and other synchronization primitives across process and API boundaries.
* When created, the semaphore is in the unsignaled state.
*/
VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(
VkDevice device,
const VkSemaphoreCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSemaphore* pSemaphore)
{
assert(device);
assert(pSemaphore);
//TODO: allocator is ignored for now
assert(pAllocator == 0);
//we'll probably just use an IOCTL to wait for a GPU sequence number to complete.
*pSemaphore = -1;
return VK_SUCCESS;
}
/*
* https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#vkGetPhysicalDeviceSurfaceCapabilitiesKHR
*/
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
{
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL vkDeviceWaitIdle(
@ -187,14 +404,6 @@ VKAPI_ATTR void VKAPI_CALL vkDestroyDevice(
}
VKAPI_ATTR void VKAPI_CALL vkDestroySurfaceKHR(
VkInstance instance,
VkSurfaceKHR surface,
const VkAllocationCallbacks* pAllocator)
{
}
VKAPI_ATTR void VKAPI_CALL vkDestroyInstance(
VkInstance instance,
const VkAllocationCallbacks* pAllocator)
@ -320,63 +529,3 @@ VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceFormatsKHR(
{
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
VkPhysicalDevice physicalDevice,
VkSurfaceKHR surface,
VkSurfaceCapabilitiesKHR* pSurfaceCapabilities)
{
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL vkCreateSemaphore(
VkDevice device,
const VkSemaphoreCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSemaphore* pSemaphore)
{
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue2(
VkDevice device,
const VkDeviceQueueInfo2* pQueueInfo,
VkQueue* pQueue)
{
}
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDevice(
VkPhysicalDevice physicalDevice,
const VkDeviceCreateInfo* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkDevice* pDevice)
{
return VK_SUCCESS;
}
VKAPI_ATTR VkResult VKAPI_CALL vkGetPhysicalDeviceSurfaceSupportKHR(
VkPhysicalDevice physicalDevice,
uint32_t queueFamilyIndex,
VkSurfaceKHR surface,
VkBool32* pSupported)
{
return VK_SUCCESS;
}
VKAPI_ATTR void VKAPI_CALL vkGetDeviceQueue(
VkDevice device,
uint32_t queueFamilyIndex,
uint32_t queueIndex,
VkQueue* pQueue)
{
}

View File

@ -69,11 +69,10 @@ struct modeset_dev {
drmModeCrtc *saved_crtc;
};
static struct modeset_dev *modeset_list = NULL;
//static struct modeset_dev *modeset_list = NULL;
static int fd = -1;
static int modeset_prepare();
static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev);
static int modeset_create_fb(struct modeset_buf *buf);
@ -124,15 +123,12 @@ int modeset_open(const char *node)
return -1;
}
return modeset_prepare();
return 0;
}
/*
* modeset_prepare() stays the same.
*/
static int modeset_prepare()
modeset_dev* modeset_create()
{
modeset_dev* ret_dev = 0;
drmModeRes *res;
drmModeConnector *conn;
struct modeset_dev *dev;
@ -142,7 +138,7 @@ static int modeset_prepare()
res = drmModeGetResources(fd);
if (!res) {
printf("cannot retrieve DRM resources (%d): %m\n", errno);
return -1;
return 0;
}
// iterate all connectors
@ -173,8 +169,8 @@ static int modeset_prepare()
// free connector data and link device into global list
drmModeFreeConnector(conn);
dev->next = modeset_list;
modeset_list = dev;
dev->next = ret_dev;
ret_dev = dev;
}
// free resources again
@ -182,7 +178,7 @@ static int modeset_prepare()
struct modeset_dev *iter;
struct modeset_buf *buf;
for (iter = modeset_list; iter; iter = iter->next) {
for (iter = ret_dev; iter; iter = iter->next) {
iter->saved_crtc = drmModeGetCrtc(fd, iter->crtc);
buf = &iter->bufs[iter->front_buf];
ret = drmModeSetCrtc(fd, iter->crtc, buf->fb, 0, 0,
@ -191,7 +187,8 @@ static int modeset_prepare()
printf("cannot set CRTC for connector %u (%d): %m\n",
iter->conn, errno);
}
return 0;
return ret_dev;
}
/*
@ -263,7 +260,7 @@ static int modeset_setup_dev(drmModeRes *res, drmModeConnector *conn,
*/
static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn,
struct modeset_dev *dev)
modeset_dev *dev)
{
drmModeEncoder *enc;
unsigned int i, j;
@ -279,7 +276,7 @@ static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn,
if (enc) {
if (enc->crtc_id) {
crtc = enc->crtc_id;
for (iter = modeset_list; iter; iter = iter->next) {
for (iter = dev; iter; iter = iter->next) {
if (iter->crtc == crtc) {
crtc = -1;
break;
@ -316,7 +313,7 @@ static int modeset_find_crtc(drmModeRes *res, drmModeConnector *conn,
// check that no other device already uses this CRTC
crtc = res->crtcs[j];
for (iter = modeset_list; iter; iter = iter->next) {
for (iter = dev; iter; iter = iter->next) {
if (iter->crtc == crtc) {
crtc = -1;
break;
@ -476,13 +473,13 @@ static void modeset_destroy_fb(struct modeset_buf *buf)
* vertical-sync.
*/
void modeset_swapbuffer()
void modeset_swapbuffer(modeset_dev* dev)
{
struct modeset_dev *iter;
struct modeset_buf *buf;
int ret;
for (iter = modeset_list; iter; iter = iter->next) {
for (iter = dev; iter; iter = iter->next) {
buf = &iter->bufs[iter->front_buf ^ 1];
ret = drmModeSetCrtc(fd, iter->crtc, buf->fb, 0, 0,
@ -500,14 +497,14 @@ void modeset_swapbuffer()
* modeset_destroy_fb() instead of accessing the framebuffers directly.
*/
void modeset_cleanup()
void modeset_destroy(modeset_dev* dev)
{
struct modeset_dev *iter;
while (modeset_list) {
while (dev) {
// remove from global list
iter = modeset_list;
modeset_list = iter->next;
iter = dev;
dev = iter->next;
// restore saved CRTC configuration
drmModeSetCrtc(fd,
@ -527,7 +524,10 @@ void modeset_cleanup()
// free allocated memory
free(iter);
}
}
void modeset_close()
{
close(fd);
}

View File

@ -17,9 +17,13 @@ extern "C" {
#include <xf86drm.h>
#include <xf86drmMode.h>
int modeset_open(const char *node);
void modeset_swapbuffer();
void modeset_cleanup();
typedef struct modeset_dev modeset_dev;
int modeset_open(const char* node);
modeset_dev* modeset_create();
void modeset_swapbuffer(modeset_dev* dev);
void modeset_destroy(modeset_dev* dev);
void modeset_close();
#if defined (__cplusplus)
}

32
driver/vkExt.h Normal file
View File

@ -0,0 +1,32 @@
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
//we need something like the other platforms to create surfaces on the RPI
//so I created this little "extension"
//full spec in this file ;)
typedef enum VkRpiSurfaceCreateFlagsKHR {
//reserved
VK_RPI_FLAG_BITS_MAX_ENUM = 0x7FFFFFFF
} VkRpiSurfaceCreateFlagsKHR;
typedef struct VkRpiSurfaceCreateInfoKHR {
VkStructureType sType;
const void* pNext;
VkRpiSurfaceCreateFlagsKHR flags;
//maybe include some other stuff dunno
} VkRpiSurfaceCreateInfoKHR;
VkResult vkCreateRpiSurfaceKHR(
VkInstance instance,
const VkRpiSurfaceCreateInfoKHR* pCreateInfo,
const VkAllocationCallbacks* pAllocator,
VkSurfaceKHR* pSurface);
#ifdef __cplusplus
}
#endif

View File

@ -5,7 +5,7 @@
#include <vulkan/vulkan.h>
#include "driver/modeset.h"
#include "driver/vkExt.h"
//#define GLFW_INCLUDE_VULKAN
//#define VK_USE_PLATFORM_WIN32_KHR
@ -165,12 +165,12 @@ void createInstance() {
}
void createWindowSurface() {
//if (glfwCreateWindowSurface(instance, window, NULL, &windowSurface) != VK_SUCCESS) {
// std::cerr << "failed to create window surface!" << std::endl;
// assert(0);
//}
if (vkCreateRpiSurfaceKHR(instance, 0, 0, &windowSurface) != VK_SUCCESS) {
std::cerr << "failed to create window surface!" << std::endl;
assert(0);
}
//std::cout << "created window surface" << std::endl;
std::cout << "created window surface" << std::endl;
}
void findPhysicalDevice() {
@ -670,17 +670,16 @@ int main() {
//window = glfwCreateWindow(640, 480, "The 630 line cornflower blue window", nullptr, nullptr);
int ret = 0;
ret = modeset_open("/dev/dri/card0"); assert(!ret);
modeset_swapbuffer();
//TODO create surface
//swapbuffer
// Use Vulkan
setupVulkan();
mainLoop();
//TODO destroy surface
cleanup();
modeset_cleanup();
return 0;
}