vkcpp
play

VKCPP Markus Tavenrath Senior Developer Technology Engineer - PowerPoint PPT Presentation

April 4-7, 2016 | Silicon Valley VKCPP Markus Tavenrath Senior Developer Technology Engineer mtavenrath@nvidia.com 4/4/2016 INTRODUCTION Who am I? Senior Dev Tech Software Engineer - Professional Visualization Joined NVIDIA 8 years ago to


  1. April 4-7, 2016 | Silicon Valley VKCPP Markus Tavenrath Senior Developer Technology Engineer mtavenrath@nvidia.com 4/4/2016

  2. INTRODUCTION Who am I? Senior Dev Tech Software Engineer - Professional Visualization Joined NVIDIA 8 years ago to work on middleware Goal: Make GPU programming easy and efficient Working with CAD ISVs to optimizing their graphics pipelines Working with driver team on Vulkan and OpenGL performance 2

  3. INTRODUCTION What is Vulkan? Clean, modern and consistent C-API without cruft Low CPU overhead Scales well with multiple threads Provides ‚ low level ‘ control over GPU Moves a lot of responsibility from driver to developer Developer essentialy writes part of the driver 4/4/2016 3

  4. HELLO VULKAN Simple HelloVulkan is ~750 lines of code So much to do, hard to start Easy to make errors Even harder to find those errors Is there a way to simplify Vulkan usage? Two projects started VKCPP (low level C++ API) NVK* (high level C++ API) 4/4/2016 4

  5. VKCPP http://github.com/nvpro-pipeline/vkcpp VKCPP is a port of the Vulkan API for C++11 Simplifies logic where possible without changing concepts/behaviour Generated from the official Vulkan spec file, vk.xml Header only with inline functions to minimize additional cost Open source project contains generated header and generator 4/4/2016 5

  6. VKCPP GOALS Reduce code size & risk of errors Initialization ‚ vertical ‘ VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pNext = NULL ; appInfo.pApplicationName = appName; -> reduced clearness due to #lines on screen appInfo.applicationVersion = 1; appInfo.pEngineName = engineName; appInfo.engineVersion = 1; appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 5); VkInstanceCreateInfo instInfo = {}; Potential issues instInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; instInfo.pNext = NULL ; instInfo.flags = 0; Struct/sType enums mismatch instInfo.pApplicationInfo = &appInfo; instInfo.enabledLayerCount = layerNames. size (); instInfo.ppEnabledLayerNames = layerNames. data () No type safety for enums and flags instInfo.enabledExtensionCount = extensionNames. size (); instInfo.ppEnabledExtensionNames = extensionNames. data (); VkResult res = vkCreateInstance(&instInfo, NULL , &info.inst); Risk of uninitialized fields assert (res == VK_SUCCESS); 6

  7. VULKAN NAMESPACE // Strip Vk prefix of all functions and structs VkResult vkCreateInstance(const VkInstanceCreateInfo* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkInstance* pInstance); avoid symbol collisions // Introduce new vk namespace for all vkcpp symbols namespace vk { Result createInstance(const InstanceCreateInfo* pCreateInfo, const AllocationCallbacks* pAllocator, Instance* pInstance); }; 7

  8. TYPE SAFETY Enums namespace vk { // Use scoped enums for type safety enum class ImageType { Strip VK_ prefix + enum name e1D = VK_IMAGE_TYPE_1D, e2D = VK_IMAGE_TYPE_2D, Use upper camel case of enum type as name e3D = VK_IMAGE_TYPE_3D }; } ‘e‘ + name prefix is required only for numbers, used everywhere for consistency reasons 8

  9. TYPE SAFETY Flags // Introduce class for typesafe flags template <typename BitType, typename MaskType = VkFlags> class Flags { ... }; // BitType is scoped enum enum class QueueFlagBits { eGraphics = VK_QUEUE_GRAPHICS_BIT, eCompute = VK_QUEUE_COMPUTE_BIT, eTransfer = VK_QUEUE_TRANSFER_BIT, eSparseBinding = VK_QUEUE_SPARSE_BINDING_BIT }; // Define typesafe flags typedef Flags<QueueFlagBits, VkQueueFlags> QueueFlags; 4/4/2016 9

  10. TYPE SAFETY Flags template <typename BitType, typename MaskType = VkFlags> class Flags { public: Flags(); // No flags set. Use QueueFlags() or {} as value Flags(BitType bit); // QueueFlags qf(QueueFlagBits::eGraphics) Flags<BitType> & operator|=(Flags<BitType> const& rhs); // qf |= QueueFlagBits::eCompute; Flags<BitType> & operator&=(Flags<BitType> const& rhs); // qf &= QueueFlagBits::eGraphics; Flags<BitType> & operator^=(Flags<BitType> const& rhs); // qf ^= QueueFlagBits::eGraphics; Flags<BitType> operator|(Flags<BitType> const& rhs) const; // qf = QueueFlagBits::eCompute | QueueFlagBits::eGraphics Flags<BitType> operator&(Flags<BitType> const& rhs) const; // qf = qf & QueueFlagBits::eGraphics Flags<BitType> operator^(Flags<BitType> const& rhs) const; // qf = qf ^ QueueFlagBits::eGraphics explicit operator bool() const; // if (qf) Is any bit set? bool operator!() const; // if (!qf) Is no bit set? bool operator==(Flags<BitType> const& rhs) const; // if (qt == QueueFlagBits::eCompute) bool operator!=(Flags<BitType> const& rhs) const; // if (qt != QueueFlagBits::eCompute) explicit operator MaskType() const; // VkFlags flags = static_cast<VkFlags>(qf); }; 10

  11. INITIALIZATION CreateInfos and Structs class EventCreateInfo { public: // All constructors initialize sType/pNext EventCreateInfo(); // Initialize all fields with default values (0 currently) EventCreateInfo(EventCreateFlags flags); // Create with all parameters specified EventCreateInfo(VkEventCreateInfo const & rhs); // Construct from native Vulkan type // get parameter object const EventCreateFlags& flags() const; EventCreateFlags& flags(); // get parameter from non-cost object // set parameter EventCreateInfo& flags(EventCreateFlags flags); ... operator const VkEventCreateInfo&() const; // cast operator to native vulkan type 4/4/2016 11 };

  12. RESULTS CODE SIZE & TYPE SAFETY VkApplicationInfo appInfo = {}; appInfo.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO; appInfo.pNext = NULL ; appInfo.pApplicationName = appName; appInfo.applicationVersion = 1; appInfo.pEngineName = engineName; appInfo.engineVersion = 1; vk::ApplicationInfo appInfo(appName, 1, appInfo.apiVersion = VK_MAKE_VERSION(1, 0, 5); engineName, 1, VK_MAKE_VERSION(1,0,5)); VkInstanceCreateInfo i = {}; vk::InstanceCreateInfo i({}, &appInfo, i.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; layerNames. size (), layerNames. data (), i.pNext = NULL ; extNames. size (), extNames. data ()); i.flags = 0; vk::Instance instance; i.pApplicationInfo = &appInfo; vk::Result res = vk::createInstance(&i, nullptr, &instance); i.enabledLayerCount = layerNames. size (); assert (res == vk::Result::eSuccess); i.ppEnabledLayerNames = layerNames. data () i.enabledExtensionCount = extNames. size (); i.ppEnabledExtensionNames = extNames. data (); VkInstance instance; VkResult res = vkCreateInstance(&i, NULL , &instance); 12 assert (res == VK_SUCCESS);

  13. RESULTS CODE SIZE & TYPE SAFETY std::vector<std::string>? Bad idea vk::ApplicationInfo appInfo(appName, 1, vk::InstanceCreateInfo i({}, &appInfo, engineName, 1, {“ layer_xyz ”} , VK_MAKE_VERSION(1,0,5)); extNames. size (), extNames. data ()); vk::InstanceCreateInfo i({}, &appInfo, Lifetime of struct != Lifetime of temporary layerNames. size (), layerNames. data (), extNames. size (), extNames. data ()); Temporary array will be destroyed after vk::Instance instance; constructor vk::Result res = vk::createInstance(&i, nullptr, &instance); assert (res == vk::Result::eSuccess); CreateInfos would have to copy data 4/4/2016 13

  14. DESIGNATED INITIALIZER LIST VkApplicationInfo appInfo = vk::ApplicationInfo appInfo = vk::ApplicationInfo() { .pApplicationName(appName) .sType = VK_STRUCTURE_TYPE_APPLICATION_INFO, .applicationVersion(1) .pNext = NULL , .pEngineName(engineName) .pApplicationName = appName, .engineVersion(1) .applicationVersion = 1, .apiVersion(VK_MAKE_VERSION(1,0,5)); .pEngineName = engineName, .engineVersion = 1, .apiVersion = VK_MAKE_VERSION(1,0,5) Names explicit, but no guarantee to set all fields }; Designated initializer list not part of C++11 4/4/2016 14

  15. C++ CODING STYLE HANDLES class CommandBuffer VkCommandBuffer cmd = ... { VkRect2D scissor; // conversion from/to native handle scissor.offset.x = 0; CommandBuffer(VkCommandBuffer commandBuffer); scissor.offset.y = 0; CommandBuffer& operator=(VkCommandBuffer scissor.extent.width = width; commandBuffer); scissor.extent.height = height; operator VkCommandBuffer() const; vkCmdSetScissor(cmd, 0, 1, &scissor); // boolean tests if handle is valid explicit operator bool() const; Convert C-Style OO bool operator!() const; to C++ Style OO // functions void setScissor(uint32_t firstScissor, uint32_t scissorCount, const Rect2D* pScissors) const; }; vk::CommandBuffer cmd; cmd .setScissor(0, 1, &scissor); 4/4/2016 15

  16. C++ CODING STYLE TEMPORARY STRUCTS AND EXCEPTIONS class Device { Result createFence(const FenceCreateInfo * createInfo, AllocationCallbacks const * allocator, Fence * fence) const; }; Change from pointer to reference allows passing temporaries class Device { Fence createFence(const FenceCreateInfo & createInfo, Optional<AllocationCallbacks const> const & allocator) const; }; 4/4/2016 16

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend