Ashes (C++)

Description

Ashes est un remplacement "drop-in" de Vulkan.
Elle permet d'écrire du code Vulkan, et de sélectionner l'API de rendu qui sera utilisée.

C'est toujours un travail en cours, la bibliothèque est loin d'être complète !!

Pour la générer, vous pouvez utiliser CMake.

Renderers disponibles

  • Vulkan: Ici Ashes est un passe plat, et n'a aucun coût supplémentaire si le dynamic loader est utilisé.
  • OpenGL 4.X
  • Direct3D 11.

Comment l'utiliser

Deux modes sont disponibles:
  • Mode automatique

    Vous chargez la shared library Ashes au lieu de celle de Vulkan, et c'est terminé.
    La sélection de l'API de rendu sera faite au premier appel à vkGetInstanceProcAddr (pour le dynamic loader), ou au premier appel d'un API Vulkan (pour le static loader).
    Dans ce mode, le seul changement que vous havez à faire, est de changer le nom du fichier de la shared library (ashes.so.1/ashes-1.dll au lieu de libvulkan.so.1/vulkan-1.dll).
  • Mode manuel

    Vous pouvez demander la liste des plugins chargés, via un appel à la fonction int ashEnumeratePlugins( uint32_t * count , AshPluginDescription * plugins );.
    Elle fonctionne comme les fonctions de Vulkan : si plugins est mis à NULL, count contiendra alors le nombre de plug-ins chargés.

API de Ashes

Les API suivants sont disponibles, dans ashes.h:
typedef struct AshPluginFeatures
{
	// Whether or not the plugin supports buffer ranges.
	VkBool32 hasBufferRange;
	// Whether or not the plugin supports image textures.
	VkBool32 hasImageTexture;
	// Whether or not the plugin supports vertex base instance.
	VkBool32 hasBaseInstance;
	// Whether or not the plugin supports clearing of single images.
	VkBool32 hasClearTexImage;
	// Whether or not the plugin supports compute shaders.
	VkBool32 hasComputeShaders;
	// Whether or not the plugin supports shader storage buffers.
	VkBool32 hasStorageBuffers;
} AshPluginFeatures;

typedef struct AshPluginSupport
{
	// The plugin's priority (from 1 (low) to 10 (high)).
	uint32_t priority;
	// Whether or not the plugin is supported.
	VkBool32 supported;
} AshPluginSupport;

typedef struct AshPluginDescription
{
	//The plugin's short name.
	char name[16];
	//The plugin's description.
	char description[64];
	//The plugin's main entry point.
	PFN_vkGetInstanceProcAddr getInstanceProcAddr;
	//The plugin's supported features.
	AshPluginFeatures features;
	//The plugin's static functions (for static loader support).
	AshPluginStaticFunction functions;
	//The plugin's support informations.
	AshPluginSupport support;
} AshPluginDescription;

// Enumerates the available rendering APIs.
typedef void( VKAPI_PTR * PFN_ashEnumeratePluginsDescriptions )( uint32_t *, AshPluginDescription * );
Ashes_API void VKAPI_PTR ashEnumeratePluginsDescriptions( uint32_t * count
	, AshPluginDescription * pDescriptions );

// Defines the active rendering API.
typedef VkResult( VKAPI_PTR * PFN_ashSelectPlugin )( AshPluginDescription );
Ashes_API VkResult VKAPI_PTR ashSelectPlugin( AshPluginDescription description );

// Retrieves the active rendering API informations.
typedef VkResult( VKAPI_PTR * PFN_ashGetPluginDescription )( AshPluginDescription * );
Ashes_API VkResult VKAPI_PTR ashGetCurrentPluginDescription( AshPluginDescription * description );

A partir de ces API, vous pouvez récupérer les plug-ins de rendu, vérifier leurs capacités, activer celui que vous vouler utiliser...

Example

Voici un petit exemple pour choisir l'API de rendu depuis un paramètre donné en option de ligne de commande :
#define ASHES_VK_PROTOTYPES
#include <ashes/ashes.h>

AshPluginDescription * enumeratePlugins( uint32_t * pluginsCount )
{
	AshPluginDescription * result = NULL;
	ashEnumeratePluginsDescriptions( pluginsCount, NULL );

	if ( *pluginsCount )
	{
		result = malloc( ( *pluginsCount ) * sizeof( AshPluginDescription ) );
		ashEnumeratePluginsDescriptions( pluginsCount, result );
	}

	return result;
}

int selectPlugin( AshPluginDescription * plugins, uint32_t pluginsCount, char * option )
{
	int selectedPlugin = -1;

	if ( pluginsCount > 0 )
	{
		char name[17];

		for ( uint32_t i = 0; i < pluginsCount && selectedPlugin == -1; ++i )
		{
			strncpy( name, "-", 16 );
			strncat( name, plugins[i].name, 16 );

			if ( strncmp( option, name, 16 ) == 0 )
			{
				selectedPlugin = i;
				ashSelectPlugin( plugins[selectedPlugin] );
			}
		}
	}

	return selectedPlugin;
}

int main( int argc, char ** argv )
{
	uint32_t pluginsCount = 0u;
	int selectedPlugin = -1;
	AshPluginDescription * plugins = enumeratePlugins( &pluginsCount );

	for ( int i = 1; i < argc && selectedPlugin == -1; ++i )
	{
		selectedPlugin = selectPlugin( plugins, pluginsCount, argv[i] );
	}

	// Now write classic Vulkan code.
	// ...
	//
}

Sources

Vous pouvez retrouver Ashes sur GitHub, et elle est aussi disponible sur vcpkg



Image Large