Vulkan Cookbook - Pawel Lapinski - E-Book

Vulkan Cookbook E-Book

Pawel Lapinski

0,0
39,59 €

-100%
Sammeln Sie Punkte in unserem Gutscheinprogramm und kaufen Sie E-Books und Hörbücher mit bis zu 100% Rabatt.

Mehr erfahren.
Beschreibung

Vulkan is the next generation graphics API released by the Khronos group. It is expected to be the successor to OpenGL and OpenGL ES, which it shares some similarities with such as its cross-platform capabilities, programmed pipeline stages, or nomenclature. Vulkan is a low-level API that gives developers much more control over the hardware, but also adds new responsibilities such as explicit memory and resources management. With it, though, Vulkan is expected to be much faster.
This book is your guide to understanding Vulkan through a series of recipes. We start off by teaching you how to create instances in Vulkan and choose the device on which operations will be performed. You will then explore more complex topics such as command buffers, resources and memory management, pipelines, GLSL shaders, render passes, and more. Gradually, the book moves on to teach you advanced rendering techniques, how to draw 3D scenes, and how to improve the performance of your applications.
By the end of the book, you will be familiar with the latest advanced techniques implemented with the Vulkan API, which can be used on a wide range of platforms.

Das E-Book können Sie in Legimi-Apps oder einer beliebigen App lesen, die das folgende Format unterstützen:

EPUB

Seitenzahl: 806

Veröffentlichungsjahr: 2017

Bewertungen
0,0
0
0
0
0
0
Mehr Informationen
Mehr Informationen
Legimi prüft nicht, ob Rezensionen von Nutzern stammen, die den betreffenden Titel tatsächlich gekauft oder gelesen/gehört haben. Wir entfernen aber gefälschte Rezensionen.



Title Page

Vulkan Cookbook
Work through recipes to unlock the full potential of the next generation graphics API—Vulkan
Pawel Lapinski

BIRMINGHAM - MUMBAI

Copyright

Vulkan Cookbook

Copyright © 2017 Packt Publishing

All rights reserved. No part of this book may be reproduced, stored in a retrieval system, or transmitted in any form or by any means, without the prior written permission of the publisher, except in the case of brief quotations embedded in critical articles or reviews.

Every effort has been made in the preparation of this book to ensure the accuracy of the information presented. However, the information contained in this book is sold without warranty, either express or implied. Neither the author, nor Packt Publishing, and its dealers and distributors will be held liable for any damages caused or alleged to be caused directly or indirectly by this book.

Packt Publishing has endeavored to provide trademark information about all of the companies and products mentioned in this book by the appropriate use of capitals. However, Packt Publishing cannot guarantee the accuracy of this information.

First published: April 2017

Production reference: 1260417

Published by Packt Publishing Ltd.
Livery Place
35 Livery Street
Birmingham
B3 2PB, UK.

ISBN 978-1-78646-815-4

www.packtpub.com

Credits

AuthorPawel Lapinski

Copy EditorSafis Editing

ReviewerChris Forbes

Project CoordinatorRitika Manoj

CommissioningEditorAshwin Nair

ProofreaderSafis Editing

AcquisitionEditorNitin Dasan

IndexerTejal Daruwale Soni

Content Development EditorAditi Gour

Production CoordinatorArvindkumar Gupta

Technical EditorMurtaza Tinwala

GraphicsJason Monteiro

About the Author

Pawel Lapinski is a graphics software engineer at Intel Corporation. His professional career started 10 years ago when he and his friends were hired to develop a 3D training/simulation application using C++, OpenGL, and Cg, which was later improved with added head-mounted display support and stereoscopic image generation.

Since his studies, Pawel has been interested in 3D graphics and especially in the open multiplatform OpenGL library. He wrote a diploma about the “Effective usage of vertex and fragment shaders.” Since then, he has continued to pursue opportunities to work with 3D graphics and expand his knowledge in the field. He had the opportunity to join a team that was developing one of the biggest CAVE‑like installations at the Polish Gdansk University of Technology. His responsibility was to prepare 3D visualizations using Unity3D engine and add stereoscopic image generation and support for motion tracking.

Pawel's whole career has involved working with computer graphics, the OpenGL library, and shaders. However, some time ago, already as a programmer at Intel, he had the opportunity to start working with the Vulkan API when he prepared validation tests for the Vulkan graphics driver. He also prepared a series of tutorials teaching people how to use Vulkan and now he wants to share more of his knowledge in the form of a Vulkan Cookbook.

Acknowledgments

This is my first published book and it is a very important moment of my life. That’s why I’d like to include quite many people in this “special thanks” list.

First and foremost, I want to thank my wife, Agata, my children, and the whole family for all their love, patience, and continuous support.

I wouldn’t have written this book if Mr. Jacek Kuffel hadn't been my language teacher in my primary school. He taught me how important our language is and he also taught me how to express myself with written words. I learned all my love of writing from him.

My affection for 3D graphics programming started during my studies. It started growing thanks to my thesis supervisor Mariusz Szwoch, Ph.D., and my 3D graphics teacher Jacek Lebiedz, Ph.D. I’d like to thank them for their support and help. Without them I would not have started learning OpenGL and, as the next step, the Vulkan API.

Kind regards and a huge thank you to my team here at Intel Poland. I couldn’t have joined a better team or started working with better people. They are not only specialists at what they do, but they are all kind, sincere and warmhearted friends. I’d like to thank them for patiently answering my many questions, for sharing their knowledge. And for the great atmosphere that they create every day. Special thanks are required to Slawek, Boguslaw, Adam, Jacek, and to my manager Jan.

And last but not least – the Packt team. I’ve always dreamt about writing a book and they not only allowed me to do it, but they helped me realize my dreams, showing their support at every step from the very beginning. Aditi, Murtaza, Nitin, Sachin – You are great. It was much easier to write this book with you on my side.

About the Reviewer

Chris Forbes works as a software developer for Google, working on Vulkan validation support and other ecosystem components. Previously he has been involved in implementing OpenGL 3 and 4 support in open source graphics drivers for Linux [www.mesa3d.org], as well as rebuilding classic strategy games to run on modern systems [www.openra.net]. He also served as a technical reviewer on Packt's previous Vulkan title, Learning Vulkan.

www.PacktPub.com

For support files and downloads related to your book, please visit www.PacktPub.com.

Did you know that Packt offers eBook versions of every book published, with PDF and ePub files available? You can upgrade to the eBook version at www.PacktPub.com and as a print book customer, you are entitled to a discount on the eBook copy. Get in touch with us at [email protected] for more details.

At www.PacktPub.com, you can also read a collection of free technical articles, sign up for a range of free newsletters and receive exclusive discounts and offers on Packt books and eBooks.

h t t p s ://w w w . p a c k t p u b . c o m /m a p t

Get the most in-demand software skills with Mapt. Mapt gives you full access to all Packt books and video courses, as well as industry-leading tools to help you plan your personal development and advance your career.

Why subscribe?

Fully searchable across every book published by Packt

Copy and paste, print, and bookmark content

On demand and accessible via a web browser

Customer Feedback

Thanks for purchasing this Packt book. At Packt, quality is at the heart of our editorial process. To help us improve, please leave us an honest review on this book's Amazon page at h t t p s ://w w w . a m a z o n . c o m /V u l k a n - C o o k b o o k - P a w e l - L a p i n s k i /d p /1786468158.

If you'd like to join our team of regular reviewers, you can e-mail us at [email protected]. We award our regular reviewers with free eBooks and videos in exchange for their valuable feedback. Help us be relentless in improving our products!

Table of Contents

Preface

What this book covers

What you need for this book

Who this book is for

Sections

Getting ready

How to do it…

How it works—

There's more—

See also

Conventions

Reader feedback

Customer support

Downloading the example code

Downloading the color images of this book

Errata

Piracy

Questions

Instance and Devices

Introduction

Downloading Vulkan's SDK

Getting ready

How to do it...

How it works...

See also

Enabling validation layers

How to do it...

How it works...

See also

Connecting with a Vulkan Loader library

How to do it...

How it works...

See also

Preparing for loading Vulkan API functions

How to do it...

How it works...

See also

Loading functions exported from a Vulkan Loader library

How to do it...

How it works...

See also

Loading global-level functions

How to do it...

How it works...

See also

Checking available Instance extensions

How to do it...

How it works...

See also

Creating a Vulkan Instance

How to do it...

How it works...

See also

Loading instance-level functions

How to do it...

How it works...

See also

Enumerating available physical devices

How to do it...

How it works...

See also

Checking available device extensions

How to do it...

How it works...

See also

Getting features and properties of a physical device

How to do it...

How it works...

See also

Checking available queue families and their properties

How to do it...

How it works...

See also

Selecting the index of a queue family with the desired capabilities

How to do it...

How it works...

See also

Creating a logical device

Getting ready

How to do it...

How it works...

See also

Loading device-level functions

How to do it...

How it works...

See also

Getting a device queue

How to do it...

How it works...

See also

Creating a logical device with geometry shaders, graphics, and compute queues

How to do it...

How it works...

See also

Destroying a logical device

How to do it...

How it works...

See also

Destroying a Vulkan Instance

How to do it...

How it works...

See also

Releasing a Vulkan Loader library

How to do it...

How it works...

See also

Image Presentation

Introduction

Creating a Vulkan Instance with WSI extensions enabled

How to do it...

How it works...

See also

Creating a presentation surface

Getting ready

How to do it...

How it works...

See also

Selecting a queue family that supports presentation to a given surface

How to do it...

How it works...

See also

Creating a logical device with WSI extensions enabled

How to do it...

How it works...

See also

Selecting a desired presentation mode

How to do it...

How it works...

See also

Getting the capabilities of a presentation surface

How to do it...

How it works...

See also

Selecting a number of swapchain images

How to do it...

How it works...

See also

Choosing a size of swapchain images

How to do it...

How it works...

See also

Selecting desired usage scenarios of swapchain images

How to do it...

How it works...

See also

Selecting a transformation of swapchain images

How to do it...

How it works...

See also

Selecting a format of swapchain images

Getting ready

How to do it...

How it works...

See also

Creating a swapchain

How to do it...

How it works...

See also

Getting handles of swapchain images

How to do it...

How it works...

See also

Creating a swapchain with R8G8B8A8 format and a mailbox present mode

How to do it...

How it works...

See also

Acquiring a swapchain image

Getting ready

How to do it...

How it works...

See also

Presenting an image

Getting ready

How to do it...

How it works...

See also

Destroying a swapchain

How to do it...

How it works...

See also

Destroying a presentation surface

How to do it...

How it works...

See also

Command Buffers and Synchronization

Introduction

Creating a command pool

How to do it...

How it works...

See also

Allocating command buffers

How to do it...

How it works...

See also

Beginning a command buffer recording operation

How to do it...

How it works...

See also

Ending a command buffer recording operation

How to do it...

How it works...

See also

Resetting a command buffer

How to do it...

How it works...

See also

Resetting a command pool

How to do it...

How it works...

See also

Creating a semaphore

How to do it...

How it works...

See also

Creating a fence

How to do it...

How it works...

See also

Waiting for fences

How to do it...

How it works...

See also

Resetting fences

How to do it...

How it works...

See also

Submitting command buffers to a queue

Getting ready

How to do it...

How it works...

See also

Synchronizing two command buffers

Getting ready

How to do it...

How it works...

See also

Checking if processing of a submitted command buffer has finished

How to do it...

How it works...

See also

Waiting until all commands submitted to a queue are finished

How to do it...

How it works...

See also

Waiting for all submitted commands to be finished

How to do it...

How it works...

See also

Destroying a fence

How to do it...

How it works...

See also

Destroying a semaphore

How to do it...

How it works...

See also

Freeing command buffers

How to do it...

How it works...

See also

Destroying a command pool

How to do it...

How it works...

See also

Resources and Memory

Introduction

Creating a buffer

How to do it...

How it works...

See also

Allocating and binding a memory object for a buffer

How to do it...

How it works...

There's more...

See also

Setting a buffer memory barrier

Getting ready

How to do it...

How it works...

There's more...

See also

Creating a buffer view

How to do it...

How it works...

See also

Creating an image

How to do it...

How it works...

See also

Allocating and binding a memory object to an image

How to do it...

How it works...

There's more...

See also

Setting an image memory barrier

Getting ready

How to do it...

How it works...

See also

Creating an image view

How to do it...

How it works...

See also

Creating a 2D image and view

How to do it...

How it works...

See also

Creating a layered 2D image with a CUBEMAP view

How to do it...

How it works...

See also

Mapping, updating and unmapping host-visible memory

How to do it...

How it works...

See also

Copying data between buffers

How to do it...

How it works...

See also

Copying data from a buffer to an image

How to do it...

How it works...

See also

Copying data from an image to a buffer

How to do it...

How it works...

See also

Using a staging buffer to update a buffer with a device-local memory bound

How to do it...

How it works...

See also

Using a staging buffer to update an image with a device-local memory bound

How to do it...

How it works...

See also

Destroying an image view

How to do it...

How it works...

See also

Destroying an image

How to do it...

How it works...

See also

Destroying a buffer view

How to do it...

How it works...

See also

Freeing a memory object

How to do it...

How it works...

See also

Destroying a buffer

How to do it...

How it works...

See also

Descriptor Sets

Introduction

Creating a sampler

How to do it...

How it works...

See also

Creating a sampled image

How to do it...

How it works...

See also

Creating a combined image sampler

How to do it...

How it works...

See also

Creating a storage image

How to do it...

How it works...

See also

Creating a uniform texel buffer

How to do it...

How it works...

See also

Creating a storage texel buffer

How to do it...

How it works...

See also

Creating a uniform buffer

How to do it...

How it works...

See also

Creating a storage buffer

How to do it...

How it works...

See also

Creating an input attachment

How to do it...

How it works...

See also

Creating a descriptor set layout

How to do it...

How it works...

See also

Creating a descriptor pool

How to do it...

How it works...

See also

Allocating descriptor sets

How to do it...

How it works...

See also

Updating descriptor sets

Getting ready

How to do it...

How it works...

See also

Binding descriptor sets

How to do it...

How it works...

See also

Creating descriptors with a texture and a uniform buffer

How to do it...

How it works...

See also

Freeing descriptor sets

How to do it...

How it works...

See also

Resetting a descriptor pool

How to do it...

How it works...

See also

Destroying a descriptor pool

How to do it...

How it works...

See also

Destroying a descriptor set layout

How to do it...

How it works...

See also

Destroying a sampler

How to do it...

How it works...

See also

Render Passes and Framebuffers

Introduction

Specifying attachments descriptions

How to do it...

How it works...

See also

Specifying subpass descriptions

Getting ready

How to do it...

How it works...

See also

Specifying dependencies between subpasses

How to do it...

How it works...

See also

Creating a render pass

Getting ready

How to do it...

How it works...

See also

Creating a framebuffer

How to do it...

How it works...

See also

Preparing a render pass for geometry rendering and postprocess subpasses

Getting ready

How to do it...

How it works...

See also

Preparing a render pass and a framebuffer with color and depth attachments

Getting ready

How to do it...

How it works...

See also

Beginning a render pass

How to do it...

How it works...

See also

Progressing to the next subpass

How to do it...

How it works...

See also

Ending a render pass

How to do it...

How it works...

See also

Destroying a framebuffer

How to do it...

How it works...

See also

Destroying a render pass

How to do it...

How it works...

See also

Shaders

Introduction

Converting GLSL shaders to SPIR-V assemblies

How to do it...

How it works...

See also

Writing vertex shaders

How to do it...

How it works...

See also

Writing tessellation control shaders

How to do it...

How it works...

See also

Writing tessellation evaluation shaders

How to do it...

How it works...

See also

Writing geometry shaders

How to do it...

How it works...

See also

Writing fragment shaders

How to do it...

How it works...

See also

Writing compute shaders

How to do it...

How it works...

See also

Writing a vertex shader that multiplies vertex position by a projection matrix

How to do it...

How it works...

See also

Using push constants in shaders

How to do it...

How it works...

See also

Writing texturing vertex and fragment shaders

How to do it...

How it works...

See also

Displaying polygon normals with a geometry shader

How to do it...

How it works...

See also

Graphics and Compute Pipelines

Introduction

Creating a shader module

How to do it...

How it works...

See also

Specifying pipeline shader stages

Getting ready

How to do it...

How it works...

See also

Specifying a pipeline vertex binding description, attribute description, and input state

How to do it...

How it works...

See also

Specifying a pipeline input assembly state

How to do it...

How it works...

See also

Specifying a pipeline tessellation state

How to do it...

How it works...

See also

Specifying a pipeline viewport and scissor test state

Getting ready

