Vulkan Abridged
Vulkan Abridged
Mike Bailey
Computer Graphics
                                                               Mike Bailey
                                                           mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
http://cs.oregonstate.edu/~mjb/vulkan
• mjb@cs.oregonstate.edu
                                   http://cs.oregonstate.edu/~mjb/vulkan
                                                                            mjb – July 24, 2020
                                                                                                      5
                                    Sections
 Section titles that have been greyed-out have not been included in the ABRIDGED
  noteset, i.e., the one that has been made to fit in SIGGRAPH’s reduced time slot.
These topics are in the FULL noteset, however, which can be found on the web page:
                        http://cs.oregonstate.edu/~mjb/vulkan
                                                                                      mjb – July 24, 2020
                                                               6
My Favorite Vulkan Reference
Introduction
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
1. Performance
2. Performance
3. Performance
Vulkan is better at keeping the GPU busy than OpenGL is. OpenGL drivers need to do a lot of CPU work
before handing work off to the GPU. Vulkan lets you get more power from the GPU card you already have.
This is especially important if you can hide the complexity of Vulkan from your customer base and just let
them see the improved performance. Thus, Vulkan has had a lot of support and interest from game engine
developers, 3rd party software vendors, etc.
             As an aside, the Vulkan development effort was originally called “glNext”, which
             created the false impression that this was a replacement for OpenGL. It’s not.
The Khronos Group, Inc. is a non-profit member-funded industry consortium, focused on the
creation of open standard, royalty-free application programming interfaces (APIs) for authoring and
accelerated playback of dynamic media on a wide variety of platforms and devices. Khronos
members may contribute to the development of Khronos API specifications, vote at various stages
before public deployment, and accelerate delivery of their platforms and applications through early
access to specification drafts and conformance tests.
• More low-level information must be provided (by you!) in the application, rather than the driver
• All of the things that we have talked about being   deprecated in OpenGL are really
  deprecated in Vulkan: built-in pipeline transformations, begin-vertex*-end, fixed-
  function, etc.
• Shaders are pre-”half-compiled” outside of your application. The compilation process is then
  finished during the runtime pipeline-building process.
• In OpenGL, your “pipeline state” is the combination of whatever your current graphics attributes
  are: color, transformations, textures, shaders, etc.
• Vulkan forces you to set all your state variables at once into a “pipeline state object” (PSO) data
  structure and then invoke the entire PSO at once whenever you want to use that state
  combination
• Potentially, you could have thousands of these pre-prepared pipeline state objects
                                                                                              VkVertexInputAttributeDescription
                     VkPipelineShaderStageCreateInfo
                                                  VkPipelineVertexInputStateCreateInfo
                                                                                                           Topology
     Shader stages                                  VkPipelineInputAssemblyStateCreateInfo
    VertexInput State
                                                                                                                      x, y, w, h,
  InputAssembly State
                                                                                         Viewport                     minDepth,
    Tesselation State                             VkViewportStateCreateInfo
                                                                                                                      maxDepth
     Viewport State
   Rasterization State                                                                   Scissor
                                     VkPipelineRasterizationStateCreateInfo                                        offset
   MultiSample State
   DepthStencil State                                                                                              extent
                                     VkPipelineDepthStencilStateCreateInfo                 cullMode
    ColorBlend State
                                                                                         polygonMode
     Dynamic State
                                                                                           frontFace
     Pipeline layout
                                                                                           lineWidth
      RenderPass
  basePipelineHandle
   basePipelineIndex
                                                                                              depthTestEnable
                                         VkPipelineColorBlendStateCreateInfo                  depthWriteEnable
                                                                                              depthCompareOp
VkGraphicsPipelineCreateInfo                                                                  stencilTestEnable
                                                                                             stencilOpStateFront
                                                                                             stencilOpStateBack
                                             VkPipelineColorBlendAttachmentState
                                                                                                      blendEnable
                                                                                                 srcColorBlendFactor
                                                                                                 dstColorBlendFactor
           vkCreateGraphicsPipeline( )                                                               colorBlendOp
                                                                                                 srcAlphaBlendFactor
                                                                                                 dstAlphaBlendFactor
                                               VkPipelineDynamicStateCreateInfo                      alphaBlendOp
                                                                                                    colorWriteMask
                                  Array naming the states that can be set dynamically                                               mjb – July 24, 2020
                                                                                                                  17
                           Querying the Number of Something
uint32_t count;
result = vkEnumeratePhysicalDevices( Instance, OUT &count, OUT (VkPhysicalDevice *)nullptr );
 This way of querying information is a recurring OpenCL and Vulkan pattern (get used to it):
                                                             How many total        Where to
                                                               there are           put them
VkMemoryRequirements vmr;
VkMemoryAllocateInfo        vmai;
   vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   vmai.pNext = nullptr;
   vmai.flags = 0;
   vmai.allocationSize = vmr.size;
   vmai.memoryTypeIndex = 0;
    https://www.khronos.org/files/vulkan11-reference-guide.pdf
                                                                 mjb – July 24, 2020
             Vulkan Quick Reference Card                                   20
https://www.khronos.org/files/vulkan11-reference-guide.pdf
Application
Instance Instance
                                                                                           Command Buffer
Queue
Queue
Queue
Queue
Queue
Queue
Queue
Queue
                                                                                   Queue
                                                                                           Command Buffer
Command Buffer
Application
Instance
                 Physical
                  Device
                 Logical
                 Device
                              Command Buffer
                    Queue
Command Buffer
Command Buffer
                     Mike Bailey
                 mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
'm', 'M': Toggle display mode (textures vs. colors, for now)
'i', 'I':       Toggle using a vertex buffer only vs. an index buffer
                (in the index buffer version)
2. Everything is in one .cpp file (except the geometry data). It really should be
   broken up, but this way you can find everything easily.
3. At times, I could have hidden complexity, but I didn’t. At all stages, I have tried
   to err on the side of showing you everything, so that nothing happens in a way
   that’s kept a secret from you.
4. I’ve setup Vulkan structs every time they are used, even though, in many cases
   (most?), they could have been setup once and then re-used each time.
5. At times, I’ve setup things that didn’t need to be setup just to show you what
   could go there.
6. There are great uses for C++ classes and methods here to hide some complexity, but
   I’ve not done that.
7. I’ve typedef’ed a couple things to make the Vulkan phraseology more consistent.
8. Even though it is not good software style, I have put persistent information in global
   variables, rather than a separate data structure. I hope it is clearer this way.
9. At times, I have copied lines from vulkan.h into the code as comments to show you
   what certain options could be.
10. I’ve divided functionality up into the pieces that make sense to me. Many other
    divisions are possible. Feel free to invent your own.
     Reset( );
     InitGraphics( );
     vkQueueWaitIdle( Queue );
     vkDeviceWaitIdle( LogicalDevice );
     DestroyAllVulkan( );
     glfwDestroyWindow( MainWindow );
     glfwTerminate( );
     return 0;
}
VK_ZZZ is a constant
My Conventions
“Init” in a function call name means that something is being setup that only needs to be setup
once
In the source code, after main( ) comes InitGraphics( ), then all of the InitxxYYY( ) functions in
numerical order. After that comes the helper functions
“Find” in a function call name means that something is being looked for
“Fill” in a function call name means that some data is being supplied to Vulkan
“IN” and “OUT” ahead of function call arguments are just there to let you know how an
argument is going to be used by the function. Otherwise, IN and OUT have no significance.
They are actually #define’d to nothing.
                                                                                                     mjb – July 24, 2020
                        Your Sample2019.zip File Contains This                                          31
Double-click here to
launch Visual Studio 2019
with this solution
          The “19” refers to the version of Visual Studio, not the year of development.
                                                                                          mjb – July 24, 2020
                    Reporting Error Results, I                                               32
struct errorcode
{
       VkResult     resultCode;
       std::stringmeaning;
}
ErrorCodes[ ] =
{
       { VK_NOT_READY,                        "Not Ready“                 },
       { VK_TIMEOUT,                          "Timeout“                   },
       { VK_EVENT_SET,                        "Event Set“                 },
       { VK_EVENT_RESET,                      "Event Reset“               },
       { VK_INCOMPLETE,                       "Incomplete“                },
       { VK_ERROR_OUT_OF_HOST_MEMORY,         "Out of Host Memory“        },
       { VK_ERROR_OUT_OF_DEVICE_MEMORY,       "Out of Device Memory“      },
       { VK_ERROR_INITIALIZATION_FAILED,      "Initialization Failed“     },
       { VK_ERROR_DEVICE_LOST,                "Device Lost“               },
       { VK_ERROR_MEMORY_MAP_FAILED,          "Memory Map Failed“         },
       { VK_ERROR_LAYER_NOT_PRESENT,          "Layer Not Present“         },
       { VK_ERROR_EXTENSION_NOT_PRESENT,      "Extension Not Present“     },
       { VK_ERROR_FEATURE_NOT_PRESENT,        "Feature Not Present“       },
       { VK_ERROR_INCOMPATIBLE_DRIVER,        "Incompatible Driver“       },
       { VK_ERROR_TOO_MANY_OBJECTS,           "Too Many Objects“          },
       { VK_ERROR_FORMAT_NOT_SUPPORTED,       "Format Not Supported“      },
       { VK_ERROR_FRAGMENTED_POOL,            "Fragmented Pool“           },
       { VK_ERROR_SURFACE_LOST_KHR,           "Surface Lost“              },
       { VK_ERROR_NATIVE_WINDOW_IN_USE_KHR,   "Native Window in Use“      },
       { VK_SUBOPTIMAL_KHR,                   "Suboptimal“                },
       { VK_ERROR_OUT_OF_DATE_KHR,            "Error Out of Date“         },
       { VK_ERROR_INCOMPATIBLE_DISPLAY_KHR,   "Incompatible Display“      },
       { VK_ERROR_VALIDATION_FAILED_EXT,      "Valuidation Failed“        },
       { VK_ERROR_INVALID_SHADER_NV,          "Invalid Shader“            },
       { VK_ERROR_OUT_OF_POOL_MEMORY_KHR,     "Out of Pool Memory“        },
       { VK_ERROR_INVALID_EXTERNAL_HANDLE,    "Invalid External Handle“   },
};
                                                                               mjb – July 24, 2020
                       Reporting Error Results, II                                                 33
void
PrintVkError( VkResult result, std::string prefix )
{
      if (Verbose && result == VK_SUCCESS)
      {
             fprintf(FpDebug, "%s: %s\n", prefix.c_str(), "Successful");
             fflush(FpDebug);
             return;
      }
bool Paused;
bool Verbose;
Drawing
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
V2
      V0             V1
                                                                       V4        V6
                                            V0     V2
   VK_PRIMITIVE_TOPOLOGY_LINE_STRIP   VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
                V3                                      V2
                                       V3
                          V2                                                V1
                     V1                                      V0
      V0                                           V0
                                            V4                    V5                       mjb – July 24, 2020
                                                                       37
             Vulkan Topologies
2 3
6 7
0 1
4       5
                        static GLuint CubeTriangleIndices[ ][3] =
                        {
                                { 0, 2, 3 },
                                { 0, 3, 1 },
                                { 4, 5, 7 },
                                { 4, 7, 6 },
                                { 1, 3, 7 },
                                { 1, 7, 5 },
                                { 0, 4, 6 },
                                { 0, 6, 2 },
                                { 2, 6, 7 },
                                { 2, 7, 3 },
                                { 0, 1, 5 }
                                { 0, 5, 4 }
                        };
                                                                    mjb – July 24, 2020
                       Triangles Represented as an Array of Structures                 39
From the file SampleVertexData.cpp:              2               3
 struct vertex
 {
      glm::vec3        position;                           7
      glm::vec3        normal;
                                        6
      glm::vec3        color;
      glm::vec2        texCoord;
 };
     // vertex #2:
     {
           { -1., 1., -1. },
                                        Modeled in
           { 0., 0., -1. },             right-handed
           { 0., 1., 0. },              coordinates
           { 1., 1. }
     },
     // vertex #3:
     {
           { 1., 1., -1. },
           { 0., 0., -1. },
           { 1., 1., 0. },
           { 0., 1. }
     },
MyBuffer MyVertexDataBuffer;
VkResult
Init05MyVertexDataBuffer( IN VkDeviceSize size, OUT MyBuffer * pMyBuffer )
{
      VkResult result;
      result = Init05DataBuffer( size, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, pMyBuffer );
      return result;
}
VkResult
Init05DataBuffer( VkDeviceSize size, VkBufferUsageFlags usage, OUT MyBuffer * pMyBuffer )
{
     VkResult result = VK_SUCCESS;
     VkBufferCreateInfo vbci;
          vbci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
          vbci.pNext = nullptr;
          vbci.flags = 0;
          vbci.size = pMyBuffer->size = size;
          vbci.usage = usage;
          vbci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
          vbci.queueFamilyIndexCount = 0;
          vbci.pQueueFamilyIndices = (const uint32_t *)nullptr;
     result = vkCreateBuffer ( LogicalDevice, IN &vbci, PALLOCATOR, OUT &pMyBuffer->buffer );
    VkMemoryRequirements             vmr;
    vkGetBufferMemoryRequirements( LogicalDevice, IN pMyBuffer->buffer, OUT &vmr );         // fills vmr
    VkMemoryAllocateInfo             vmai;
       vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
       vmai.pNext = nullptr;
       vmai.allocationSize = vmr.size;
       vmai.memoryTypeIndex = FindMemoryThatIsHostVisible( );
    VkDeviceMemory                   vdm;
    result = vkAllocateMemory( LogicalDevice, IN &vmai, PALLOCATOR, OUT &vdm );
    pMyBuffer->vdm = vdm;
         We will come to the Pipeline later, but for now, know that a Vulkan pipeline is essentially a very large
         data structure that holds (what OpenGL would call) the state, including how to parse its input.
                         C/C++:
            struct vertex
                                                                         GLSL Shader:
            {                                                  layout( location = 0 ) in vec3 aVertex;
                 glm::vec3       position;                     layout( location = 1 ) in vec3 aNormal;
                 glm::vec3       normal;                       layout( location = 2 ) in vec3 aColor;
                 glm::vec3       color;                        layout( location = 3 ) in vec2 aTexCoord;
                 glm::vec2       texCoord;
            };
          vviad[2].location = 2;
          vviad[2].binding = 0;
          vviad[2].format = VK_FORMAT_VEC3;              // r, g, b
          vviad[2].offset = offsetof( struct vertex, color );                  // 24
          vviad[3].location = 3;
          vviad[3].binding = 0;
          vviad[3].format = VK_FORMAT_VEC2;              // s, t
          vviad[3].offset = offsetof( struct vertex, texCoord );                // 36
   We will come to the Pipeline later, but for now, know that a Vulkan Pipeline is essentially a very large
   data structure that holds (what OpenGL would call) the state, including how to parse its vertex input.
VkPipelineInputAssemblyStateCreateInfo    vpiasci;
         vpiasci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
         vpiasci.pNext = nullptr;
         vpiasci.flags = 0;
         vpiasci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;;
We will come to the Pipeline later, but for now, know that a Vulkan Pipeline is essentially a very large
data structure that holds (what OpenGL would call) the state, including how to parse its vertex input.
VkGraphicsPipelineCreateInfo                   vgpci;
         vgpci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
         vgpci.pNext = nullptr;
         vgpci.flags = 0;
         vgpci.stageCount = 2;           // number of shader stages in this pipeline
         vgpci.pStages = vpssci;
         vgpci.pVertexInputState = &vpvisci;
         vgpci.pInputAssemblyState = &vpiasci;
         vgpci.pTessellationState = (VkPipelineTessellationStateCreateInfo *)nullptr; // &vptsci
         vgpci.pViewportState = &vpvsci;
         vgpci.pRasterizationState = &vprsci;
         vgpci.pMultisampleState = &vpmsci;
         vgpci.pDepthStencilState = &vpdssci;
         vgpci.pColorBlendState = &vpcbsci;
         vgpci.pDynamicState = &vpdsci;
         vgpci.layout = IN GraphicsPipelineLayout;
         vgpci.renderPass = IN RenderPass;
         vgpci.subpass = 0;                    // subpass number
         vgpci.basePipelineHandle = (VkPipeline) VK_NULL_HANDLE;
         vgpci.basePipelineIndex = 0;
   We will come to Command Buffers later, but for now, know that you will specify the vertex buffer
   that you want drawn.
VkResult
Init05MyIndexDataBuffer(IN VkDeviceSize size, OUT MyBuffer * pMyBuffer)
{
      VkResult result = Init05DataBuffer(size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT, pMyBuffer);
                                               // fills pMyBuffer
      return result;
}
2 3
6 7
4 5
    Sometimes a point that is common to multiple faces has the same attributes, no matter what
    face it is in. Sometimes it doesn’t.
    A color-interpolated cube like this actually has both. Point #7 above has the same color,
    regardless of what face it is in. However, Point #7 has 3 different normal vectors, depending
    on which face you are defining. Same with its texture coordinates.
    Thus, when using indexed buffer drawing, you need to create a new vertex struct if any
    of {position, normal, color, texCoords} changes from what was previously-stored at
    those coordinates.
                                                                                                    mjb – July 24, 2020
           Sometimes the Same Point Needs Multiple Attributes                                53
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
= Fixed Function
= Programmable
Shader stages
            gl_VertexIndex                                    gl_VertexID
            gl_InstanceIndex                                  gl_InstanceID
gl_FragColor:
     Push Constants:
         layout( push_constant ) . . . ;
Specialization Constants:
    layout( constant_id = 3 ) const int N = 5;
• Only for scalars, but a vector’s components can be constructed from specialization constants
                                                                                    code[ ] (u_int32_t)
                            shaderModuleCreateFlags
                                                              codeSize (in bytes)
VkShaderModuleCreateInfo( )
device
                                                   vkCreateShaderModule( )
                                                                                                                          mjb – July 24, 2020
                                         Vulkan Shader Compiling                                                   60
     • Your shaders get turned into an intermediate form known as SPIR-V, which stands
       for Standard Portable Intermediate Representation.
     • SPIR-V gets turned into fully-compiled code at runtime, when the pipeline
       structure is finally created
     • The SPIR-V spec has been public for a few years –new shader languages are
       surely being developed
     Shaderfile extensions:
     .vert    Vertex
     .tesc    Tessellation Control
     .tese    Tessellation Evaluation
     .geom Geometry
     .frag    Fragment
     .comp Compute
     (Can be overridden by the –S option)
                     Windows: glslangValidator.exe
                     Linux:   glslangValidator
                                                                                     mjb – July 24, 2020
                              Running glslangValidator.exe                                                      62
Compile for Vulkan (“-G” is compile for OpenGL) Specify the output file
                      The input file. The compiler determines the shader type by the file extension:
                      .vert          Vertex shader
                      .tccs          Tessellation Control Shader
                      .tecs          Tessellation Evaluation Shader
                      .geom          Geometry shader
                      .frag          Fragment shader
                      .comp          Compute shader
Also, if you care, legal .spv files have a magic number of 0x07230203
So, if you do an od –x on the .spv file, the magic number looks like this:
               0203 0723 . . .
VkShaderModule      ShaderModuleVertex;
...
    VkShaderModuleCreateInfo            vsmci;
        vsmci.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
        vsmci.pNext = nullptr;
        vsmci.flags = 0;
        vsmci.codeSize = size;
        vsmci.pCode = (uint32_t *)code;
                                                                                              VkVertexInputAttributeDescription
                     VkPipelineShaderStageCreateInfo
                                                  VkPipelineVertexInputStateCreateInfo
                                                                                                           Topology
     Shader stages                                  VkPipelineInputAssemblyStateCreateInfo
    VertexInput State
                                                                                                                      x, y, w, h,
  InputAssembly State
                                                                                         Viewport                     minDepth,
    Tesselation State                             VkViewportStateCreateInfo
                                                                                                                      maxDepth
     Viewport State
   Rasterization State                                                                   Scissor
                                     VkPipelineRasterizationStateCreateInfo                                        offset
   MultiSample State
   DepthStencil State                                                                                              extent
                                     VkPipelineDepthStencilStateCreateInfo                 cullMode
    ColorBlend State
                                                                                         polygonMode
     Dynamic State
                                                                                           frontFace
     Pipeline layout
                                                                                           lineWidth
      RenderPass
  basePipelineHandle
   basePipelineIndex
                                                                                              depthTestEnable
                                         VkPipelineColorBlendStateCreateInfo                  depthWriteEnable
                                                                                              depthCompareOp
VkGraphicsPipelineCreateInfo                                                                  stencilTestEnable
                                                                                             stencilOpStateFront
                                                                                             stencilOpStateBack
                                             VkPipelineColorBlendAttachmentState
                                                                                                      blendEnable
                                                                                                 srcColorBlendFactor
                                                                                                 dstColorBlendFactor
           vkCreateGraphicsPipeline( )                                                               colorBlendOp
                                                                                                 srcAlphaBlendFactor
                                                                                                 dstAlphaBlendFactor
                                               VkPipelineDynamicStateCreateInfo                      alphaBlendOp
                                                                                                    colorWriteMask
                                  Array naming the states that can be set dynamically                                               mjb – July 24, 2020
                           You can also take a look at SPIR-V Assembly                               68
#version 400
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout( std140, set = 0, binding = 0 ) uniform matBuf
{
     mat4 uModelMatrix;
     mat4 uViewMatrix;
     mat4 uProjectionMatrix;
     mat3 uNormalMatrix;
} Matrices;
void
main( )
{
                         Capability Shader
                    1:   ExtInstImport "GLSL.std.450"
                         MemoryModel Logical GLSL450
                         EntryPoint Vertex 4 "main" 34 37 48 53 56 57 61 63
                         Source GLSL 400
                         SourceExtension "GL_ARB_separate_shader_objects"
                         SourceExtension "GL_ARB_shading_language_420pack"
                         Name 4 "main"
                         Name 10 "PVM"
                         Name 13 "matBuf"
                         MemberName 13(matBuf) 0 "uModelMatrix"
                         MemberName 13(matBuf) 1 "uViewMatrix"
                         MemberName 13(matBuf) 2 "uProjectionMatrix"
                         MemberName 13(matBuf) 3 "uNormalMatrix"
                         Name 15 "Matrices"
                         Name 32 "gl_PerVertex"
                         MemberName 32(gl_PerVertex) 0 "gl_Position"
                         MemberName 32(gl_PerVertex) 1 "gl_PointSize"
                         MemberName 32(gl_PerVertex) 2 "gl_ClipDistance"
                         Name 34 ""
                         Name 37 "aVertex"
                         Name 48 "vNormal"
                         Name 53 "aNormal"
                         Name 56 "vColor"
                         Name 57 "aColor"
                         Name 61 "vTexCoord"
                         Name 63 "aTexCoord"
                         Name 65 "lightBuf"
                         MemberName 65(lightBuf) 0 "uLightPos"
                         Name 67 "Light"
                         MemberDecorate 13(matBuf) 0 ColMajor
                         MemberDecorate 13(matBuf) 0 Offset 0
                         MemberDecorate 13(matBuf) 0 MatrixStride 16
                         MemberDecorate 13(matBuf) 1 ColMajor
                         MemberDecorate 13(matBuf) 1 Offset 64
                         MemberDecorate 13(matBuf) 1 MatrixStride 16
                         MemberDecorate 13(matBuf) 2 ColMajor
                         MemberDecorate 13(matBuf) 2 Offset 128
                         MemberDecorate 13(matBuf) 2 MatrixStride 16
                         MemberDecorate 13(matBuf) 3 ColMajor
                         MemberDecorate 13(matBuf) 3 Offset 192
                         MemberDecorate 13(matBuf) 3 MatrixStride 16
                         Decorate 13(matBuf) Block
                         Decorate 15(Matrices) DescriptorSet 0
                                                                              mjb – July 24, 2020
This is the SPIR-V Assembly, Part II                                                                       71
There are several really nice features. The two I really like are:
Data Buffers
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
A Vulkan Data Buffer is just a group of contiguous bytes in GPU memory. They have no
inherent meaning. The data that is stored there is whatever you want it to be. (This is
sometimes called a “Binary Large Object”, or “BLOB”.)
It is up to you to be sure that the writer and the reader of the Data Buffer are interpreting
the bytes in the same way!
Vulkan calls these things “Buffers”. But, Vulkan calls other things “Buffers”, too, such as
Texture Buffers and Command Buffers. So, I sometimes have taken to calling these things
“Data Buffers” and have even gone to far as to override some of Vulkan’s own terminology:
                                        bufferUsage
      LogicalDevice                  queueFamilyIndices
                                        size (bytes)
VkBufferCreateInfo
vkCreateBuffer( )
Buffer
vkGetBufferMemoryRequirements( )
memoryType size
VkMemoryAllocateInfo
LogicalDevice vkAllocateMemory( )
bufferMemoryHandle
vkBindBufferMemory( )
vkMapMemory( )
gpuAddress
VkBuffer Buffer;
VkBufferCreateInfo vbci;
    vbci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
    vbci.pNext = nullptr;
    vbci.flags = 0;
    vbci.size = << buffer size in bytes >>
    vbci.usage = <<or’ed bits of: >>
          VK_USAGE_TRANSFER_SRC_BIT
          VK_USAGE_TRANSFER_DST_BIT
          VK_USAGE_UNIFORM_TEXEL_BUFFER_BIT
          VK_USAGE_STORAGE_TEXEL_BUFFER_BIT
          VK_USAGE_UNIFORM_BUFFER_BIT
          VK_USAGE_STORAGE_BUFFER_BIT
          VK_USAGE_INDEX_BUFFER_BIT
          VK_USAGE_VERTEX_BUFFER_BIT
          VK_USAGE_INDIRECT_BUFFER_BIT
    vbci.sharingMode = << one of: >>
          VK_SHARING_MODE_EXCLUSIVE
          VK_SHARING_MODE_CONCURRENT
    vbci.queueFamilyIndexCount = 0;
    vbci.pQueueFamilyIndices = (const iont32_t) nullptr;
VkMemoryRequirements        vmr;
result = vkGetBufferMemoryRequirements( LogicalDevice, Buffer, OUT &vmr );
VkMemoryAllocateInfo             vmai;
   vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
   vmai.pNext = nullptr;
   vmai.flags = 0;
   vmai.allocationSize = vmr.size;
   vmai.memoryTypeIndex = FindMemoryThatIsHostVisible( );
...
VkDeviceMemory               vdm;
result = vkAllocateMemory( LogicalDevice, IN &vmai, PALLOCATOR, OUT &vdm );
...
int
FindMemoryThatIsHostVisible( )
{
    VkPhysicalDeviceMemoryProperties         vpdmp;
    vkGetPhysicalDeviceMemoryProperties( PhysicalDevice, OUT &vpdmp );
    for( unsigned int i = 0; i < vpdmp.memoryTypeCount; i++ )
    {
          VkMemoryType vmt = vpdmp.memoryTypes[ i ];
          if( ( vmt.propertyFlags & VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT ) != 0 )
          {
                 return i;
          }
    }
    return -1;
}
int
FindMemoryThatIsDeviceLocal( )
{
    VkPhysicalDeviceMemoryProperties         vpdmp;
    vkGetPhysicalDeviceMemoryProperties( PhysicalDevice, OUT &vpdmp );
    for( unsigned int i = 0; i < vpdmp.memoryTypeCount; i++ )
    {
          VkMemoryType vmt = vpdmp.memoryTypes[ i ];
          if( ( vmt.propertyFlags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT ) != 0 )
          {
                 return i;
          }
    }
    return -1;
}
VkPhysicalDeviceMemoryProperties              vpdmp;
vkGetPhysicalDeviceMemoryProperties( PhysicalDevice, OUT &vpdmp );
     11 Memory Types:
     Memory 0:
     Memory 1:
     Memory 2:
     Memory 3:
     Memory 4:
     Memory 5:
     Memory 6:
     Memory 7: DeviceLocal
     Memory 8: DeviceLocal
     Memory 9: HostVisible HostCoherent
     Memory 10: HostVisible HostCoherent HostCached
     2 Memory Heaps:
     Heap 0: size = 0xb7c00000 DeviceLocal
     Heap 1: size = 0xfac00000
https://github.com/GPUOpen-LibrariesAndSDKs/VulkanMemoryAllocator
#define VMA_IMPLEMENTATION
#include “vk_mem_alloc.h”
...
VkBufferCreateInfo            vbci;
...
VmaAllocationCreateInfo       vaci;
     vaci.physicalDevice = PhysicalDevice;
     vaci.device = LogicalDevice;
     vaci.usage = VMA_MEMORY_USAGE_GPU_ONLY;
VmaAllocator                 var;
vmaCreateAllocator( IN &vaci, OUT &var );
...
..
VkBuffer                     Buffer;
VmaAllocation                van;
vmaCreateBuffer( IN var, IN &vbci, IN &vaci, OUT &Buffer. OUT &van, nullptr );
void *mappedDataAddr;
vmaMapMemory( IN var, IN van, OUT &mappedDataAddr );
     memcpy( mappedDataAddr, &MyData, sizeof(MyData) );
vmaUnmapMemory( IN var, IN van );
...
MyBuffer MyMatrixUniformBuffer;
It’s the usual object-oriented benefit – you can pass around just one
data-item and everyone can access whatever information they need.
 It’s the usual object-oriented benefit – you can pass around just one
 data-item and everyone can access whatever information they need.
VkResult
Init05DataBuffer( VkDeviceSize size, VkBufferUsageFlags usage, OUT MyBuffer * pMyBuffer )
{
...
     vbci.size = pMyBuffer->size = size;
...
     result = vkCreateBuffer ( LogicalDevice, IN &vbci, PALLOCATOR, OUT &pMyBuffer->buffer );
...
     pMyBuffer->vdm = vdm;
...
}
             struct matBuf
             {
                  glm::mat4 uModelMatrix;
                  glm::mat4 uViewMatrix;
                  glm::mat4 uProjectionMatrix;
                  glm::mat3 uNormalMatrix;
             } Matrices;
Here’s the associated GLSL shader code to access those uniform variables
glm::vec3 eye(0.,0.,EYEDIST);
glm::vec3 look(0.,0.,0.);
glm::vec3 up(0.,1.,0.);
#define GLM_FORCE_RADIANS
                                         MyBuffer   MyMatrixUniformBuffer;
                  The MyBuffer does not hold any actual data itself. It just
                  information about what is in the data buffer
VkResult
Init05DataBuffer( VkDeviceSize size, VkBufferUsageFlags usage, OUT MyBuffer * pMyBuffer )
{
     VkResult result = VK_SUCCESS;
     VkBufferCreateInfo vbci;
          vbci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
          vbci.pNext = nullptr;
          vbci.flags = 0;
          vbci.size = pMyBuffer->size = size;
          vbci.usage = usage;
         vbci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
         vbci.queueFamilyIndexCount = 0;
          vbci.pQueueFamilyIndices = (const uint32_t *)nullptr;
     result = vkCreateBuffer ( LogicalDevice, IN &vbci, PALLOCATOR, OUT &pMyBuffer->buffer );
    VkMemoryRequirements             vmr;
    vkGetBufferMemoryRequirements( LogicalDevice, IN pMyBuffer->buffer, OUT &vmr );      // fills vmr
    VkMemoryAllocateInfo             vmai;
       vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
       vmai.pNext = nullptr;
       vmai.allocationSize = vmr.size;
       vmai.memoryTypeIndex = FindMemoryThatIsHostVisible( );
    VkDeviceMemory                   vdm;
    result = vkAllocateMemory( LogicalDevice, IN &vmai, PALLOCATOR, OUT &vdm );
    pMyBuffer->vdm = vdm;
VkResult
Fill05DataBuffer( IN MyBuffer myBuffer, IN void * data )
{
     // the size of the data had better match the size that was used to Init the buffer!
     void * pGpuMemory;
     vkMapMemory( LogicalDevice, IN myBuffer.vdm, 0, VK_WHOLE_SIZE, 0, OUT &pGpuMemory );
                                                         // 0 and 0 are offset and flags
     memcpy( pGpuMemory, data, (size_t)myBuffer.size );
     vkUnmapMemory( LogicalDevice, IN myBuffer.vdm );
     return VK_SUCCESS;
}
GLFW
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
#define GLFW_INCLUDE_VULKAN
#include "glfw3.h"
      ...
void
InitGLFW( )
{
     glfwInit( );
      if( ! glfwVulkanSupported( ) )
      {
             fprintf( stderr, “Vulkan is not supported on this system!\n” );
             exit( 1 );
      }
     glfwWindowHint( GLFW_CLIENT_API, GLFW_NO_API );
     glfwWindowHint( GLFW_RESIZABLE, GLFW_FALSE );
     MainWindow = glfwCreateWindow( Width, Height, "Vulkan Sample", NULL, NULL );
     VkResult result = glfwCreateWindowSurface( Instance, MainWindow, NULL, OUT &Surface );
    glfwSetErrorCallback( GLFWErrorCallback );
    glfwSetKeyCallback( MainWindow,       GLFWKeyboard );
    glfwSetCursorPosCallback( MainWindow,      GLFWMouseMotion );
    glfwSetMouseButtonCallback( MainWindow, GLFWMouseButton );
}
                                                                                              mjb – July 24, 2020
       You Can Also Query What Vulkan Extensions GLFW Requires                                95
uint32_t count;
const char ** extensions = glfwGetRequiredInstanceExtensions (&count);
void
GLFWKeyboard( GLFWwindow * window, int key, int scancode, int action, int mods )
{
     if( action == GLFW_PRESS )
     {
           switch( key )
           {
                 //case GLFW_KEY_M:
                 case 'm':
                 case 'M':
                      Mode++;
                      if( Mode >= 2 )
                            Mode = 0;
                      break;
              default:
                   fprintf( FpDebug, "Unknow key hit: 0x%04x = '%c'\n", key, key );
                   fflush(FpDebug);
         }
    }
}
         case GLFW_MOUSE_BUTTON_MIDDLE:
             b = MIDDLE;   break;
         case GLFW_MOUSE_BUTTON_RIGHT:
             b = RIGHT;   break;
         default:
             b = 0;
             fprintf( FpDebug, "Unknown mouse button: %d\n", button );
    }
void
GLFWMouseMotion( GLFWwindow *window, double xpos, double ypos )
{
     int dx = (int)xpos - Xmouse; // change in mouse coords
     int dy = (int)ypos - Ymouse;
vkQueueWaitIdle( Queue );
vkDeviceWaitIdle( LogicalDevice );
DestroyAllVulkan( );
glfwDestroyWindow( MainWindow );
glfwTerminate( );
glfwWaitEvents( );
You can have the blocking wake up after a timeout period with:
You can wake up one of these blocks from another thread with:
glfwPostEmptyEvent( );
GLM
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
GLM is a set of C++ classes and functions to fill in the programming gaps in writing
the basic vector and matrix mathematics for OpenGL applications. However, even
though it was written for OpenGL, it works fine with Vulkan.
        #include <glm/glm.hpp>
        #include <glm/gtc/matrix_transform.hpp>
        #include <glm/gtc/matrix_inverse.hpp>
If GLM is not installed in a system place, put it somewhere you can get access to.
All of the things that we have talked about being deprecated in OpenGL are really
deprecated in Vulkan -- built-in pipeline transformations, begin-end, fixed-function, etc.              So,
where you might have said in OpenGL:
glMatrixMode( GL_MODELVIEW );
glLoadIdentity( );
gluLookAt( 0., 0., 3., 0., 0., 0., 0., 1., 0. );
glRotatef( (GLfloat)Yrot, 0., 1., 0. );
glRotatef( (GLfloat)Xrot, 1., 0., 0. );
glScalef( (GLfloat)Scale, (GLfloat)Scale, (GLfloat)Scale );
This is exactly the same concept as OpenGL, but a different expression of it. Read on for details …
// constructor:
glm::mat4 * glm::mat4
glm::mat4 * glm::vec4
glm::mat4 * glm::vec4( glm::vec3, 1. )       // promote a vec3 to a vec4 via a constructor
glm::mat4 glm::rotate( glm::mat4 const & m, float angle, glm::vec3 const & axis );
glm::mat4 glm::ortho( float left, float right, float bottom, float top, float near, float far );
glm::mat4 glm::ortho( float left, float right, float bottom, float top );
glm::mat4 glm::frustum( float left, float right, float bottom, float top, float near, float far );
glm::mat4 glm::perspective( float fovy, float aspect, float near, float far);
glm::mat4 glm::lookAt( glm::vec3 const & eye, glm::vec3 const & look, glm::vec3 const & up );
I like to just put the whole thing under my Visual Studio project folder
so I can zip up a complete project and give it to someone else.
glm::vec3 eye(0.,0.,EYEDIST );
glm::vec3 look(0.,0.,0.);
glm::vec3 up(0.,1.,0.);
Matrices.uVewMatrix = glm::lookAt( eye, look, up );
Misc.uTime = (float)Time;
Misc.uMode = Mode;
Fill05DataBuffer( MyMiscUniformBuffer, (void *) &Misc );
                                                                                        Right!
          Original object and normal
Instancing
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
• It uses all the same vertices and graphics pipeline each time
        • It avoids the overhead of the program asking to have the object drawn again,
          letting the GPU/driver handle all of that
          But, this will only get us multiple instances of identical objects drawn on top of
          each other. How can we make each instance look differently?
Use the built-in vertex shader variable gl_InstanceIndex to define a unique display property,
such as position or color.
gl_InstanceIndex starts at 0
Put the unique characteristics in a uniform buffer array and reference them
...
vec4 vertex = . . .
              Mike Bailey
          mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
1. The Vulkan Graphics Pipeline is like what OpenGL would call “The State”, or “The Context”. It is a data structure.
3. For the most part, the Vulkan Graphics Pipeline Data Structure is immutable – that is, once this combination of
   state variables is combined into a Pipeline, that Pipeline never gets changed. To make new combinations of state
   variables, create a new Graphics Pipeline.
4. The shaders get compiled the rest of the way when their Graphics Pipeline gets created.
                                                                                                                   mjb – July 24, 2020
                          Graphics Pipeline Stages and what goes into Them                            117
Viewport
Scissoring                                                          Viewport
Depth Clamping
DiscardEnable
PolygonMode
CullMode                                                          Rasterization
FrontFace
LineWidth
        The Graphics Pipeline Layout is fairly static. Only the layout of the
        Descriptor Sets and information on the Push Constants need to be supplied.
VkResult
Init14GraphicsPipelineLayout( )
{
     VkResult result;
    VkPipelineLayoutCreateInfo            vplci;
        vplci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        vplci.pNext = nullptr;
                                                                    Let the Pipeline Layout know about the
        vplci.flags = 0;
        vplci.setLayoutCount = 4;                                   Descriptor Set and Push Constant layouts.
        vplci.pSetLayouts = &DescriptorSetLayouts[0];
        vplci.pushConstantRangeCount = 0;
        vplci.pPushConstantRanges = (VkPushConstantRange *)nullptr;
    return result;
}
                      Why is this necessary? It is because the Descriptor Sets and Push
                      Constants data structures have different sizes depending on how many of
                      each you have. So, the exact structure of the Pipeline Layout depends on
                      you telling Vulkan about the Descriptor Sets and Push Constants that you
                      will be using.                                                                        mjb – July 24, 2020
                                                                                                                  119
                   A Pipeline Data Structure Contains the Following State Items:
Bold/Italics indicates that this state item can also be set with Dynamic State Variables
                                                                                                           VkVertexInputAttributeDescription
                                    VkPipelineShaderStageCreateInfo
                                                               VkPipelineVertexInputStateCreateInfo
                                                                                                                         Topology
                   Shaders                                       VkPipelineInputAssemblyStateCreateInfo
               VertexInput State
                                                                                                                                    x, y, w, h,
             InputAssembly State
                                                                                                       Viewport                     minDepth,
               Tesselation State                               VkViewportStateCreateInfo
                                                                                                                                    maxDepth
                Viewport State
              Rasterization State                                                                      Scissor
                                                   VkPipelineRasterizationStateCreateInfo                                       offset
              MultiSample State
              DepthStencil State                                                                                                extent
                                                  VkPipelineDepthStencilStateCreateInfo                  cullMode
               ColorBlend State
                                                                                                       polygonMode
                Dynamic State
                                                                                                         frontFace
                Pipeline layout
                                                                                                         lineWidth
                 RenderPass
             basePipelineHandle
              basePipelineIndex
                                                                                                           depthTestEnable
                                                   VkPipelineColorBlendStateCreateInfo                     depthWriteEnable
                                                                                                           depthCompareOp
           VkGraphicsPipelineCreateInfo                                                                    stencilTestEnable
                                                                                                          stencilOpStateFront
                                                                                                          stencilOpStateBack
                                                           VkPipelineColorBlendAttachmentState
                                                                                                                       blendEnable
                                                                                                                  srcColorBlendFactor
                       vkCreateGraphicsPipeline( )                                                                dstColorBlendFactor
                                                                                                                      colorBlendOp
                                                                                                                  srcAlphaBlendFactor
                                                            VkPipelineDynamicStateCreateInfo                      dstAlphaBlendFactor
                                                                                                                      alphaBlendOp
                 Graphics Pipeline
                                                                                                                     colorWriteMask
                                                 Array naming the states that can be set dynamically                                              mjb – July 24, 2020
                                           Creating a Typical Graphics Pipeline                                                     121
VkResult
Init14GraphicsVertexFragmentPipeline( VkShaderModule vertexShader, VkShaderModule fragmentShader,
                                     VkPrimitiveTopology topology, OUT VkPipeline *pGraphicsPipeline )
{
#ifdef ASSUMPTIONS
          vvibd[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
          vprsci.depthClampEnable = VK_FALSE;
          vprsci.rasterizerDiscardEnable = VK_FALSE;
          vprsci.polygonMode = VK_POLYGON_MODE_FILL;
          vprsci.cullMode = VK_CULL_MODE_NONE; // best to do this because of the projectionMatrix[1][1] *= -1.;
          vprsci.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
          vpmsci.rasterizationSamples = VK_SAMPLE_COUNT_ONE_BIT;
          vpcbas.blendEnable = VK_FALSE;
          vpcbsci.logicOpEnable = VK_FALSE;
         vpdssci.depthTestEnable = VK_TRUE;
          vpdssci.depthWriteEnable = VK_TRUE;
          vpdssci.depthCompareOp = VK_COMPARE_OP_LESS;
#endif
                                                   These settings seem pretty typical to me. Let’s write a simplified
     ...
                                                   Pipeline-creator that accepts Vertex and Fragment shader modules
                                                   and the topology, and always uses the settings in red above.
VkPipelineShaderStageCreateInfo                    vpssci[2];
          vpssci[0].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
          vpssci[0].pNext = nullptr;
          vpssci[0].flags = 0;
          vpssci[0].stage = VK_SHADER_STAGE_VERTEX_BIT;
          vpssci[0].module = vertexShader;
          vpssci[0].pName = "main";
          vpssci[0].pSpecializationInfo = (VkSpecializationInfo *)nullptr;
                                                                           Use one vpssci array member per
#ifdef BITS                                                                shader module you are using
VK_SHADER_STAGE_VERTEX_BIT
VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT
VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT
VK_SHADER_STAGE_GEOMETRY_BIT
VK_SHADER_STAGE_FRAGMENT_BIT
VK_SHADER_STAGE_COMPUTE_BIT
VK_SHADER_STAGE_ALL_GRAPHICS
VK_SHADER_STAGE_ALL
#endif
          vpssci[1].sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
          vpssci[1].pNext = nullptr;
          vpssci[1].flags = 0;
          vpssci[1].stage = VK_SHADER_STAGE_FRAGMENT_BIT;
          vpssci[1].module = fragmentShader;
          vpssci[1].pName = "main";                                        Use one vvibd array member per vertex
          vpssci[1].pSpecializationInfo = (VkSpecializationInfo *)nullptr; input array-of-structures you are using
     VkVertexInputBindingDescription                vvibd[1];      // an array containing one of these per buffer being used
         vvibd[0].binding = 0;         // which binding # this is
         vvibd[0].stride = sizeof( struct vertex );         // bytes between successive
         vvibd[0].inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
#ifdef CHOICES
VK_VERTEX_INPUT_RATE_VERTEX
VK_VERTEX_INPUT_RATE_INSTANCE
#endif
 VkVertexInputAttributeDescription                vviad[4];            // an array containing one of these per vertex attribute in all bindings
           // 4 = vertex, normal, color, texture coord
           vviad[0].location = 0;             // location in the layout
           vviad[0].binding = 0;               // which binding description this is part of     Use one vviad array member per element
           vviad[0].format = VK_FORMAT_VEC3;                // x, y, z                          in the struct for the array-of-structures
           vviad[0].offset = offsetof( struct vertex, position );              // 0
#ifdef EXTRAS_DEFINED_AT_THE_TOP                                                                element you are using as vertex input
// these are here for convenience and readability:
#define VK_FORMAT_VEC4                  VK_FORMAT_R32G32B32A32_SFLOAT
#define VK_FORMAT_XYZW                  VK_FORMAT_R32G32B32A32_SFLOAT
#define VK_FORMAT_VEC3                  VK_FORMAT_R32G32B32_SFLOAT
#define VK_FORMAT_STP                  VK_FORMAT_R32G32B32_SFLOAT                                    These are defined at the top of the
#define VK_FORMAT_XYZ                  VK_FORMAT_R32G32B32_SFLOAT
#define VK_FORMAT_VEC2                  VK_FORMAT_R32G32_SFLOAT
                                                                                                     sample code so that you don’t need to
#define VK_FORMAT_ST                    VK_FORMAT_R32G32_SFLOAT                                      use confusing image-looking formats
#define VK_FORMAT_XY                    VK_FORMAT_R32G32_SFLOAT                                      for positions, normals, and tex coords
#define VK_FORMAT_FLOAT                 VK_FORMAT_R32_SFLOAT
#define VK_FORMAT_S                     VK_FORMAT_R32_SFLOAT
#define VK_FORMAT_X                     VK_FORMAT_R32_SFLOAT
#endif
           vviad[1].location = 1;
           vviad[1].binding = 0;
           vviad[1].format = VK_FORMAT_VEC3;                // nx, ny, nz
           vviad[1].offset = offsetof( struct vertex, normal );                 // 12
         vviad[2].location = 2;
         vviad[2].binding = 0;
         vviad[2].format = VK_FORMAT_VEC3;               // r, g, b
         vviad[2].offset = offsetof( struct vertex, color );          // 24
         vviad[3].location = 3;
         vviad[3].binding = 0;
         vviad[3].format = VK_FORMAT_VEC2;              // s, t
         vviad[3].offset = offsetof( struct vertex, texCoord );       // 36
     VkPipelineInputAssemblyStateCreateInfo      vpiasci;
         vpiasci.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
         vpiasci.pNext = nullptr;
         vpiasci.flags = 0;
         vpiasci.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;;
#ifdef CHOICES
VK_PRIMITIVE_TOPOLOGY_POINT_LIST
VK_PRIMITIVE_TOPOLOGY_LINE_LIST                                      Declare the vertex              topology
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY
VK_PRIMITIVE_TOPOLOGY_LINE_STRIP_WITH_ADJACENCY
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY
#endif
         vpiasci.primitiveRestartEnable = VK_FALSE;
   VkPipelineTessellationStateCreateInfo          vptsci;
       vptsci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
       vptsci.pNext = nullptr;
       vptsci.flags = 0;                                                   Tessellation       Shader info
       vptsci.patchControlPoints = 0;    // number of patch control points
   VkPipelineGeometryStateCreateInfo      vpgsci;
       vptsci.sType = VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO;
       vptsci.pNext = nullptr;
       vptsci.flags = 0;                                            Geometry Shader                   info
                                                                                                                    mjb – July 24, 2020
                            Options for vpiasci.topology                                                  125
VK_PRIMITIVE_TOPOLOGY_POINT_LIST               VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST
                                                                              V5
                  V3                                     V2
                             V2                                                         V4
                                                                              V3
          V0           V1                                           V1
                                               V0
                                           VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
VK_PRIMITIVE_TOPOLOGY_LINE_LIST                                         V6
                  V3                                      V4                             V7
                                                    V2
                             V2                                                    V5
                       V1                                                    V3
          V0                               V0
                                                         V1
 VK_PRIMITIVE_TOPOLOGY_LINE_STRIP              VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN
                  V3                                          V2
                                          V3
                             V2                                               V1
                       V1                                          V0
          V0                                             V0
                                               V4                       V5                    mjb – July 24, 2020
                     What is “Primitive Restart Enable”?                                                       126
vpiasci.primitiveRestartEnable = VK_FALSE;
VkViewport                          vv;
       vv.x = 0;
       vv.y = 0;                                       Declare the viewport information
       vv.width = (float)Width;
       vv.height = (float)Height;
       vv.minDepth = 0.0f;
       vv.maxDepth = 1.0f;
 VkPipelineViewportStateCreateInfo    vpvsci;
         vpvsci.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
         vpvsci.pNext = nullptr;
         vpvsci.flags = 0;                                            Group the viewport and
         vpvsci.viewportCount = 1;                                    scissor information together
         vpvsci.pViewports = &vv;
         vpvsci.scissorCount = 1;
         vpvsci.pScissors = &vr;
           Viewport
           :Viewporting operates on vertices and takes place
            right before the rasterizer. Changing the vertical part
            of the viewport causes the entire scene to get scaled
            (scrunched) into the viewport area.
Original Image
                         Scissoring:
                         Scissoring operates on fragments and
                         takes place right after the rasterizer.
                         Changing the vertical part of the
                         scissor causes the entire scene to get
                         clipped where it falls outside the
                         scissor area.
 VkPipelineRasterizationStateCreateInfo          vprsci;
          vprsci.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
          vprsci.pNext = nullptr;
          vprsci.flags = 0;                                         Declare information about how                 the
          vprsci.depthClampEnable = VK_FALSE;                       rasterization will take place
          vprsci.rasterizerDiscardEnable = VK_FALSE;
          vprsci.polygonMode = VK_POLYGON_MODE_FILL;
#ifdef CHOICES
VK_POLYGON_MODE_FILL
VK_POLYGON_MODE_LINE
VK_POLYGON_MODE_POINT
#endif
          vprsci.cullMode = VK_CULL_MODE_NONE;           // recommend this because of the projMatrix[1][1] *= -
1.;
#ifdef CHOICES
VK_CULL_MODE_NONE
VK_CULL_MODE_FRONT_BIT
VK_CULL_MODE_BACK_BIT
VK_CULL_MODE_FRONT_AND_BACK_BIT
#endif
          vprsci.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
#ifdef CHOICES
VK_FRONT_FACE_COUNTER_CLOCKWISE
VK_FRONT_FACE_CLOCKWISE
#endif
          vprsci.depthBiasEnable = VK_FALSE;
          vprsci.depthBiasConstantFactor = 0.f;
          vprsci.depthBiasClamp = 0.f;
          vprsci.depthBiasSlopeFactor = 0.f;
          vprsci.lineWidth = 1.f;
vprsci.depthClampEnable = VK_FALSE;
Depth Clamp Enable causes the fragments that would normally have been
discarded because they are closer to the viewer than the near clipping plane to
instead get projected to the near clipping plane and displayed.
 vprsci.depthBiasEnable = VK_FALSE;
 vprsci.depthBiasConstantFactor = 0.f;
 vprsci.depthBiasClamp = 0.f;
 vprsci.depthBiasSlopeFactor = 0.f;
Depth Bias Enable allows scaling and translation of the Z-depth values as
they come through the rasterizer to avoid Z-fighting.
Z-fighting
VkPipelineMultisampleStateCreateInfo         vpmsci;
         vpmsci.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
         vpmsci.pNext = nullptr;
         vpmsci.flags = 0;
         vpmsci.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;      Declare information about how
         vpmsci.sampleShadingEnable = VK_FALSE;                    the multisampling will take place
         vpmsci.minSampleShading = 0;
         vpmsci.pSampleMask = (VkSampleMask *)nullptr;
         vpmsci.alphaToCoverageEnable = VK_FALSE;
         vpmsci.alphaToOneEnable = VK_FALSE;
      Create an array with one of these for each color buffer attachment. Each
      color buffer attachment can use different blending operations.
VkPipelineColorBlendAttachmentState          vpcbas;
         vpcbas.blendEnable = VK_FALSE;
         vpcbas.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_COLOR;
         vpcbas.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
         vpcbas.colorBlendOp = VK_BLEND_OP_ADD;
         vpcbas.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;   This controls blending between the output of
         vpcbas.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO; each color attachment and its image memory.
         vpcbas.alphaBlendOp = VK_BLEND_OP_ADD;
         vpcbas.colorWriteMask =      VK_COLOR_COMPONENT_R_BIT
                                 | VK_COLOR_COMPONENT_G_BIT
                                 | VK_COLOR_COMPONENT_B_BIT
                                 | VK_COLOR_COMPONENT_A_BIT;
 VkPipelineColorBlendStateCreateInfo        vpcbsci;
          vpcbsci.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
          vpcbsci.pNext = nullptr;
          vpcbsci.flags = 0;
          vpcbsci.logicOpEnable = VK_FALSE;
          vpcbsci.logicOp = VK_LOGIC_OP_COPY;
#ifdef CHOICES
VK_LOGIC_OP_CLEAR
VK_LOGIC_OP_AND
VK_LOGIC_OP_AND_REVERSE
VK_LOGIC_OP_COPY                                        This controls blending between the
VK_LOGIC_OP_AND_INVERTED                                output of the fragment shader and the
VK_LOGIC_OP_NO_OP
VK_LOGIC_OP_XOR
                                                        input to the color attachments.
VK_LOGIC_OP_OR
VK_LOGIC_OP_NOR
VK_LOGIC_OP_EQUIVALENT
VK_LOGIC_OP_INVERT
VK_LOGIC_OP_OR_REVERSE
VK_LOGIC_OP_COPY_INVERTED
VK_LOGIC_OP_OR_INVERTED
VK_LOGIC_OP_NAND
VK_LOGIC_OP_SET
#endif
          vpcbsci.attachmentCount = 1;
          vpcbsci.pAttachments = &vpcbas;
          vpcbsci.blendConstants[0] = 0;
          vpcbsci.blendConstants[1] = 0;
          vpcbsci.blendConstants[2] = 0;
          vpcbsci.blendConstants[3] = 0;
Depth
Update Stencil
Render
     2. While drawing into the Render Buffer, you can do arithmetic on values in the
        Stencil Buffer at the same time.
     3. When drawing into the Render Buffer, you can write-protect certain parts of the
        Render Buffer based on values that are in the Stencil Buffer
                                                                                          mjb – July 24, 2020
                                                              138
Using the Stencil Buffer to Create a Magic Lens
1.   Clear the SB = 0
2.   Write protect the color buffer
3.   Fill a square, setting SB = 1
4.   Write-enable the color buffer
5.   Draw the solids wherever SB == 0
6.   Draw the wireframes wherever SB == 1
Z-fighting
Clear the SB = 0
    VkPipelineDepthStencilStateCreateInfo        vpdssci;
        vpdssci.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
        vpdssci.pNext = nullptr;
        vpdssci.flags = 0;
        vpdssci.depthTestEnable = VK_TRUE;
        vpdssci.depthWriteEnable = VK_TRUE;
        vpdssci.depthCompareOp = VK_COMPARE_OP_LESS;
VK_COMPARE_OP_NEVER                           -- never succeeds
VK_COMPARE_OP_LESS                            -- succeeds if new depth value is < the existing value
VK_COMPARE_OP_EQUAL                           -- succeeds if new depth value is == the existing value
VK_COMPARE_OP_LESS_OR_EQUAL                   -- succeeds if new depth value is <= the existing value
VK_COMPARE_OP_GREATER                         -- succeeds if new depth value is > the existing value
VK_COMPARE_OP_NOT_EQUAL                       -- succeeds if new depth value is != the existing value
VK_COMPARE_OP_GREATER_OR_EQUAL                -- succeeds if new depth value is >= the existing value
VK_COMPARE_OP_ALWAYS                          -- always succeeds
#endif
        vpdssci.depthBoundsTestEnable = VK_FALSE;
        vpdssci.front = vsosf;
        vpdssci.back = vsosb;
        vpdssci.minDepthBounds = 0.;
        vpdssci.maxDepthBounds = 1.;
        vpdssci.stencilTestEnable = VK_FALSE;
VkPipeline GraphicsPipeline;
     VkGraphicsPipelineCreateInfo                    vgpci;
         vgpci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
         vgpci.pNext = nullptr;
         vgpci.flags = 0;
#ifdef CHOICES                                                             Group all of the   individual state
VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT                                information and    create the pipeline
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
VK_PIPELINE_CREATE_DERIVATIVE_BIT
#endif
         vgpci.stageCount = 2;                   // number of stages in this pipeline
         vgpci.pStages = vpssci;
         vgpci.pVertexInputState = &vpvisci;
         vgpci.pInputAssemblyState = &vpiasci;
         vgpci.pTessellationState = (VkPipelineTessellationStateCreateInfo *)nullptr;
         vgpci.pViewportState = &vpvsci;
         vgpci.pRasterizationState = &vprsci;
         vgpci.pMultisampleState = &vpmsci;
         vgpci.pDepthStencilState = &vpdssci;
         vgpci.pColorBlendState = &vpcbsci;
         vgpci.pDynamicState = &vpdsci;
         vgpci.layout = IN GraphicsPipelineLayout;
         vgpci.renderPass = IN RenderPass;
         vgpci.subpass = 0;                    // subpass number
         vgpci.basePipelineHandle = (VkPipeline) VK_NULL_HANDLE;
         vgpci.basePipelineIndex = 0;
vkCmdBindPipeline( CommandBuffers[nextImageIndex],
                VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipeline );
If you take a close look at the pipeline data structure creation information, you will see that almost all
the pieces have a fixed size. For example, the viewport only needs 6 pieces of information – ever:
     VkViewport            vv;
        vv.x = 0;
        vv.y = 0;
        vv.width = (float)Width;
        vv.height = (float)Height;
        vv.minDepth = 0.0f;
        vv.maxDepth = 1.0f;
There are two exceptions to this -- the Descriptor Sets and the Push Constants. Each of these two
can be almost any size, depending on what you allocate for them. So, I think of the Pipeline Data
Structure as consisting of some fixed-layout blocks and 2 variable-layout blocks, like this:
Descriptor Sets
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
OpenGL puts all uniform data in the same “set”, but with different binding numbers, so you
can get at each one.
Wouldn’t it be nice if we could update a collection of related uniform variables all at once,
without having to update the uniform variables that are not related to this collection?
Descriptor Sets are an intermediate data structure that tells shaders how to connect
information held in GPU memory to groups of related uniform variables and texture sampler
declarations in shaders. There are three advantages in doing things this way:
• Descriptor Sets are activated when the Command Buffer is filled. Different values for the
  uniform buffer variables can be toggled by just swapping out the Descriptor Set that
  points to GPU memory, rather than re-writing the GPU memory.
• Values for the shaders’ uniform buffer variables can be compartmentalized into what
  quantities change often and what change seldom (scene-level, model-level, draw-level),
  so that uniform variables need to be re-written no more often than is necessary.
  for( each scene )
  {
          Bind Descriptor Set #0
          for( each object )
          {
                Bind Descriptor Set #1
                for( each draw )
                {
                      Bind Descriptor Set #2
                      Do the drawing
                }
          }
  }                                                                                           mjb – July 24, 2020
                              Descriptor Sets                                 152
                                           10111001010101111101000
struct matBuf                              10000101110110101110100
                                                                       layout( std140, set = 0, binding = 0 ) uniform matBuf
{                                          11011001100000011101011     {
                                           11001110110100110010111
     glm::mat4 uModelMatrix;               11010111001101101010000
                                                                            mat4 uModelMatrix;
     glm::mat4 uViewMatrix;                01001000111101000100101          mat4 uViewMatrix;
                                           01010100111111001000011
     glm::mat4 uProjectionMatrix;          10010101010011000110110          mat4 uProjectionMatrix;
     glm::mat3 uNormalMatrix;              10110111110111111111100          mat3 uNormalMatrix;
                                           11010101000010111011001
};                                         10010001101000101001110     } Matrices;
                                           01110101110100110001110
                                           10001010001111010111101
struct lightBuf                            10111010010010001101011     layout( std140, set = 1, binding = 0 ) uniform lightBuf
                                           00000001111100011000010
{                                          00001101100111010100011
                                                                       {
     glm::vec4 uLightPos;                  10100011001100110010000          vec4 uLightPos;
                                           11000011001111001001111
};                                         01001000100101100111000
                                                                       } Light;
                                           10111000000101000010111
                                           11101011111001110001011
struct miscBuf                             10000110011101001111001     layout( std140, set = 2, binding = 0 ) uniform miscBuf
{                                          11110111011111111011111     {
                                           10100111101111010111100
     float uTime;                          10101000000111100100110          float uTime;
     int uMode;                            01110011111010010110011          int uMode;
                                           10110011100011011000111
};                                         10110000111110001110010     } Misc;
                                           11001001110011010111011
                                           10010100
                                                                       layout( set = 3, binding = 0 ) uniform sampler2D uSampler;
              * “binary large object”
                                                                                                                                         mjb – July 24, 2020
                                   Step 1: Descriptor Set Pools                                       154
You don’t allocate Descriptor Sets on the fly – that is too slow.
Instead, you allocate a “pool” of Descriptor Sets and then pull from that pool later.
VkDescriptorPoolCreateInfo
device
vkCreateDescriptorPool( )
DescriptorSetPool
    VkDescriptorPoolSize             vdps[4];
        vdps[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        vdps[0].descriptorCount = 1;
        vdps[1].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        vdps[1].descriptorCount = 1;
        vdps[2].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
        vdps[2].descriptorCount = 1;
        vdps[3].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
        vdps[3].descriptorCount = 1;
#ifdef CHOICES
VK_DESCRIPTOR_TYPE_SAMPLER
VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER
VK_DESCRIPTOR_TYPE_STORAGE_IMAGE
VK_DESCRIPTOR_TYPE_UNIFORM_TEXEL_BUFFER
VK_DESCRIPTOR_TYPE_STORAGE_TEXEL_BUFFER
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER_DYNAMIC
VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT
#endif
    VkDescriptorPoolCreateInfo       vdpci;
        vdpci.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
        vdpci.pNext = nullptr;
        vdpci.flags = 0;
        vdpci.maxSets = 4;
        vdpci.poolSizeCount = 4;
        vdpci.pPoolSizes = &vdps[0];
I think of Descriptor Set Layouts as a kind of “Rosetta Stone” that allows the Graphics
Pipeline data structure to allocate room for the uniform variables and to access them.
MatrixSet DS Layout Binding: LightSet DS Layout Binding: MiscSet DS Layout Binding: TexSamplerSet DS Layout Binding:
VkResult
Init13DescriptorSetLayouts( )
{
     VkResult result;
    //DS #0:
    VkDescriptorSetLayoutBinding         MatrixSet[1];
         MatrixSet[0].binding       = 0;
         MatrixSet[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
         MatrixSet[0].descriptorCount = 1;
         MatrixSet[0].stageFlags      = VK_SHADER_STAGE_VERTEX_BIT;
         MatrixSet[0].pImmutableSamplers = (VkSampler *)nullptr;
    // DS #1:
    VkDescriptorSetLayoutBinding         LightSet[1];
         LightSet[0].binding       = 0;
         LightSet[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
         LightSet[0].descriptorCount = 1;
         LightSet[0].stageFlags      = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
         LightSet[0].pImmutableSamplers = (VkSampler *)nullptr;
    //DS #2:
    VkDescriptorSetLayoutBinding        MiscSet[1];
         MiscSet[0].binding       = 0;
         MiscSet[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
         MiscSet[0].descriptorCount = 1;
         MiscSet[0].stageFlags      = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT;
         MiscSet[0].pImmutableSamplers = (VkSampler *)nullptr;
    // DS #3:
    VkDescriptorSetLayoutBinding        TexSamplerSet[1];
         TexSamplerSet[0].binding       = 0;
         TexSamplerSet[0].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
         TexSamplerSet[0].descriptorCount = 1;
         TexSamplerSet[0].stageFlags      = VK_SHADER_STAGE_FRAGMENT_BIT;    uniform sampler2D uSampler;
         TexSamplerSet[0].pImmutableSamplers = (VkSampler *)nullptr;         vec4 rgba = texture( uSampler, vST );
MatrixSet DS Layout Binding:   LightSet DS Layout Binding:   MiscSet DS Layout Binding: TexSamplerSet DS Layout Binding:
         binding                        binding                       binding                      binding
     descriptorType                 descriptorType                descriptorType               descriptorType
    descriptorCount                descriptorCount               descriptorCount              descriptorCount
    pipeline stage(s)              pipeline stage(s)             pipeline stage(s)            pipeline stage(s)
  set = 0                        set = 1                       set = 2                      set = 3
vdslc0 DS Layout CI: vdslc1 DS Layout CI: vdslc2 DS Layout CI: vdslc3 DS Layout CI:
                                                Array of Descriptor
                                                   Set Layouts
Pipeline Layout
    VkDescriptorSetLayoutCreateInfo      vdslc1;
        vdslc1.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        vdslc1.pNext = nullptr;
        vdslc1.flags = 0;
        vdslc1.bindingCount = 1;
        vdslc1.pBindings = &LightSet[0];
    VkDescriptorSetLayoutCreateInfo     vdslc2;
        vdslc2.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        vdslc2.pNext = nullptr;
        vdslc2.flags = 0;
        vdslc2.bindingCount = 1;
        vdslc2.pBindings = &MiscSet[0];
    VkDescriptorSetLayoutCreateInfo        vdslc3;
        vdslc3.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
        vdslc3.pNext = nullptr;
        vdslc3.flags = 0;
        vdslc3.bindingCount = 1;
        vdslc3.pBindings = &TexSamplerSet[0];
    return result;
}
VkResult
Init14GraphicsPipelineLayout( )
{
     VkResult result;
    VkPipelineLayoutCreateInfo            vplci;
        vplci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
        vplci.pNext = nullptr;
        vplci.flags = 0;
        vplci.setLayoutCount = 4;
        vplci.pSetLayouts = &DescriptorSetLayouts[0];
        vplci.pushConstantRangeCount = 0;
        vplci.pPushConstantRanges = (VkPushConstantRange *)nullptr;
    return result;
}
 DescriptorSetPool
                                       descriptorSetCount   DescriptorSetLayouts
VkDescriptorSetAllocateInfo
vkAllocateDescriptorSets( )
Descriptor Set
VkResult
Init13DescriptorSets( )
{
     VkResult result;
    VkDescriptorSetAllocateInfo        vdsai;
        vdsai.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
        vdsai.pNext = nullptr;
        vdsai.descriptorPool = DescriptorPool;
        vdsai.descriptorSetCount = 4;
        vdsai.pSetLayouts = DescriptorSetLayouts;
VkDescriptorBufferInfo               vdbi1;
    vdbi1.buffer = MyLightUniformBuffer.buffer;     This struct identifies what buffer it
    vdbi1.offset = 0;                               owns and how big it is
    vdbi1.range = sizeof(Light);
uint32_t copyCount = 0;
// this could have been done with one call and an array of VkWriteDescriptorSets:
VkGraphicsPipelineCreateInfo                   vgpci;
         vgpci.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
         vgpci.pNext = nullptr;
         vgpci.flags = 0;
#ifdef CHOICES
VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT
VK_PIPELINE_CREATE_ALLOW_DERIVATIVES_BIT
VK_PIPELINE_CREATE_DERIVATIVE_BIT
#endif
         vgpci.stageCount = 2;                   // number of stages in this pipeline
         vgpci.pStages = vpssci;
         vgpci.pVertexInputState = &vpvisci;
         vgpci.pInputAssemblyState = &vpiasci;
         vgpci.pTessellationState = (VkPipelineTessellationStateCreateInfo *)nullptr;
         vgpci.pViewportState = &vpvsci;
         vgpci.pRasterizationState = &vprsci;
         vgpci.pMultisampleState = &vpmsci;
         vgpci.pDepthStencilState = &vpdssci;
         vgpci.pColorBlendState = &vpcbsci;
         vgpci.pDynamicState = &vpdsci;
         vgpci.layout = IN GraphicsPipelineLayout;
         vgpci.renderPass = IN RenderPass;
         vgpci.subpass = 0;                    // subpass number
         vgpci.basePipelineHandle = (VkPipeline) VK_NULL_HANDLE;
         vgpci.basePipelineIndex = 0;
Descriptor Set
                                                             graphicsPipelineLayout   descriptorSetCount
                    pipelineBindPoint
cmdBuffer descriptorSets
vkCmdBindDescriptorSets( )
      vkCmdBindDescriptorSets( CommandBuffers[nextImageIndex],
                VK_PIPELINE_BIND_POINT_GRAPHICS, GraphicsPipelineLayout,
                0, 4, DescriptorSets, 0, (uint32_t *)nullptr );
So, the Pipeline Layout contains the structure of the Descriptor Sets.
Any collection of Descriptor Sets that match that structure can be bound into that pipeline.
 VkDescriptorPoolCreateInfo
                                                      Create the pool of Descriptor
     vkCreateDescriptorPool( )                        Sets for future use
VkDescriptorSetLayoutBinding
    VkDescriptorSetLayoutCreateInfo                   Describe a particular Descriptor
        vkCreateDescriptorSetLayout( )                Set layout and use it in a specific
                                                      Pipeline layout
           vkCreatePipelineLayout( )
vkUpdateDescriptorSets( )
The pieces of the Pipeline Data Structure are fixed in size – with the exception of the
Descriptor Sets and the Push Constants. Each of these two can be any size, depending on
what you allocate for them. So, the Pipeline Data Structure needs to know how these two
are configured before it can set its own total layout.
Think of the DS layout as being a particular-sized hole in the Pipeline Data Structure. Any
data you have that matches this hole’s shape and size can be plugged in there.
Any set of data that matches the Descriptor Set Layout can be plugged in there.
Textures
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
    // vertex #2:
    {
          { -1., 1., -1. },
          { 0., 0., -1. },
          { 0., 1., 0. },
          { 1., 1. }
    },
    // vertex #3:
    {
          { 1., 1., -1. },
          { 0., 0., -1. },
          { 1., 1., 0. },
          { 0., 1. }
    },
                        Host              Device
                       Visible            Local
                     GPU Memory         GPU Memory
         memcpy( )       vkCmdCopyImage( )
                                           Texture
                                      Sampling Hardware
11 Memory Types:
Memory 0:
Memory 1:
Memory 2:
Memory 3:
Memory 4:
Memory 5:
Memory 6:
Memory 7: DeviceLocal
Memory 8: DeviceLocal
Memory 9: HostVisible HostCoherent
Memory 10: HostVisible HostCoherent HostCached
3 Memory Types:
Memory 0: DeviceLocal
Memory 1: DeviceLocal HostVisible HostCoherent
Memory 2: DeviceLocal HostVisible HostCoherent HostCached
                                                                   OpenGL
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
                                                                      Vulkan
VkSamplerCreateInfo                    vsci;
        vsci.magFilter = VK_FILTER_LINEAR;
        vsci.minFilter = VK_FILTER_LINEAR;
        vsci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
        vsci.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        vsci.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
        vsci.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
...
As an object gets farther away and covers a smaller and smaller part of the screen, the texels
: pixels ratio used in the coverage becomes larger and larger. This means that there are
pieces of the texture leftover in between the pixels that are being drawn into, so that some of
the texture image is not being taken into account in the final image. This means that the
texture is being undersampled and could end up producing artifacts in the rendered image.
                 Texels
Pixels
Consider a texture that consists of one red texel and all the rest white. It is easy to imagine an
object rendered with that texture as ending up all white, with the red texel having never been
included in the final image. The solution is to create lower-resolutions of the same texture so
that the red texel gets included somehow in all resolution-level textures.
         Average 4 pixels to
         make a new one
                                           Average 4 pixels to
     RGBA, RGBA, RGBA, RGBA, RGBA,         make a new one
     RGBA, RGBA, RGBA, RGBA, RGBA,
     RGBA, RGBA,RGBA, RGBA, RGBA,
     RGBA, RGBA, RGBA, RGBA, RGBA,
     RGBA, RGBA, RGBA, RGBA, RGBA,                                   Average 4 pixels to
                                                                     make a new one
     RGBA, RGBA,RGBA, RGBA, RGBA,
     RGBA, RGBA, RGBA, RGBA, RGBA,
     RGBA, RGBA, RGBA, RGBA, RGBA,
     RGBA, RGBA, RGBA, RGBA, RGBA,
• Graphics hardware determines which level to use based on the texels : pixels ratio.
• In addition to just picking one mip-map level, the rendering system can sample from
  two of them, one less that the T:P ratio and one more, and then blend the two RGBAs
  returned. This is known as VK_SAMPLER_MIPMAP_MODE_LINEAR.
                                                 * Latin: multim in parvo, “many things in a small place”
                                                                                                            mjb – July 24, 2020
                                                                                                                       178
VkResult
Init07TextureSampler( MyTexture * pMyTexture )
{
     VkResult result;
     VkSamplerCreateInfo                     vsci;
         vsci.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
         vsci.pNext = nullptr;
         vsci.flags = 0;
         vsci.magFilter = VK_FILTER_LINEAR;
         vsci.minFilter = VK_FILTER_LINEAR;
         vsci.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
         vsci.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT;
         vsci.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT;
         vsci.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
#ifdef CHOICES
VK_SAMPLER_ADDRESS_MODE_REPEAT
VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE
VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER
VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE
#endif
         vsci.mipLodBias = 0.;
         vsci.anisotropyEnable = VK_FALSE;
         vsci.maxAnisotropy = 1.;
         vsci.compareEnable = VK_FALSE;
         vsci.compareOp = VK_COMPARE_OP_NEVER;
#ifdef CHOICES
VK_COMPARE_OP_NEVER
VK_COMPARE_OP_LESS
VK_COMPARE_OP_EQUAL
VK_COMPARE_OP_LESS_OR_EQUAL
VK_COMPARE_OP_GREATER
VK_COMPARE_OP_NOT_EQUAL
VK_COMPARE_OP_GREATER_OR_EQUAL
VK_COMPARE_OP_ALWAYS
#endif
         vsci.minLod = 0.;
         vsci.maxLod = 0.;
         vsci.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
#ifdef CHOICES
VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK
VK_BORDER_COLOR_INT_TRANSPARENT_BLACK
VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK
VK_BORDER_COLOR_INT_OPAQUE_BLACK
VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE
VK_BORDER_COLOR_INT_OPAQUE_WHITE
#endif
         vsci.unnormalizedCoordinates = VK_FALSE;    // VK_TRUE means we are use raw texels as the index
                                     // VK_FALSE means we are using the usual 0. - 1.
     VkImage stagingImage;
     VkImage textureImage;
     // *******************************************************************************
     // this first {...} is to create the staging image:
     // *******************************************************************************
     {
            VkImageCreateInfo                      vici;
                   vici.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
                   vici.pNext = nullptr;
                   vici.flags = 0;
                  vici.imageType = VK_IMAGE_TYPE_2D;
                   vici.format = VK_FORMAT_R8G8B8A8_UNORM;
                   vici.extent.width = texWidth;
                   vici.extent.height = texHeight;
                   vici.extent.depth = 1;
                   vici.mipLevels = 1;
                   vici.arrayLayers = 1;
                   vici.samples = VK_SAMPLE_COUNT_1_BIT;
                   vici.tiling = VK_IMAGE_TILING_LINEAR;
#ifdef CHOICES
VK_IMAGE_TILING_OPTIMAL
VK_IMAGE_TILING_LINEAR
#endif
                   vici.usage = VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
#ifdef CHOICES
VK_IMAGE_USAGE_TRANSFER_SRC_BIT
VK_IMAGE_USAGE_TRANSFER_DST_BIT
VK_IMAGE_USAGE_SAMPLED_BIT
VK_IMAGE_USAGE_STORAGE_BIT
VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT
VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT
VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT
#endif
                   vici.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
result = vkCreateImage(LogicalDevice, IN &vici, PALLOCATOR, OUT &stagingImage); // allocated, but not filled
         VkMemoryRequirements         vmr;
         vkGetImageMemoryRequirements( LogicalDevice, IN stagingImage, OUT &vmr);
         if (Verbose)
         {
               fprintf(FpDebug, "Image vmr.size = %lld\n", vmr.size);
               fprintf(FpDebug, "Image vmr.alignment = %lld\n", vmr.alignment);
               fprintf(FpDebug, "Image vmr.memoryTypeBits = 0x%08x\n", vmr.memoryTypeBits);
               fflush(FpDebug);
         }
         VkMemoryAllocateInfo             vmai;
            vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
            vmai.pNext = nullptr;
            vmai.allocationSize = vmr.size;
            vmai.memoryTypeIndex = FindMemoryThatIsHostVisible(); // because we want to mmap it
         VkDeviceMemory                 vdm;
         result = vkAllocateMemory( LogicalDevice, IN &vmai, PALLOCATOR, OUT &vdm);
         pMyTexture->vdm = vdm;
// we have now created the staging image -- fill it with the pixel data:
         VkImageSubresource            vis;
             vis.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
             vis.mipLevel = 0;
             vis.arrayLayer = 0;
         VkSubresourceLayout          vsl;
         vkGetImageSubresourceLayout( LogicalDevice, stagingImage, IN &vis, OUT &vsl);
         if (Verbose)
         {
               fprintf(FpDebug, "Subresource Layout:\n");
               fprintf(FpDebug, "\toffset = %lld\n", vsl.offset);
               fprintf(FpDebug, "\tsize = %lld\n", vsl.size);
               fprintf(FpDebug, "\trowPitch = %lld\n", vsl.rowPitch);
               fprintf(FpDebug, "\tarrayPitch = %lld\n", vsl.arrayPitch);
               fprintf(FpDebug, "\tdepthPitch = %lld\n", vsl.depthPitch);
               fflush(FpDebug);
         |
     void * gpuMemory;
     vkMapMemory( LogicalDevice, vdm, 0, VK_WHOLE_SIZE, 0, OUT &gpuMemory);
                          // 0 and 0 = offset and memory map flags
     if (vsl.rowPitch == 4 * texWidth)
     {
            memcpy(gpuMemory, (void *)texture, (size_t)textureSize);
     }
     else
     {
            unsigned char *gpuBytes = (unsigned char *)gpuMemory;
            for (unsigned int y = 0; y < texHeight; y++)
            {
                  memcpy(&gpuBytes[y * vsl.rowPitch], &texture[4 * y * texWidth], (size_t)(4*texWidth) );
            }
     }
}
// *******************************************************************************
result = vkCreateImage(LogicalDevice, IN &vici, PALLOCATOR, OUT &textureImage); // allocated, but not filled
     VkMemoryRequirements         vmr;
     vkGetImageMemoryRequirements( LogicalDevice, IN textureImage, OUT &vmr);
    if( Verbose )
    {
          fprintf( FpDebug, "Texture vmr.size = %lld\n", vmr.size );
          fprintf( FpDebug, "Texture vmr.alignment = %lld\n", vmr.alignment );
          fprintf( FpDebug, "Texture vmr.memoryTypeBits = 0x%08x\n", vmr.memoryTypeBits );
          fflush( FpDebug );
    }
    VkMemoryAllocateInfo               vmai;
          vmai.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
          vmai.pNext = nullptr;
          vmai.allocationSize = vmr.size;
          vmai.memoryTypeIndex = FindMemoryThatIsDeviceLocal( ); // because we want to sample from it
     VkDeviceMemory                 vdm;
     result = vkAllocateMemory( LogicalDevice, IN &vmai, PALLOCATOR, OUT &vdm);
VkCommandBufferBeginInfo           vcbbi;
    vcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
    vcbbi.pNext = nullptr;
    vcbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
    vcbbi.pInheritanceInfo = (VkCommandBufferInheritanceInfo *)nullptr;
// *******************************************************************************
// transition the staging buffer layout:
// *******************************************************************************
{
       VkImageSubresourceRange                     visr;
            visr.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
            visr.baseMipLevel = 0;
            visr.levelCount = 1;
            visr.baseArrayLayer = 0;
            visr.layerCount = 1;
     VkImageMemoryBarrier              vimb;
         vimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
         vimb.pNext = nullptr;
         vimb.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
         vimb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL;
         vimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
         vimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
         vimb.image = stagingImage;
         vimb.srcAccessMask = VK_ACCESS_HOST_WRITE_BIT;
         vimb.dstAccessMask = 0;
         vimb.subresourceRange = visr;
      vkCmdPipelineBarrier( TextureCommandBuffer,
             VK_PIPELINE_STAGE_HOST_BIT, VK_PIPELINE_STAGE_HOST_BIT, 0,
             0, (VkMemoryBarrier *)nullptr,
             0, (VkBufferMemoryBarrier *)nullptr,
             1, IN &vimb );
}
// *******************************************************************************
     VkImageMemoryBarrier              vimb;
         vimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
         vimb.pNext = nullptr;
         vimb.oldLayout = VK_IMAGE_LAYOUT_PREINITIALIZED;
         vimb.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
         vimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
         vimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
         vimb.image = textureImage;
         vimb.srcAccessMask = 0;
         vimb.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
         vimb.subresourceRange = visr;
     vkCmdPipelineBarrier( TextureCommandBuffer,
        VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0,
        0, (VkMemoryBarrier *)nullptr,
        0, (VkBufferMemoryBarrier *)nullptr,
        1, IN &vimb);
     VkImageSubresourceLayers        visl;
         visl.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
         visl.baseArrayLayer = 0;
         visl.mipLevel = 0;
         visl.layerCount = 1;
     VkOffset3D                         vo3;
         vo3.x = 0;
         vo3.y = 0;
         vo3.z = 0;
     VkExtent3D                          ve3;
         ve3.width = texWidth;
         ve3.height = texHeight;
         ve3.depth = 1;
                                                                                     mjb – July 24, 2020
                                                                                                 185
     VkImageCopy                    vic;
         vic.srcSubresource = visl;
         vic.srcOffset = vo3;
         vic.dstSubresource = visl;
         vic.dstOffset = vo3;
         vic.extent = ve3;
     vkCmdCopyImage(TextureCommandBuffer,
        stagingImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
        textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, IN &vic);
}
// *******************************************************************************
           VkImageMemoryBarrier              vimb;
               vimb.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
               vimb.pNext = nullptr;
               vimb.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
               vimb.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
               vimb.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
               vimb.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
               vimb.image = textureImage;
               vimb.srcAccessMask = 0;
               vimb.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
               vimb.subresourceRange = visr;
           vkCmdPipelineBarrier(TextureCommandBuffer,
               VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0,
               0, (VkMemoryBarrier *)nullptr,
               0, (VkBufferMemoryBarrier *)nullptr,
               1, IN &vimb);
     }
     // *******************************************************************************
     VkSubmitInfo               vsi;
         vsi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
         vsi.pNext = nullptr;
         vsi.commandBufferCount = 1;
         vsi.pCommandBuffers = &TextureCommandBuffer;
         vsi.waitSemaphoreCount = 0;
         vsi.pWaitSemaphores = (VkSemaphore *)nullptr;
         vsi.signalSemaphoreCount = 0;
         vsi.pSignalSemaphores = (VkSemaphore *)nullptr;
         vsi.pWaitDstStageMask = (VkPipelineStageFlags *)nullptr;
    VkImageViewCreateInfo              vivci;
        vivci.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
        vivci.pNext = nullptr;
        vivci.flags = 0;
        vivci.image = textureImage;                        8 bits Red                8 bits Green       8 bits Blue    8 bits Alpha
        vivci.viewType = VK_IMAGE_VIEW_TYPE_2D;
        vivci.format = VK_FORMAT_R8G8B8A8_UNORM;
        vivci.components.r = VK_COMPONENT_SWIZZLE_R;
        vivci.components.g = VK_COMPONENT_SWIZZLE_G;
        vivci.components.b = VK_COMPONENT_SWIZZLE_B;
        vivci.components.a = VK_COMPONENT_SWIZZLE_A;
        vivci.subresourceRange = visr;
    return result;
}
                Note that, at this point, the Staging Buffer is no longer needed, and can be destroyed.
                                                                                                                                 mjb – July 24, 2020
                                           Reading in a Texture from a BMP File                                188
•••
MyTexture MyPuppyTexture;
This function can be found in the sample.cpp file. The BMP file needs to be created by something
that writes uncompressed 24-bit color BMP files, or was converted to the uncompressed BMP format
by a tool such as ImageMagick’s convert, Adobe Photoshop, or GNU’s GIMP.
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
Application
Instance
       Physical
        Device
       Logical
       Device
                    Command Buffer
          Queue
Command Buffer
Command Buffer
• Command Buffers record commands, but no work takes place until a Command Buffer is submitted to a Queue
• We don’t create Queue Families – the Physical Device already has them
uint32_t count;
vkGetPhysicalDeviceQueueFamilyProperties( IN PhysicalDevice, &count, OUT (VkQueueFamilyProperties *) nullptr );
int
FindQueueFamilyThatDoesGraphics( )
{
    uint32_t count = -1;
    vkGetPhysicalDeviceQueueFamilyProperties( IN PhysicalDevice, OUT &count, OUT (VkQueueFamilyProperties *)nullptr );
 float queuePriorities[ ] =
{
          1.                // one entry per queueCount
};
VkDeviceQueueCreateInfo vdqci[1];
     vdqci[0].sType = VK_STRUCTURE_TYPE_QUEUE_CREATE_INFO;
     vdqci[0].pNext = nullptr;
     vdqci[0].flags = 0;
     vdqci[0].queueFamilyIndex = FindQueueFamilyThatDoesGraphics( );
     vdqci[0].queueCount = 1;
     vdqci[0].queuePriorities = (float *) queuePriorities;
VkDeviceCreateInfo vdci;
        vdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
        vdci.pNext = nullptr;
        vdci.flags = 0;
        vdci.queueCreateInfoCount = 1;             // # of device queues wanted
        vdci.pQueueCreateInfos = IN &vdqci[0];     // array of VkDeviceQueueCreateInfo's
        vdci.enabledLayerCount = sizeof(myDeviceLayers) / sizeof(char *);
        vdci.ppEnabledLayerNames = myDeviceLayers;
        vdci.enabledExtensionCount = sizeof(myDeviceExtensions) / sizeof(char *);
        vdci.ppEnabledExtensionNames = myDeviceExtensions;
        vdci.pEnabledFeatures = IN &PhysicalDeviceFeatures; // already created
VkQueue Queue;
uint32_t queueFamilyIndex = FindQueueFamilyThatDoesGraphics( );
uint32_t queueIndex = 0;
VkResult
Init06CommandPool( )
{
     VkResult result;
     VkCommandPoolCreateInfo                vcpci;
         vcpci.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
         vcpci.pNext = nullptr;
         vcpci.flags =     VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
                       | VK_COMMAND_POOL_CREATE_TRANSIENT_BIT;
#ifdef CHOICES
VK_COMMAND_POOL_CREATE_TRANSIENT_BIT
VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT
#endif
         vcpci.queueFamilyIndex = FindQueueFamilyThatDoesGraphics( );
    return result;
}
VkResult
Init06CommandBuffers( )
{
     VkResult result;
    {
         VkCommandBufferAllocateInfo          vcbai;
             vcbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
             vcbai.pNext = nullptr;
             vcbai.commandPool = CommandPool;
             vcbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
             vcbai.commandBufferCount = 2;    // 2, because of double-buffering
// allocate 1 command buffer for the transferring pixels from a staging buffer to a texture buffer:
    {
         VkCommandBufferAllocateInfo          vcbai;
             vcbai.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
             vcbai.pNext = nullptr;
             vcbai.commandPool = CommandPool;
             vcbai.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
             vcbai.commandBufferCount = 1;
    return result;
}
                                                                                                          mjb – July 24, 2020
                          Beginning a Command Buffer – One per Image                                       197
VkSemaphoreCreateInfo           vsci;
    vsci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    vsci.pNext = nullptr;
    vsci.flags = 0;
VkSemaphore imageReadySemaphore;
result = vkCreateSemaphore( LogicalDevice, IN &vsci, PALLOCATOR, OUT &imageReadySemaphore );
uint32_t nextImageIndex;
vkAcquireNextImageKHR( LogicalDevice, IN SwapChain, IN UINT64_MAX,
                         IN imageReadySemaphore, IN VK_NULL_HANDLE, OUT &nextImageIndex );
VkCommandBufferBeginInfo           vcbbi;
       vcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
       vcbbi.pNext = nullptr;
       vcbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
       vcbbi.pInheritanceInfo = (VkCommandBufferInheritanceInfo *)nullptr;
...
vkEndCommandBuffer( CommandBuffers[nextImageIndex] );
VkCommandBufferPoolCreateInfo
vkCreateCommandBufferPool( )
VkCommandBufferAllocateInfo
VkCommandBufferBeginInfo vkAllocateCommandBuffer( )
vkBeginCommandBuffer( )
VkResult
RenderScene( )
{
    VkResult result;
    VkSemaphoreCreateInfo        vsci;
     vsci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
     vsci.pNext = nullptr;
     vsci.flags = 0;
   VkSemaphore imageReadySemaphore;
   result = vkCreateSemaphore( LogicalDevice, IN &vsci, PALLOCATOR, OUT &imageReadySemaphore );
   uint32_t nextImageIndex;
   vkAcquireNextImageKHR( LogicalDevice, IN SwapChain, IN UINT64_MAX, IN VK_NULL_HANDLE,
                            IN VK_NULL_HANDLE, OUT &nextImageIndex );
   VkCommandBufferBeginInfo           vcbbi;
       vcbbi.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
       vcbbi.pNext = nullptr;
       vcbbi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
       vcbbi.pInheritanceInfo = (VkCommandBufferInheritanceInfo *)nullptr;
VkClearColorValue               vccv;
    vccv.float32[0] = 0.0;
    vccv.float32[1] = 0.0;
    vccv.float32[2] = 0.0;
    vccv.float32[3] = 1.0;
VkClearDepthStencilValue              vcdsv;
    vcdsv.depth = 1.f;
    vcdsv.stencil = 0;
VkClearValue                  vcv[2];
    vcv[0].color = vccv;
    vcv[1].depthStencil = vcdsv;
VkOffset2D o2d = { 0, 0 };
VkExtent2D e2d = { Width, Height };
VkRect2D r2d = { o2d, e2d };
VkRenderPassBeginInfo                     vrpbi;
    vrpbi.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
    vrpbi.pNext = nullptr;
    vrpbi.renderPass = RenderPass;
    vrpbi.framebuffer = Framebuffers[ nextImageIndex ];
    vrpbi.renderArea = r2d;
    vrpbi.clearValueCount = 2;
    vrpbi.pClearValues = vcv;          // used for VK_ATTACHMENT_LOAD_OP_CLEAR
VkRect2D scissor =
{
    0,
    0,
    Width,
    Height
};
VkDeviceSize offsets[1] = { 0 };
vkCmdEndRenderPass( CommandBuffers[nextImageIndex] );
vkEndCommandBuffer( CommandBuffers[nextImageIndex] );
                                                                                                                                  mjb – July 24, 2020
 Submitting a Command Buffer to a Queue for Execution                           204
VkSubmitInfo                  vsi;
         vsi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
         vsi.pNext = nullptr;
         vsi.commandBufferCount = 1;
         vsi.pCommandBuffers = &CommandBuffer;
         vsi.waitSemaphoreCount = 1;
         vsi.pWaitSemaphores = imageReadySemaphore;
         vsi.signalSemaphoreCount = 0;
         vsi.pSignalSemaphores = (VkSemaphore *)nullptr;
         vsi.pWaitDstStageMask = (VkPipelineStageFlags *)nullptr;
VkFence renderFence;
vkCreateFence( LogicalDevice, IN &vfci, PALLOCATOR, OUT &renderFence );
result = VK_SUCCESS;
VkSubmitInfo               vsi;
    vsi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
    vsi.pNext = nullptr;
    vsi.waitSemaphoreCount = 1;
    vsi.pWaitSemaphores = &imageReadySemaphore;
    vsi.pWaitDstStageMask = &waitAtBottom;
    vsi.commandBufferCount = 1;
    vsi.pCommandBuffers = &CommandBuffers[nextImageIndex];
    vsi.signalSemaphoreCount = 0;
    vsi.pSignalSemaphores = &SemaphoreRenderFinished;
VkPresentInfoKHR                        vpi;
    vpi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
    vpi.pNext = nullptr;
    vpi.waitSemaphoreCount = 0;
    vpi.pWaitSemaphores = (VkSemaphore *)nullptr;
    vpi.swapchainCount = 1;
    vpi.pSwapchains = &SwapChain;
    vpi.pImageIndices = &nextImageIndex;
    vpi.pResults = (VkResult *)nullptr;
“Command buffer submissions to a single queue respect submission order and other
implicit ordering guarantees, but otherwise may overlap or execute out of order. Other
types of batches and queue submissions against a single queue (e.g. sparse memory
binding) have no implicit ordering constraints with any other queue submission or
batch. Additional explicit ordering constraints between queue submissions and
individual batches can be expressed with semaphores and fences.”
In other words, the Vulkan driver on your system will execute the commands in a single buffer in
the order in which they were put there.
But, between different command buffers submitted to different queues, the driver is allowed to
execute commands between buffers in-order or out-of-order or overlapped-order, depending on
what it thinks it can get away with.
The message here is, I think, always consider using some sort of Vulkan synchronization when
one command depends on a previous command reaching a certain state first.
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
                       Back                                   Back
Update
Depth
Back
Present
Front
Vulkan does not use the idea of a “back buffer”. So, we need a place to render into
before moving an image into place for viewing. The is called the Swap Chain.
In essence, the Swap Chain manages one or more image objects that form a sequence
of images that can be drawn into and then given to the Surface to be presented to the
user for viewing.
After creating the Swap Chain in the first place, the process for using the Swap Chain is:
VkSurfaceCapabilitiesKHR            vsc;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( PhysicalDevice, Surface, OUT &vsc );
VkExtent2D surfaceRes = vsc.currentExtent;
fprintf( FpDebug, "\nvkGetPhysicalDeviceSurfaceCapabilitiesKHR:\n" );
...
VkBool32 supported;
result = vkGetPhysicalDeviceSurfaceSupportKHR( PhysicalDevice, FindQueueFamilyThatDoesGraphics( ), Surface, &supported );
if( supported == VK_TRUE )
       fprintf( FpDebug, "** This Surface is supported by the Graphics Queue **\n" );
uint32_t formatCount;
vkGetPhysicalDeviceSurfaceFormatsKHR( PhysicalDevice, Surface, &formatCount, (VkSurfaceFormatKHR *) nullptr );
VkSurfaceFormatKHR * surfaceFormats = new VkSurfaceFormatKHR[ formatCount ];
vkGetPhysicalDeviceSurfaceFormatsKHR( PhysicalDevice, Surface, &formatCount, surfaceFormats );
fprintf( FpDebug, "\nFound %d Surface Formats:\n", formatCount )
...
uint32_t presentModeCount;
vkGetPhysicalDeviceSurfacePresentModesKHR( PhysicalDevice, Surface, &presentModeCount, (VkPresentModeKHR *) nullptr );
VkPresentModeKHR * presentModes = new VkPresentModeKHR[ presentModeCount ];
vkGetPhysicalDeviceSurfacePresentModesKHR( PhysicalDevice, Surface, &presentModeCount, presentModes );
fprintf( FpDebug, "\nFound %d Present Modes:\n", presentModeCount );
     ...
                                                                                                                            mjb – July 24, 2020
                We Need to Find Out What our Display Capabilities Are                                     212
VulkanDebug.txt output:
vkGetPhysicalDeviceSurfaceCapabilitiesKHR:
    minImageCount = 2 ; maxImageCount = 8
    currentExtent = 1024 x 1024
    minImageExtent = 1024 x 1024
    maxImageExtent = 1024 x 1024
    maxImageArrayLayers = 1
    supportedTransforms = 0x0001
    currentTransform = 0x0001
    supportedCompositeAlpha = 0x0001
    supportedUsageFlags = 0x009f
vkGetDevicePhysicalSurfaceCapabilities( )
VkSurfaceCapabilities
      surface                              minImageCount
   imageFormat                            maxImageCount
 imageColorSpace                            currentExtent
    imageExtent                           minImageExtent
 imageArrayLayers                         maxImageExtent
    imageUsage                          maxImageArrayLayers
imageSharingMode                        supportedTransforms
   preTransform                           currentTransform
  compositeAlpha                      supportedCompositeAlpha
   presentMode
      clipped
VkSwapchainCreateInfo
vkCreateSwapchain( )
vkGetSwapChainImages( )
vkCreateImageView( )
VkSurfaceCapabilitiesKHR          vsc;
vkGetPhysicalDeviceSurfaceCapabilitiesKHR( PhysicalDevice, Surface, OUT &vsc );
VkExtent2D surfaceRes = vsc.currentExtent;
VkSwapchainCreateInfoKHR           vscci;
       vscci.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
       vscci.pNext = nullptr;
       vscci.flags = 0;
       vscci.surface = Surface;
       vscci.minImageCount = 2;               // double buffering
       vscci.imageFormat = VK_FORMAT_B8G8R8A8_UNORM;
       vscci.imageColorSpace = VK_COLORSPACE_SRGB_NONLINEAR_KHR;
       vscci.imageExtent.width = surfaceRes.width;
       vscci.imageExtent.height = surfaceRes.height;
       vscci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
       vscci.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
       vscci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
       vscci.imageArrayLayers = 1;
       vscci.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
       vscci.queueFamilyIndexCount = 0;
       vscci.pQueueFamilyIndices = (const uint32_t *)nullptr;
       vscci.presentMode = VK_PRESENT_MODE_MAILBOX_KHR;
       vscci.oldSwapchain = VK_NULL_HANDLE;
       vscci.clipped = VK_TRUE;
VkSemaphoreCreateInfo        vsci;
    vsci.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
    vsci.pNext = nullptr;
    vsci.flags = 0;
VkSemaphore imageReadySemaphore;
result = vkCreateSemaphore( LogicalDevice, IN &vsci, PALLOCATOR, OUT &imageReadySemaphore );
uint32_t nextImageIndex;
uint64_t tmeout = UINT64_MAX;
vkAcquireNextImageKHR( LogicalDevice, IN SwapChain, IN timeout, IN imageReadySemaphore,
                  IN VK_NULL_HANDLE, OUT &nextImageIndex );
     ...
...
...
VkFenceCreateInfo             vfci;
        vfci.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
        vfci.pNext = nullptr;
        vfci.flags = 0;
VkFence renderFence;
vkCreateFence( LogicalDevice, &vfci, PALLOCATOR, OUT &renderFence );
VkQueue presentQueue;
vkGetDeviceQueue( LogicalDevice, FindQueueFamilyThatDoesGraphics( ), 0,
                   OUT &presentQueue );
...
VkSubmitInfo                  vsi;
         vsi.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
         vsi.pNext = nullptr;
         vsi.waitSemaphoreCount = 1;
         vsi.pWaitSemaphores = &imageReadySemaphore;
         vsi.pWaitDstStageMask = &waitAtBottom;
         vsi.commandBufferCount = 1;
         vsi.pCommandBuffers = &CommandBuffers[ nextImageIndex ];
         vsi.signalSemaphoreCount = 0;
         vsi.pSignalSemaphores = &SemaphoreRenderFinished;
VkPresentInfoKHR                      vpi;
         vpi.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
         vpi.pNext = nullptr;
         vpi.waitSemaphoreCount = 0;
         vpi.pWaitSemaphores = (VkSemaphore *)nullptr;
         vpi.swapchainCount = 1;
         vpi.pSwapchains = &SwapChain;
         vpi.pImageIndices = &nextImageIndex;
         vpi.pResults = (VkResult *) nullptr;
Push Constants
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
In an effort to expand flexibility and retain efficiency, Vulkan provides something called
Push Constants. Like the name implies, these let you “push” constant values out to the
shaders. These are typically used for small, frequently-updated data values. This is good,
since Vulkan, at times, makes it cumbersome to send changes to the graphics.
By “small”, Vulkan specifies that these must be at least 128 bytes in size, although they
can be larger. For example, the maximum size is 256 bytes on the NVIDIA 1080ti. (You
can query this limit by looking at the maxPushConstantSize parameter in the
VkPhysicalDeviceLimits structure.) Unlike uniform buffers and vertex buffers, these are
not backed by memory. They are actually part of the Vulkan pipeline.
                                                                                                           VkVertexInputAttributeDescription
                                    VkPipelineShaderStageCreateInfo
                                                               VkPipelineVertexInputStateCreateInfo
                                                                                                                         Topology
                   Shaders                                       VkPipelineInputAssemblyStateCreateInfo
               VertexInput State
                                                                                                                                    x, y, w, h,
             InputAssembly State
                                                                                                       Viewport                     minDepth,
               Tesselation State                               VkViewportStateCreateInfo
                                                                                                                                    maxDepth
                Viewport State
              Rasterization State                                                                      Scissor
                                                   VkPipelineRasterizationStateCreateInfo                                       offset
              MultiSample State
              DepthStencil State                                                                                                extent
                                                  VkPipelineDepthStencilStateCreateInfo                  cullMode
               ColorBlend State
                                                                                                       polygonMode
                Dynamic State
                                                                                                         frontFace
                Pipeline layout
                                                                                                         lineWidth
                 RenderPass
             basePipelineHandle
              basePipelineIndex
                                                                                                           depthTestEnable
                                                   VkPipelineColorBlendStateCreateInfo                     depthWriteEnable
                                                                                                           depthCompareOp
           VkGraphicsPipelineCreateInfo                                                                    stencilTestEnable
                                                                                                          stencilOpStateFront
                                                                                                          stencilOpStateBack
                                                           VkPipelineColorBlendAttachmentState
                                                                                                                       blendEnable
                                                                                                                  srcColorBlendFactor
                       vkCreateGraphicsPipeline( )                                                                dstColorBlendFactor
                                                                                                                      colorBlendOp
                                                                                                                  srcAlphaBlendFactor
                                                            VkPipelineDynamicStateCreateInfo                      dstAlphaBlendFactor
                                                                                                                      alphaBlendOp
                 Graphics Pipeline
                                                                                                                     colorWriteMask
                                                 Array naming the states that can be set dynamically
                                                                                                                                                  mjb – July 24, 2020
                                       Push Constants                                                             222
         On the shader side, if, for example, you are sending a 4x4 matrix, the use of push
         constants in the shader looks like this:
                        layout( push_constant ) uniform matrix
                        {
                            mat4 modelMatrix;
                        } Matrix;
where:
stageFlags are or’ed bits of VK_PIPELINE_STAGE_VERTEX_SHADER_BIT,
                         VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, etc.
size is in bytes
pValues is a void * pointer to the data, which, in this 4x4 matrix example, would be of type glm::mat4.
Prior to that, however, the pipeline layout needs to be told about the Push Constants:
VkPushConstantRange                    vpcr[1];
   vpcr[0].stageFlags =
             VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
            |VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
   vpcr[0].offset = 0;
   vpcr[0].size = sizeof( glm::mat4 );
VkPipelineLayoutCreateInfo                   vplci;
    vplci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
    vplci.pNext = nullptr;
    vplci.flags = 0;
    vplci.setLayoutCount = 4;
    vplci.pSetLayouts = DescriptorSetLayouts;
    vplci.pushConstantRangeCount = 1;
    vplci.pPushConstantRanges = vpcr;
3
2
1
Locations?
3 3
                                       2
                                               2
     1                                 1
Ground
1. Rotate by Θ1
2. Translate by T1/G
Write it
                        M 1/G   T1/G  *  R 1 
                                                      Say it
1. Rotate by Θ2
2. Translate the length of part 1
3. Rotate by Θ 1
4. Translate by T1/G
                                         Write it
1. Rotate by Θ3
2. Translate the length of part 2
3. Rotate by Θ2
4. Translate the length of part 1
5. Rotate by Θ1
6. Translate by T1/G
                                            Write it
                                                          Say it
                                                                           mjb – July 24, 2020
                             In the Reset Function                                                     231
...
      Arm1.armMatrix = glm::mat4( 1. );
      Arm1.armColor = glm::vec3( 0.f, 1.f, 0.f );
      Arm1.armScale = 6.f;
                                                     The constructor glm::mat4( 1. )
      Arm2.armMatrix = glm::mat4( 1. );              produces an identity matrix. The
      Arm2.armColor = glm::vec3( 1.f, 0.f, 0.f );    actual transformation matrices will
      Arm2.armScale = 4.f;                           be set in UpdateScene( ).
      Arm3.armMatrix = glm::mat4( 1. );
      Arm3.armColor = glm::vec3( 0.f, 0.f, 1.f );
      Arm3.armScale = 2.f;
VkPushConstantRange                     vpcr[1];
       vpcr[0].stageFlags =
                   VK_PIPELINE_STAGE_VERTEX_SHADER_BIT
                 | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
       vpcr[0].offset = 0;
       vpcr[0].size = sizeof( struct arm );
VkPipelineLayoutCreateInfo                   vplci;
          vplci.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
          vplci.pNext = nullptr;
          vplci.flags = 0;
          vplci.setLayoutCount = 4;
          vplci.pSetLayouts = DescriptorSetLayouts;
          vplci.pushConstantRangeCount = 1;
          vplci.pPushConstantRanges = vpcr;
                                                                 1
                                                                                                             mjb – July 24, 2020
                                   In the Vertex Shader                                                     235
...
...
Physical Devices
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
Application
Instance
                      Physical
                       Device
                      Logical
                      Device
                                   Command Buffer
                         Queue
Command Buffer
Command Buffer
 uint32_t count;
 result = vkEnumeratePhysicalDevices( Instance, OUT &count, OUT (VkPhysicalDevice *)nullptr );
This way of querying information is a recurring OpenCL and Vulkan pattern (get used to it):
VkPhysicalDeviceProperties PhysicalDeviceFeatures;
vkGetPhysicalDeviceFeatures( IN PhysicalDevice, OUT &PhysicalDeviceFeatures );
vkEnumeratePhysicalDevices:
Device 0:
    API version: 4198499
     Driver version: 4198499
     Vendor ID: 0x10de
     Device ID: 0x1e04
     Physical Device Type: 2 = (Discrete GPU)
     Device Name: RTX 2080 Ti
     Pipeline Cache Size: 206
Device #0 selected (‘RTX 2080 Ti')
vkEnumeratePhysicalDevices:
Device 0:
    API version: 4194360
     Driver version: 4194360
     Vendor ID: 0x8086
     Device ID: 0x1916
     Physical Device Type: 1 = (Integrated GPU)
     Device Name: Intel(R) HD Graphics 520
     Pipeline Cache Size: 213
Device #0 selected ('Intel(R) HD Graphics 520')
VkPhysicalDeviceMemoryProperties              vpdmp;
vkGetPhysicalDeviceMemoryProperties( PhysicalDevice, OUT &vpdmp );
11 Memory Types:
Memory 0:
Memory 1:
Memory 2:
Memory 3:
Memory 4:
Memory 5:
Memory 6:
Memory 7: DeviceLocal
Memory 8: DeviceLocal
Memory 9: HostVisible HostCoherent
Memory 10: HostVisible HostCoherent HostCached
2 Memory Heaps:
Heap 0: size = 0xb7c00000 DeviceLocal
Heap 1: size = 0xfac00000
Logical Devices
             Mike Bailey
         mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan
Application
Instance
                      Physical
                       Device
                      Logical
                      Device
                                   Command Buffer
                         Queue
Command Buffer
Command Buffer
uint32_t layerCount;
vkEnumerateDeviceLayerProperties(PhysicalDevice, &layerCount, (VkLayerProperties *)nullptr);
uint32_t extensionCount;
vkEnumerateDeviceExtensionProperties(PhysicalDevice, deviceLayers[i].layerName,
                                      &extensionCount, (VkExtensionProperties *)nullptr);
float queuePriorities[1] =
{
          1.
};
VkDeviceQueueCreateInfo vdqci;
      vdqci.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
      vdqci.pNext = nullptr;
      vdqci.flags = 0;
      vdqci.queueFamiltyIndex = 0;
      vdqci.queueCount = 1;
      vdqci.pQueueProperties = queuePriorities;
VkDeviceCreateInfo vdci;
        vdci.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
        vdci.pNext = nullptr;
        vdci.flags = 0;
        vdci.queueCreateInfoCount = 1;           // # of device queues
        vdci.pQueueCreateInfos = IN vdqci;       // array of VkDeviceQueueCreateInfo's
        vdci.enabledLayerCount = sizeof(myDeviceLayers) / sizeof(char *);
        vdci.enabledLayerCount = 0;
        vdci.ppEnabledLayerNames = myDeviceLayers;
        vdci.enabledExtensionCount = 0;
        vdci.ppEnabledExtensionNames = (const char **)nullptr;            // no extensons
        vdci.enabledExtensionCount = sizeof(myDeviceExtensions) / sizeof(char *);
        vdci.ppEnabledExtensionNames = myDeviceExtensions;
        vdci.pEnabledFeatures = IN &PhysicalDeviceFeatures;
Computer Graphics
                                                               Mike Bailey
                                                           mjb@cs.oregonstate.edu
http://cs.oregonstate.edu/~mjb/vulkan