How to do it...

How it works...

See also

Specifying a pipeline rasterization state

How to do it...

How it works...

See also

Specifying a pipeline multisample state

How to do it...

How it works...

See also

Specifying a pipeline depth and stencil state

How to do it...

How it works...

See also

Specifying a pipeline blend state

How to do it...

How it works...

See also

Specifying pipeline dynamic states

How to do it...

How it works...

See also

Creating a pipeline layout

How to do it...

How it works...

See also

Specifying graphics pipeline creation parameters

How to do it...

How it works...

See also

Creating a pipeline cache object

How to do it...

How it works...

See also

Retrieving data from a pipeline cache

How to do it...

How it works...

See also

Merging multiple pipeline cache objects

How to do it...

How it works...

See also

Creating a graphics pipeline

How to do it...

How it works...

See also

Creating a compute pipeline

How to do it...

How it works...

See also

Binding a pipeline object

How to do it...

How it works...

See also

Creating a pipeline layout with a combined image sampler, a buffer, and push constant ranges

How to do it...

How it works...

See also

Creating a graphics pipeline with vertex and fragment shaders, depth test enabled, and with dynamic viewport and scissor tests

How to do it...

How it works...

See also

Creating multiple graphics pipelines on multiple threads

Getting ready

How to do it...

How it works...

See also

Destroying a pipeline

How to do it...

How it works...

See also

Destroying a pipeline cache

How to do it...

How it works...

See also

Destroying a pipeline layout

How to do it...

How it works...

See also

Destroying a shader module

How to do it...

How it works...

See also

Command Recording and Drawing

Introduction

Clearing a color image

How to do it...

How it works...

See also

Clearing a depth-stencil image

How to do it...

How it works...

See also

Clearing render pass attachments

How to do it...

How it works...

See also

Binding vertex buffers

Getting ready

How to do it...

How it works...

See also

Binding an index buffer

How to do it...

How it works...

See also

Providing data to shaders through push constants

How to do it...

How it works...

See also

Setting viewport states dynamically

How to do it...

How it works...

See also

Setting scissor states dynamically

How to do it...

How it works...

See also

Setting line width states dynamically

How to do it...

How it works...

See also

Setting depth bias states dynamically

How to do it...

How it works...

See also

Setting blend constants states dynamically

How to do it...

How it works...

See also

Drawing a geometry

How to do it...

How it works...

See also

Drawing an indexed geometry

How to do it...

How it works...

See also

Dispatching compute work

How to do it...

How it works...

See also

Executing a secondary command buffer inside a primary command buffer

How to do it...

How it works...

See also

Recording a command buffer that draws a geometry with dynamic viewport and scissor states

Getting ready

How to do it...

How it works...

See also

Recording command buffers on multiple threads

Getting ready

How to do it...

How it works...

See also

Preparing a single frame of animation

How to do it...

How it works...

See also

Increasing the performance through increasing the number of separately rendered frames

Getting ready

How to do it...

How it works...

See also

Helper Recipes

Introduction

Preparing a translation matrix

How to do it...

How it works...

See also

Preparing a rotation matrix

How to do it...

How it works...

See also

Preparing a scaling matrix

How to do it...

How it works...

See also

Preparing a perspective projection matrix

How to do it...

How it works...

See also

Preparing an orthographic projection matrix

How to do it...

How it works...

See also

Loading texture data from a file

Getting ready

How to do it...

How it works...

See also

Loading a 3D model from an OBJ file

Getting ready

How to do it...

How it works...

See also

Lighting

Introduction

Rendering a geometry with a vertex diffuse lighting

Getting ready

How to do it...

How it works...

See also

Rendering a geometry with a fragment specular lighting

Getting ready

How to do it...

How it works...

See also

Rendering a normal mapped geometry

Getting ready

How to do it...

How it works...

See also

Drawing a reflective and refractive geometry using cubemaps

Getting ready

How to do it...

How it works...

See also

Adding shadows to the scene

Getting ready

How to do it...

How it works...

See also

Advanced Rendering Techniques

Introduction

Drawing a skybox

Getting ready

How to do it...

How it works...

See also

Drawing billboards using geometry shaders

How to do it...

How it works...

See also

Drawing particles using compute and graphics pipelines

How to do it...

How it works...

See also

Rendering a tessellated terrain

Getting ready

How to do it...

How it works...

See also

Rendering a full-screen quad for post-processing

How to do it...

How it works...

See also

Using input attachments for a color correction post-process effect

How to do it...

How it works...

See also

Preface

Computer graphics have a very long and interesting history. Many APIs or custom approaches to the generation of 2D or 3D images have come and gone. A landmark in this history was the invention of OpenGL, one of the first graphics libraries, which allowed us to create real‑time, high-performance 3D graphics, and which was available for everyone on multiple operating systems. It is still developed and widely used even today. And this year we can celebrate its 25th birthday!

But many things have changed since OpenGL was created. The graphics hardware industry is evolving very quickly. And recently, to accommodate these changes, a new approach to 3D graphics rendering was presented. It took the form of a low‑level access to the graphics hardware. OpenGL was designed as a high-level API, which allows users to easily render images on screen. But this high‑level approach, convenient for users, is difficult for graphics drivers to handle. This is one of the main reasons for restricting the hardware to show its full potential. The new approach tries to overcome these struggles–it gives users much more control over the hardware, but also many more responsibilities. This way application developers can release the full potential of the graphics hardware, because the drivers no longer block them. Low‑level access allows drivers to be much smaller, much thinner. But these benefits come at the expense of much more work that needs to done by the developers.

The first evangelist of the new approach to graphics rendering was a Mantle API designed by AMD. When it proved that low‑level access can give considerable performance benefits, other companies started working on their own graphics libraries. One of the most notable representatives of the new trend were Metal API, designed by Apple, and DirectX 12, developed by Microsoft.

But all of the above libraries were developed with specific operating systems and/or hardware in mind. There was no open and multiplatform standard such as OpenGL. Until last year. Year 2016 saw the release of the Vulkan API, developed by Khronos consortium, which maintains the OpenGL library. Vulkan also represents the new approach, a low‑level access to the graphics hardware, but unlike the other libraries it is available for everyone on multiple operating systems and hardware platforms–from high‑performance desktop computers with Windows or Linux operating systems, to mobile devices with Android OS. And as it is still being very new, there are few resources teaching developers how to use it. This book tries to fill this gap.

What this book covers

Chapter 1, Instance and Devices, shows how to get started with the Vulkan API. This chapter explains where to download the Vulkan SDK from, how to connect with the Vulkan Loader library, how to select the physical device on which operations will be performed, and how to prepare and create a logical device.

Chapter 2, Image Presentation, describes how to display Vulkan‑generated images on screen. It explains what a swapchain is and what parameters are required to create it, so we can use it for rendering and see the results of our work.

Chapter 3, Command Buffers and Synchronization, is about recording various operations into command buffers and submitting them to queues, where they are processed by the hardware. Also, various synchronization mechanisms are presented in this chapter.

Chapter 4, Resources and Memory, presents two basic and most important resource types, images and buffers, which allow us to store data. We explain how to create them, how to prepare memory for these resources, and, also, how to upload data to them from our application (CPU).

Chapter 5, Descriptor Sets, explains how to provide created resource to shaders. We explain how to prepare resources so they can be used inside shaders and how to set up descriptor sets, which form the interface between the application and the shaders.

Chapter 6, Render Passes and Framebuffers, shows how to organize drawing operations into sets of separate steps called subpasses, which are organized into render passes. In this chapter we also show how to prepare descriptions of attachments (render targets) used during drawing and how to create framebuffers, which bind specific resources according to these descriptions.

Chapter 7, Shaders, describes the specifics of programming all available graphics and compute shader stages. This chapter presents how to implement shader programs using GLSL programming language and how to convert them into SPIR‑V assemblies – the only form core Vulkan API accepts.

Chapter 8, Graphics and Compute Pipelines, presents the process of creating two available pipeline types. They are used to set up all the parameters graphics hardware needs to properly process drawing commands or computational work.

Chapter 9, Command Recording and Drawing, is about recording all the operations needed to successfully draw 3D models or dispatch computational work. Also, various optimization techniques are presented in this chapter, which can help increase the performance of the application.

Chapter 10, Helper Recipes, shows convenient set of tools no 3D rendering application can do without. It is shown how to load textures and 3D models from files and how to manipulate the geometry inside shaders.

Chapter 11, Lighting, presents commonly used lighting techniques from simple diffuse and specular lighting calculations to normal mapping and shadow mapping techniques.

Chapter 12, Advanced Rendering Techniques, explains how to implement impressive graphics techniques, which can be found in many popular 3D applications such as games and benchmarks.

What you need for this book

This book explains various aspects of the Vulkan graphics API, which is open and multiplatform. It is available on Microsoft Windows (version 7 and newer) or Linux (preferably Ubuntu 16.04 or newer) systems. (Vulkan is also supported on Android devices with the 7.0+ / Nougat version of the operating system, but the code samples available with this book weren’t designed to be executed on the Android OS.)

To execute sample programs or to develop our own applications, apart from Windows 7+ or Linux operating systems, graphics hardware and drivers that support Vulkan API are also required. Refer to 3D graphics vendors’ sites and/or support to check which hardware is capable of running Vulkan‑enabled software.

When using the Windows operating system, code samples can be compiled using the Visual Studio Community 2015 IDE (or newer), which is free and available for everyone. To generate a solution for the Visual Studio IDE the CMAKE 3.0 or newer is required.

On Linux systems, compilation is performed using a combination of the CMAKE 3.0 and the make tool. But the samples can also be compiled using other tools such as QtCreator.

Who this book is for

This book is ideal for developers who know C/C++ languages, have some basic familiarity with graphics programming, and now want to take advantage of the new Vulkan API in the process of building next generation computer graphics. Some basic familiarity with Vulkan would be useful to follow the recipes. OpenGL developers who want to take advantage of the Vulkan API will also find this book useful.

Sections

In this book, you will find several headings that appear frequently (Getting ready, How to do it, How it works, There's more, and See also).

To give clear instructions on how to complete a recipe, we use these sections as follows:

Getting ready

This section tells you what to expect in the recipe, and describes how to set up any software or any preliminary settings required for the recipe.

How to do it…

This section contains the steps required to follow the recipe.

How it works…

This section usually consists of a detailed explanation of what happened in the previous section.

There's more…

This section consists of additional information about the recipe in order to make the reader more knowledgeable about the recipe.

See also

This section provides helpful links to other useful information for the recipe.

Reader feedback

Feedback from our readers is always welcome. Let us know what you think about this book-what you liked or disliked. Reader feedback is important for us as it helps us develop titles that you will really get the most out of.

To send us general feedback, simply e-mail [email protected], and mention the book's title in the subject of your message.

If there is a topic that you have expertise in and you are interested in either writing or contributing to a book, see our author guide at www.packtpub.com/authors .

Customer support

Now that you are the proud owner of a Packt book, we have a number of things to help you to get the most from your purchase.

Downloading the example code

You can download the example code files for this book from your account at h t t p ://w w w . p a c k t p u b . c o m. If you purchased this book elsewhere, you can visit h t t p ://w w w . p a c k t p u b . c o m /s u p p o r t and register to have the files e-mailed directly to you.

You can download the code files by following these steps:

Log in or register to our website using your e-mail address and password.

Hover the mouse pointer on the

SUPPORT

tab at the top.

Click on

Code Downloads & Errata

.

Enter the name of the book in the

Search

box.

Select the book for which you're looking to download the code files.

Choose from the drop-down menu where you purchased this book from.

Click on

Code Download

.

You can also download the code files by clicking on the Code Files button on the book's webpage at the Packt Publishing website. This page can be accessed by entering the book's name in the Search box. Please note that you need to be logged in to your Packt account.

Once the file is downloaded, please make sure that you unzip or extract the folder using the latest version of:

WinRAR / 7-Zip for Windows

Zipeg / iZip / UnRarX for Mac

7-Zip / PeaZip for Linux

The code bundle for the book is also hosted on GitHub at h t t p s ://g i t h u b . c o m /P a c k t P u b l i s h i n g /V u l k a n - C o o k b o o k . We also have other code bundles from our rich catalog of books and videos available at h t t p s ://g i t h u b . c o m /P a c k t P u b l i s h i n g /. Check them out!

Downloading the color images of this book

We also provide you with a PDF file that has color images of the screenshots/diagrams used in this book. The color images will help you better understand the changes in the output. You can download this file from h t t p s ://w w w . p a c k t p u b . c o m /s i t e s /d e f a u l t /f i l e s /d o w n l o a d s /V u l k a n C o o k b o o k _ C o l o r I m a g e s . p d f.

Errata

Although we have taken every care to ensure the accuracy of our content, mistakes do happen. If you find a mistake in one of our books-maybe a mistake in the text or the code-we would be grateful if you could report this to us. By doing so, you can save other readers from frustration and help us improve subsequent versions of this book. If you find any errata, please report them by visiting h t t p ://w w w . p a c k t p u b . c o m /s u b m i t - e r r a t a , selecting your book, clicking on the Errata Submission Form link, and entering the details of your errata. Once your errata are verified, your submission will be accepted and the errata will be uploaded to our website or added to any list of existing errata under the Errata section of that title.

To view the previously submitted errata, go to h t t p s ://w w w . p a c k t p u b . c o m /b o o k s /c o n t e n t /s u p p o r tand enter the name of the book in the search field. The required information will appear under the Errata section.

Piracy

Piracy of copyrighted material on the Internet is an ongoing problem across all media. At Packt, we take the protection of our copyright and licenses very seriously. If you come across any illegal copies of our works in any form on the Internet, please provide us with the location address or website name immediately so that we can pursue a remedy.

Please contact us at [email protected] with a link to the suspected pirated material.

We appreciate your help in protecting our authors and our ability to bring you valuable content.

Questions

If you have a problem with any aspect of this book, you can contact us at [email protected], and we will do our best to address the problem.

Instance and Devices

In this chapter, we will cover the following recipes:

Downloading Vulkan SDK

Enabling validation layers

Connecting with a Vulkan Loader library

Preparing for loading Vulkan API functions

Loading function exported from a Vulkan Loader library

Loading global-level functions

Checking available Instance extensions

Creating a Vulkan Instance

Loading instance-level functions

Enumerating available physical devices

Checking available device extensions

Getting features and properties of a physical device

Checking available queue families and their properties

Selecting the index of a queue family with the desired capabilities

Creating a logical device

Loading device-level functions

Getting a device queue

Creating a logical device with geometry shaders and graphics and compute queues

Destroying a logical device

Destroying a Vulkan Instance

Releasing a Vulkan Loader library

Introduction

Vulkan is a new graphics API developed by the Khronos Consortium. It is perceived as a successor to the OpenGL: it is open source and cross-platform. However, as it is possible to use Vulkan on different types of devices and operating systems, there are some differences in the basic setup code we need to create in order to use Vulkan in our application.

In this chapter, we will cover topics that are specific to using Vulkan on Microsoft Windows and Ubuntu Linux operating systems. We will learn Vulkan basics such as downloading the Software Development Kit (SDK) and setting validation layers, which enable us to debug the applications that use the Vulkan API. We will start using the Vulkan Loader library, load all the Vulkan API functions, create a Vulkan Instance, and select the device our work will be executed on.

Downloading Vulkan's SDK

To start developing applications using the Vulkan API, we need to download a SDK and use some of its resources in our application.

Vulkan's SDK can be found at https://vulkan.lunarg.com.

Getting ready

Before we can execute any application that uses the Vulkan API, we also need to install a graphics drivers that supports the Vulkan API. These can be found on a graphics hardware vendor's site.

How to do it...

On the Windows operating system family:

Go to

https://vulkan.lunarg.com

.

Scroll to the bottom of the page and choose

WINDOWS

operating system.

Download and save the SDK installer file.

Run the installer and select the destination at which you want to install the SDK. By default, it is installed to a

C:\VulkanSDK\<version>\

folder.

When the installation is finished, open the folder in which the Vulkan SDK was installed and then open the

RunTimeInstaller

sub-folder. Execute

VulkanRT-<version>-Installer

file. This will install the latest version of the Vulkan Loader.

Once again, go to the folder in which the SDK was installed and open the

Include\vulkan

sub-folder. Copy the

vk_platform.h

and

vulkan.h

header files to the project folder of the application you want to develop. We will call these two files

Vulkan header files

.

On the Linux operating system family:

Update system packages by running the following commands:

sudo apt-get update

sudo apt-get dist-upgrade

To be able to build and execute Vulkan samples from the SDK, install additional development packages by running the following command:

sudo apt-get install libglm-dev graphviz libxcb-dri3-0 libxcb-present0 libpciaccess0 cmake libpng-dev libxcb-dri3- dev libx11-dev

Go to

https://vulkan.lunarg.com

.

Scroll to the bottom of the page and choose

LINUX

operating system.

Download the Linux package for the SDK and save it in the desired folder.

Open Terminal and change the current directory to the folder to which the SDK package was downloaded.

Change the access permissions to the downloaded file by executing the following command:

chmod ugo+x vulkansdk-linux-x86_64-<version>.run

Run the downloaded SDK package installer file with the following command:

./vulkansdk-linux-x86_64-<version>.run

Change the current directory to the

VulkanSDK/<version>

folder that was created by the SDK package installer.

Set up environment variables by executing the following command:

sudo su

VULKAN_SDK=$PWD/x86_64

echo export PATH=$PATH:$VULKAN_SDK/bin >> /etc/environment

echo export VK_LAYER_PATH=$VULKAN_SDK/etc/explicit_layer.d >> /etc/environment

echo $VULKAN_SDK/lib >> /etc/ld.so.conf.d/vulkan.conf

ldconfig

Change the current directory to the

x86_64/include/vulkan

folder.

Copy

vk_platform.h

and

vulkan.h

header files to the project folder of the application you want to develop. We will call these two files

Vulkan header files

.

Restart the computer for the changes to take effect.

How it works...

The SDK contains resources needed to create applications using the Vulkan API. Vulkan header files (the vk_platform.h and vulkan.h files) need to be included in the source code of our application so we can use the Vulkan API functions, structures, enumerations, and so on, inside the code.

The Vulkan Loader (vulkan-1.dll file on Windows, libvulkan.so.1 file on Linux systems) is a dynamic library responsible for exposing Vulkan API functions and forwarding them to the graphics driver. We connect with it in our application and load Vulkan API functions from it.

See also

The following recipes in this chapter:

Enabling validation layers

Connecting with a Vulkan Loader library

Releasing a Vulkan Loader library

Enabling validation layers

The Vulkan API was designed with performance in mind. One way to increase its performance is to lower state and error checking performed by the driver. This is one of the reasons Vulkan is called a "thin API" or "thin driver," it is a minimal abstraction of the hardware, which is required for the API to be portable across multiple hardware vendors and device types (high-performance desktop computers, mobile phones, and integrated and low-power embedded systems).

However, this approach makes creating applications with the Vulkan API much more difficult, compared to the traditional high-level APIs such as OpenGL. It's because very little feedback is given to developers by the driver, as it expects that programmers will correctly use the API and abide by rules defined in the Vulkan specification.

To mitigate this problem, Vulkan was also designed to be a layered API. The lowest layer, the core, is the Vulkan API itself, which communicates with the Driver, allowing us to program the Hardware (as seen in the preceding diagram). On top of it (between the Application and the Vulkan API), developers can enable additional layers, to ease the debugging process.

How to do it...

On the Windows operating system family:

Go to the folder in which the SDK was installed and then open the

Config

sub-directory.

Copy the

vk_layer_settings.txt

file into the directory of the executable you want to debug (into a folder of an application you want to execute).

Create an environment variable named

VK_INSTANCE_LAYERS

:

Open the command-line console (Command Prompt/

cmd.exe

).

Type the following:

setx VK_INSTANCE_LAYERS VK_LAYER_LUNARG_standard_validation

3. Close the console.

Re-open the command prompt once again.

Change the current directory to the folder of the application you want to execute.

Run the application; potential warnings or errors will be displayed in the standard output of the command prompt.

On the Linux operating system family:

Go to the folder in which the SDK was installed and then open the

Config

sub-directory.

Copy the

vk_layer_settings.txt

file into the directory of the executable you want to debug (into a folder of an application you want to execute).

Create an environment variable named

VK_INSTANCE_LAYERS

:

Open the Terminal window.

Type the following:

export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_standard_validation

Run the application; potential warnings or errors will be displayed in the standard output of the Terminal window.

How it works...

Vulkan validation layers contain a set of libraries which help find potential problems in created applications. Their debugging capabilities include, but are not limited to, validating parameters passed to Vulkan functions, validating texture and render target formats, tracking Vulkan objects and their lifetime and usage, and checking for potential memory leaks or dumping (displaying/printing) Vulkan API function calls. These functionalities are enabled by different validation layers, but most of them are gathered into a single layer called VK_LAYER_LUNARG_standard_validation which is enabled in this recipe. Examples of names of other layers include VK_LAYER_LUNARG_swapchain, VK_LAYER_LUNARG_object_tracker, VK_LAYER_GOOGLE_threading, or VK_LAYER_LUNARG_api_dump, among others. Multiple layers can be enabled at the same time, in a similar way as presented here in the recipe. Just assign the names of the layers you want to activate to the VK_INSTANCE_LAYERS environment variable. If you are a Windows OS user, remember to separate them with a semicolon, as in the example:

setx VK_INSTANCE_LAYERS VK_LAYER_LUNARG_api_dump;VK_LAYER_LUNARG_core_validation

If you are a Linux OS user, separate them with a colon. Here is an example:

export VK_INSTANCE_LAYERS=VK_LAYER_LUNARG_api_dump:VK_LAYER_LUNARG _core_validation

The environment variable named VK_INSTANCE_LAYERS can be also set with other OS specific ways such as, advanced operating system settings on Windows or /etc/environment on Linux.

The preceding examples enable validation layers globally, for all applications, but they can also be enabled only for our own application, in its source code during Instance creation. However, this approach requires us to recompile the whole program every time we want to enable or disable different layers. So, it is easier to enable them using the preceding recipe. This way, we also won't forget to disable them when we want to ship the final version of our application. To disable validation layers, we just have to delete VK_INSTANCE_LAYERS environment variable.

Validation layers should not be enabled in the released (shipped) version of the applications as they may drastically decrease performance.

For a full list of available validation layers, please refer to the documentation, which can be found in the Documentation sub-folder of the directory in which the Vulkan SDK was installed.

See also

The following recipes in this chapter:

Downloading Vulkan's SDK

Connecting with a Vulkan Loader library

Releasing a Vulkan Loader library

Connecting with a Vulkan Loader library

Support for the Vulkan API is implemented by the graphics-hardware vendor and provided through graphics drivers. Each vendor can implement it in any dynamic library they choose, and can even change it with the driver update.

That's why, along with the drivers, Vulkan Loader is also installed. We can also install it from the folder in which the SDK was installed. It allows developers to access Vulkan API entry points, through a vulkan-1.dll library on Windows OS or libvulkan.so.1 library on Linux OS, no matter what driver, from what vendor, is installed.

Vulkan Loader is responsible for transmitting Vulkan API calls to an appropriate graphics driver. On a given computer, there may be more hardware components that support Vulkan, but with Vulkan Loader, we don't need to wonder which driver we should use, or which library we should connect with to be able to use Vulkan. Developers just need to know the name of a Vulkan library: vulkan-1.dll on Windows or libvulkan.so.1 on Linux. When we want to use Vulkan in our application, we just need to connect with it in our code (load it).

On Windows OS, Vulkan Loader library is called vulkan-1.dll. On Linux OS, Vulkan Loader library is called libvulkan.so.1.

How to do it...

On the Windows operating system family:

Prepare a variable of type

HMODULE

named

vulkan_library

.

Call

LoadLibrary( "vulkan-1.dll" )

and store the result of this operation in a

vulkan_library

variable.

Confirm that this operation has been successful by checking if a value of a

vulkan_library

variable is different than

nullptr

.

On the Linux operating system family:

Prepare a variable of type

void*

named

vulkan_library

.

Call

dlopen( "libvulkan.so.1", RTLD_NOW )

and store the result of this operation in a

vulkan_library

variable.

Confirm that this operation has been successful by checking if a value of a

vulkan_library

variable is different than

nullptr

.

See also

The following recipes in this chapter:

Downloading Vulkan SDK

Enabling validation layers

Releasing a Vulkan Loader library

Preparing for loading Vulkan API functions

When we want to use Vulkan API in our application, we need to acquire procedures specified in the Vulkan documentation. In order to do that, we can add a dependency to the Vulkan Loader library, statically link with it in our project, and use function prototypes defined in the vulkan.h header file. The second approach is to disable the function prototypes defined in the vulkan.h header file and load function pointers dynamically in our application.

The first approach is little bit easier, but it uses functions defined directly in the Vulkan Loader library. When we perform operations on a given device, Vulkan Loader needs to redirect function calls to the proper implementation based on the handle of the device we provide as an argument. This redirection takes some time, and thus impacts performance.

The second option requires more work on the application side, but allows us to skip the preceding redirection (jump) and save some performance. It is performed by loading functions directly from the device we want to use. This way, we can also choose only the subset of Vulkan functions if we don't need them all.

In this book, the second approach is presented, as this gives developers more control over the things that are going in their applications. To dynamically load functions from a Vulkan Loader library, it is convenient to wrap the names of all Vulkan API functions into a set of simple macros and divide declarations, definitions and function loading into multiple files.

How to do it...

Define the

VK_NO_PROTOTYPES

preprocessor definition in the project: do this in the project properties (when using development environments such as Microsoft Visual Studio or Qt Creator), or by using the

#define VK_NO_PROTOTYPES

preprocessor directive just before the

vulkan.h

file is included in the source code of our application.

Create a new file, named

ListOfVulkanFunctions.inl

.

Type the following contents into the file:

#ifndef EXPORTED_VULKAN_FUNCTION #define EXPORTED_VULKAN_FUNCTION( function ) #endif #undef EXPORTED_VULKAN_FUNCTION // #ifndef GLOBAL_LEVEL_VULKAN_FUNCTION #define GLOBAL_LEVEL_VULKAN_FUNCTION( function ) #endif #undef GLOBAL_LEVEL_VULKAN_FUNCTION // #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION #define INSTANCE_LEVEL_VULKAN_FUNCTION( function ) #endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION // #ifndef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, extension ) #endif #undef INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION // #ifndef DEVICE_LEVEL_VULKAN_FUNCTION #define DEVICE_LEVEL_VULKAN_FUNCTION( function ) #endif #undef DEVICE_LEVEL_VULKAN_FUNCTION // #ifndef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( function, extension ) #endif #undef DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION

Create a new header file, named

VulkanFunctions.h

.

Insert the following contents into the file:

#include "vulkan.h" namespace VulkanCookbook { #define EXPORTED_VULKAN_FUNCTION( name ) extern PFN_##name name; #define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION( name ) extern PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) extern PFN_##name name; #include "ListOfVulkanFunctions.inl" } // namespace VulkanCookbook

Create a new file with a source code named

VulkanFunctions.cpp

.

Insert the following contents into the file:

#include "VulkanFunctions.h" namespace VulkanCookbook { #define EXPORTED_VULKAN_FUNCTION( name ) PFN_##name name; #define GLOBAL_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; #define INSTANCE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION( name ) PFN_##name name; #define DEVICE_LEVEL_VULKAN_FUNCTION_FROM_EXTENSION( name, extension ) PFN_##name name; #include "ListOfVulkanFunctions.inl" } // namespace VulkanCookbook

How it works...