|
Главная
Статьи
Ссылки
Скачать
Скриншоты
Юмор
Почитать
Tools
Проекты
Обо мне
Гостевая
Форум
|
Изначально когда Vulkan только придумывался, туда было добавлено многое из того, что не прошло проверку времени и оказалось слишком сложным, неудобным и не дающим ощутимого эффекта.
К числу таких возможностей были неизменяемые объекты-конвейеры (Vk*Pipeline).
Изначально идея была в том, что их использование поможет драйверу принимать более оптимальные решения заранее зная полную конфигурацию.
За счет этого планировалось перенести всю тяжесть поддержки множества различных комбинаций с драйвера на само приложение.
Также за счет этого планировалось заметно сократить время на валидацию. При этом предполагалось, что разработчики заранее могут определить все возможные комбинации состояния и занести их в объекты-конвейеры. Также считалось что цена, которую платит драйвер за эту абстракцию, окажется сильно меньше получаемого выигрыша.
Однако на практике оказалось, что пользы от них не так много, а вот сложностей более чем достаточно. В результате в приложениях стали плодится многочисленные объекты-конвейеры - для каждой используемой комбинации параметров/шейдеров пришлось создавать свой объект-конвейер.
И в результате оказалось, что код, для работы с кучей состояний, просто перешел из драйвера в многочисленные приложения. Цена перешла на постоянный bind-конвейеров, создавая значительную нагрузку. Стали возникать разнообразные хэши, где по требуемому состоянию искали соответствующий объект-конвейер. Более того, для некоторых IHV оказалось, что данная модель просто ограничивает возможности разработчика. Т.е. оказалось, что эта абстракция стала создавать многочисленные проблемы, не давая при этом четкого выигрыша. Ее использование затрудняло использование Vulkan, особенно для новичков.
В результате было принято радикальное решение вообще отказаться от концепции объекта-конвейера Vk*Pipeline,
представляющей по сути проблему для многих с самого появления Vulkan, перейдя к более удобному и дружественному подходу.
В результате появилось расширение VK_EXT_shader_object, которое предложило простую альтернативу.
Больше никаких объектов-конвейеров - Vk*Pipeline оказались вообще не нужны.
Вместо них вводится новый тип объекта Vulkan - VkShaderEXT,
представляющий отдельный шейдерный шаг конвейера - вершинный, фрагментный, вычислительный и т.д.
Эти объекты могут создаваться независимо друг от друга или вместе при помощи вызова
Вызов этой функции собирает код для одной или нескольких стадий конвейера (графического или вычислительного) в объект типа
Ниже приводится описание структуры
Для подключения этого объекта (вместо конвейера) к командному буферу служит следующая команда.
Для уничтожения объектов типа
Поскольку теперь у нас нет объекта-конвейера, то то, что раньше было его состоянием, нужно задавать динамически.
Необходимые для этого команды были введены в Vulkan при помощи ранее введенных расширений
Обратите внимание, что в Vulkan нет состояния по умолчанию, поэтому все необходимое состояния графического конвейера необходимо явно задать через приведенные выше команды
Точно также и структура вершины, которая раньше задавалась в
По аналогии с тем как это было сделано раньше, мы можем завернуть задание атрибутов вершины с отдельный объект с удобным интерфейсом.
Ниже приводится простой пример использования данного расширения (вместе с динамическим рендерингом), весь исходный код находится в репозитории на github.
vkCreateShadersEXT:
VkResult vkCreateShadersEXT (
VkDevice device,
uint32_t createInfoCount,
VkShaderCreateInfoEXT pCreateInfos,
VkAllocationCallbacks pAllocator,
VkShaderEXT* pShaders );
VkShaderEXT.
Если createInfoCount больше единицы, то несколько шейдеров могут быть слинкованы вместе
(передавая флаг VK_SHADER_CREATE_LINK_STAGE_BIT_EXT в каждой из структур VkShaderCreateInfoEXT).
VkShaderCreateInfoEXT, через которую передается информация о шейдерной стадии конвейера.
Обратите внимание, что через поле nextStage мы можем передать следующую стадию (например, что за вершинный шейдером следует именно
фрагментный, а не геометрический) - это может позволить драйверу произвести оптимизацию.
typedef struct VkShaderCreateInfoEXT {
VkStructureType sType;
const void pNext;
VkShaderCreateFlagsEXT flags;
VkShaderStageFlagBits stage;
VkShaderStageFlags nextStage;
VkShaderCodeTypeEXT codeType;
size_t codeSize;
const void pCode;
const char pName;
uint32_t setLayoutCount;
const VkDescriptorSetLayout pSetLayouts;
uint32_t pushConstantRangeCount;
const VkPushConstantRange pPushConstantRanges;
const VkSpecializationInfo pSpecializationInfo;
} VkShaderCreateInfoEXT;
VKAPI_ATTR void VKAPI_CALL vkCmdBindShadersEXT (
VkCommandBuffer commandBuffer,
uint32_t stageCount,
const VkShaderStageFlagBits pStages,
const VkShaderEXT pShaders );
VkShaderEXT служит следующая функция
void vkDestroyShaderEXT (
VkDevice device,
VkShaderEXT shader,
VkAllocationCallbacks* pAllocator );
VK_EXT_extended_dynamic_state, VK_EXT_extended_dynamic_state2,
VK_EXT_extended_dynamic_state3, или VK_EXT_vertex_input_dynamic_state.
Ниже приводится прототипы основных таких функций.
void vkCmdBindVertexBuffers2 ( VkCommandBuffer commandBuffer,
uint32_t firstBinding, uint32_t bindingCount,
const VkBuffer pBuffers,
const VkDeviceSize pOffsets,
const VkDeviceSize pSizes,
const VkDeviceSize pStrides );
void vkCmdSetAlphaToCoverageEnableEXT ( VkCommandBuffer commandBuffer, VkBool32 alphaToCoverageEnable );
void vkCmdSetAlphaToOneEnableEXT ( VkCommandBuffer commandBuffer, VkBool32 alphaToOneEnable );
void vkCmdSetColorBlendEnableEXT ( VkCommandBuffer commandBuffer,
uint32_t firstAttachment, uint32_t attachmentCount, const VkBool32* pColorBlendEnables );
void vkCmdSetColorBlendEquationEXT ( VkCommandBuffer commandBuffer,
uint32_t firstAttachment, uint32_t attachmentCount, const VkColorBlendEquationEXT* pColorBlendEquations );
void vkCmdSetColorWriteMaskEXT ( VkCommandBuffer commandBuffer,
uint32_t firstAttachment, uint32_t attachmentCount, const VkColorComponentFlags* pColorWriteMasks );
void vkCmdSetCullMode ( VkCommandBuffer commandBuffer, VkCullModeFlags cullMode );
void vkCmdSetDepthBiasEnable ( VkCommandBuffer commandBuffer, VkBool32 depthBiasEnable );
void vkCmdSetDepthBoundsTestEnable ( VkCommandBuffer commandBuffer, VkBool32 depthBoundsTestEnable );
void vkCmdSetDepthClampEnableEXT ( VkCommandBuffer commandBuffer, VkBool32 depthClampEnable );
void vkCmdSetDepthCompareOp ( VkCommandBuffer commandBuffer, VkCompareOp depthCompareOp );
void vkCmdSetDepthTestEnable ( VkCommandBuffer commandBuffer, VkBool32 depthTestEnable );
void vkCmdSetDepthWriteEnable ( VkCommandBuffer commandBuffer, VkBool32 depthWriteEnable );
void vkCmdSetFrontFace ( VkCommandBuffer commandBuffer, VkFrontFace frontFace );
void vkCmdSetLogicOpEXT ( VkCommandBuffer commandBuffer, VkLogicOp logicOp );
void vkCmdSetLogicOpEnableEXT ( VkCommandBuffer commandBuffer, VkBool32 logicOpEnable );
void vkCmdSetPolygonModeEXT ( VkCommandBuffer commandBuffer, VkPolygonMode polygonMode );
void vkCmdSetPrimitiveRestartEnable ( VkCommandBuffer commandBuffer, VkBool32 primitiveRestartEnable );
void vkCmdSetPrimitiveTopology ( VkCommandBuffer commandBuffer, VkPrimitiveTopology primitiveTopology );
void vkCmdSetRasterizerDiscardEnable ( VkCommandBuffer commandBuffer, VkBool32 rasterizerDiscardEnable );
void vkCmdSetScissorWithCount ( VkCommandBuffer commandBuffer, uint32_t scissorCount, const VkRect2D* pScissors );
void vkCmdSetStencilTestEnable ( VkCommandBuffer commandBuffer, VkBool32 stencilTestEnable );
void vkCmdSetTessellationDomainOriginEXT ( kCommandBuffer commandBuffer, VkTessellationDomainOrigin domainOrigin );
void vkCmdSetVertexInputEXT ( VkCommandBuffer commandBuffer,
uint32_t vertexBindingDescriptionCount,
const VkVertexInputBindingDescription2EXT pVertexBindingDescriptions,
uint32_t vertexAttributeDescriptionCount, const VkVertexInputAttributeDescription2EXT pVertexAttributeDescriptions );
vkCmdSet*.
Ниже приводится пример типового задания свойств.
// No more pipelines required, everything is bound at command buffer level
// This also means that we need to explicitly set a lot of the state to be spec compliant
vkCmdSetViewportWithCountEXT ( cmdBuffer, 1, &viewport );
vkCmdSetScissorWithCountEXT ( cmdBuffer, 1, &scissor );
vkCmdSetCullModeEXT ( cmdBuffer, VK_CULL_MODE_BACK_BIT );
vkCmdSetFrontFaceEXT ( cmdBuffer, VK_FRONT_FACE_COUNTER_CLOCKWISE);
vkCmdSetDepthTestEnableEXT ( cmdBuffer, VK_TRUE );
vkCmdSetDepthWriteEnableEXT ( cmdBuffer, VK_TRUE );
vkCmdSetDepthCompareOpEXT ( cmdBuffer, VK_COMPARE_OP_LESS_OR_EQUAL);
vkCmdSetPrimitiveTopologyEXT ( cmdBuffer, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST );
vkCmdSetRasterizerDiscardEnableEXT ( cmdBuffer, VK_FALSE );
vkCmdSetPolygonModeEXT ( cmdBuffer, VK_POLYGON_MODE_FILL );
vkCmdSetRasterizationSamplesEXT ( cmdBuffer, VK_SAMPLE_COUNT_1_BIT );
vkCmdSetAlphaToCoverageEnableEXT ( cmdBuffer, VK_FALSE );
vkCmdSetDepthBiasEnableEXT ( cmdBuffer, VK_FALSE );
vkCmdSetStencilTestEnableEXT ( cmdBuffer, VK_FALSE );
vkCmdSetPrimitiveRestartEnableEXT ( cmdBuffer, VK_FALSE );
const uint32_t sampleMask = 0xFF;
vkCmdSetSampleMaskEXT ( cmdBuffer, VK_SAMPLE_COUNT_1_BIT, &sampleMask );
const VkBool32 colorBlendEnables = false;
const VkColorComponentFlags colorBlendComponentFlags = 0xf;
const VkColorBlendEquationEXT colorBlendEquation {};
vkCmdSetColorBlendEnableEXT ( cmdBuffer, 0, 1, &colorBlendEnables );
vkCmdSetColorWriteMaskEXT ( cmdBuffer, 0, 1, &colorBlendComponentFlags );
VkGraphicsPipeline должна задаваться отдельно. Ниже приводится подобный пример.
VkVertexInputBindingDescription2EXT vertexInputBinding {};
vertexInputBinding.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
vertexInputBinding.binding = 0;
vertexInputBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
vertexInputBinding.stride = sizeof(Vertex);
vertexInputBinding.divisor = 1;
std::vector vertexAttributes = {
{ VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, nullptr, 0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, pos) },
{ VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, nullptr, 1, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(Vertex, normal) },
{ VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, nullptr, 2, 0, VK_FORMAT_R32G32B32A32_SFLOAT, offsetof(Vertex, color) }
};
vkCmdSetVertexInputEXT ( cmdBuffer, 1, &vertexInputBinding, 3, vertexAttributes.data () );
class VertexDescription
{
VkVertexInputBindingDescription2EXT vertexInputBinding {};
std::vector<VkVertexInputAttributeDescription2EXT> vertexAttributes;
public:
VertexDescription ( uint32_t stride, uint32_t rate = VK_VERTEX_INPUT_RATE_VERTEX, uint32_t divisor = 1 );
VertexDescription& addAttr ( uint32_t location, VkFormat format, uint32_t offset, uint32_t bindidng = 0 )
{
VkVertexInputAttributeDescription2EXT d {};
d.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
d.location = location;
d.binding = binding;
d.format = format;
d.offset = offset;
vertexAttributes.push_back ( d );
return *this;
}
};
template
inline VertexDescription& registerVertexAttrs ( VertexDescription& desc )
{
return desc;
}
#include <memory>
#include "VulkanWindow.h"
#include "Buffer.h"
#include "DescriptorSet.h"
#include "Mesh.h"
#include "Controller.h"
#include "StatisticsPool.h"
#include "TimestampPool.h"
struct Ubo
{
glm::mat4 model;
glm::mat4 view;
glm::mat4 proj;
glm::mat3 nm;
};
class ShaderObjectWindow : public VulkanWindow
{
std::vector<CommandBuffer> commandBuffers;
std::vector<DescriptorSet> descriptorSets;
std::vector<Uniform<Ubo>> uniformBuffers;
DescSetLayout descSetLayout;
VkPipelineLayout pipelineLayout = VK_NULL_HANDLE;
VkShaderEXT vertexShader {};
VkShaderEXT fragmentShader {};
Texture texture;
Sampler sampler;
std::unique_ptr<Mesh> mesh;
PFN_vkCreateShadersEXT vkCreateShadersEXT { VK_NULL_HANDLE };
PFN_vkDestroyShaderEXT vkDestroyShaderEXT { VK_NULL_HANDLE };
PFN_vkCmdBindShadersEXT vkCmdBindShadersEXT { VK_NULL_HANDLE };
PFN_vkGetShaderBinaryDataEXT vkGetShaderBinaryDataEXT { VK_NULL_HANDLE };
// VK_EXT_shader_objects requires render passes to be dynamic
PFN_vkCmdBeginRenderingKHR vkCmdBeginRenderingKHR { VK_NULL_HANDLE };
PFN_vkCmdEndRenderingKHR vkCmdEndRenderingKHR { VK_NULL_HANDLE };
// With VK_EXT_shader_object pipeline state must be set at
// command buffer creation using these functions
PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetColorBlendEnableEXT vkCmdSetColorBlendEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetColorWriteMaskEXT vkCmdSetColorWriteMaskEXT { VK_NULL_HANDLE };
PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT { VK_NULL_HANDLE };
PFN_vkCmdSetDepthBiasEnableEXT vkCmdSetDepthBiasEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT { VK_NULL_HANDLE };
PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT { VK_NULL_HANDLE };
PFN_vkCmdSetPolygonModeEXT vkCmdSetPolygonModeEXT { VK_NULL_HANDLE };
PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT { VK_NULL_HANDLE };
PFN_vkCmdSetRasterizationSamplesEXT vkCmdSetRasterizationSamplesEXT { VK_NULL_HANDLE };
PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetSampleMaskEXT vkCmdSetSampleMaskEXT { VK_NULL_HANDLE };
PFN_vkCmdSetScissorWithCountEXT vkCmdSetScissorWithCountEXT { VK_NULL_HANDLE };
PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT { VK_NULL_HANDLE };
PFN_vkCmdSetViewportWithCountEXT vkCmdSetViewportWithCountEXT { VK_NULL_HANDLE };
// VK_EXT_vertex_input_dynamic_state
PFN_vkCmdSetVertexInputEXT vkCmdSetVertexInputEXT { VK_NULL_HANDLE };
public:
ShaderObjectWindow ( int w, int h, const std::string& t, DevicePolicy * p ) :
VulkanWindow ( w, h, t, true, p )
{
loadExtensions ();
setController ( new RotateController ( this, glm::vec3(2.0f, 2.0f, 2.0f) ) );
mesh = std::unique_ptr<Mesh> ( loadMesh ( device, "../../Models/teapot.3ds", 0.04f ) );
sampler.create ( device ); // use default options
texture.load ( device, "../../Textures/Fieldstone.dds", false );
descSetLayout
.add ( 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, VK_SHADER_STAGE_VERTEX_BIT )
.add ( 1, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, VK_SHADER_STAGE_FRAGMENT_BIT )
.create ( device.getDevice () );
vertexShader = createShader ( Data ( "shaders/shader-tex.vert.spv" ),
VK_SHADER_STAGE_VERTEX_BIT, &descSetLayout );
fragmentShader = createShader ( Data ( "shaders/shader-tex.frag.spv" ),
VK_SHADER_STAGE_FRAGMENT_BIT, &descSetLayout );
createPipelines ();
}
void createUniformBuffers ()
{
uniformBuffers.resize ( swapChain.getImageCount() );
for ( size_t i = 0; i < swapChain.getImageCount (); i++ )
uniformBuffers [i].create ( device, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT );
}
void freeUniformBuffers ()
{
uniformBuffers.clear ();
}
void createDescriptorSets ()
{
descriptorSets.resize ( swapChain.getImageCount () );
for ( uint32_t i = 0; i < swapChain.getImageCount (); i++ )
{
descriptorSets [i]
.setLayout ( device, descAllocator, descSetLayout )
.addUniformBuffer ( 0, uniformBuffers [i], 0, sizeof ( Ubo ) )
.addImage ( 1, texture, sampler )
.create ();
}
}
virtual void createPipelines () override
{
VkPipelineRenderingCreateInfoKHR pipelineRenderingCreateInfo = {};
VkFormat swapChainFormats [] = { swapChain.getFormat () };
pipelineRenderingCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_RENDERING_CREATE_INFO_KHR;
pipelineRenderingCreateInfo.colorAttachmentCount = 1;
pipelineRenderingCreateInfo.pColorAttachmentFormats = swapChainFormats;
pipelineRenderingCreateInfo.depthAttachmentFormat = depthTexture.getFormat ();
pipelineRenderingCreateInfo.stencilAttachmentFormat = depthTexture.getFormat ();
createUniformBuffers ();
createDescriptorSets ();
createCommandBuffers ();
}
virtual void freePipelines () override
{
commandBuffers.clear ();
freeUniformBuffers ();
descriptorSets.clear ();
descAllocator.clean ();
}
virtual void submit ( uint32_t imageIndex ) override
{
updateUniformBuffer ( imageIndex );
defaultSubmit ( commandBuffers [imageIndex] );
}
void createCommandBuffers ()
{
commandBuffers = device.allocCommandBuffers ( swapChain.getImageCount () );
for ( size_t i = 0; i < swapChain.getImageCount (); i++ )
{
VkRenderingAttachmentInfoKHR colorAttachment = {};
VkRenderingAttachmentInfoKHR depthStencilAttachment = {};
colorAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
colorAttachment.imageView = swapChain.getImageViews () [i];
colorAttachment.imageLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
colorAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
colorAttachment.clearValue.color = { 0.0f,0.0f,0.0f,0.0f };
depthStencilAttachment.sType = VK_STRUCTURE_TYPE_RENDERING_ATTACHMENT_INFO_KHR;
depthStencilAttachment.imageView = depthTexture.getImageView ();
depthStencilAttachment.imageLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
depthStencilAttachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
depthStencilAttachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
depthStencilAttachment.clearValue.depthStencil = { 1.0f, 0 };
VkRenderingInfoKHR renderingInfo = {};
renderingInfo.sType = VK_STRUCTURE_TYPE_RENDERING_INFO_KHR;
renderingInfo.renderArea = { 0, 0, uint32_t ( width ), uint32_t ( height ) };
renderingInfo.layerCount = 1;
renderingInfo.colorAttachmentCount = 1;
renderingInfo.pColorAttachments = &colorAttachment;
renderingInfo.pDepthAttachment = &depthStencilAttachment;
renderingInfo.pStencilAttachment = &depthStencilAttachment;
// With dynamic rendering there are no subpass dependencies,
// we need to take care of proper layout transitions by using barriers
// for color and depth images
auto barrierImage = imageBarrier ( swapChain.getImages () [i],
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask
0, // srcAccessMask
VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // dstStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // dstAccessMask
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // newLayout
VK_IMAGE_ASPECT_COLOR_BIT // aspectMask
);
auto barrierDepth = imageBarrier ( depthTexture.getImage (),
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // srcStageMask,
0, // srcAccessMask,
VK_IMAGE_LAYOUT_UNDEFINED, // oldLayout,
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, // dstStageMask,
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT, // dstAccessMask,
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, // newLayout,
VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT // aspectMask
);
commandBuffers [i].begin ();
auto cmd = commandBuffers [i].getHandle ();
pipelineBarrier ( commandBuffers [i], { barrierImage, barrierDepth } );
vkCmdBeginRenderingKHR ( cmd, &renderingInfo );
VkViewport viewport = { 0.0f, 0.0f, float(width), float(height), 0.0f, 1.0f };
VkRect2D scissor = { 0, 0, width, height };
// No more pipelines required, everything is bound at command buffer level
// This also means that we need to explicitly set a lot of the state to be spec compliant
vkCmdSetViewportWithCountEXT ( cmd, 1, &viewport );
vkCmdSetScissorWithCountEXT ( cmd, 1, &scissor );
vkCmdSetCullModeEXT ( cmd, VK_CULL_MODE_BACK_BIT );
vkCmdSetFrontFaceEXT ( cmd, VK_FRONT_FACE_CLOCKWISE );
vkCmdSetDepthTestEnableEXT ( cmd, VK_TRUE );
vkCmdSetDepthWriteEnableEXT ( cmd, VK_TRUE );
vkCmdSetDepthCompareOpEXT ( cmd, VK_COMPARE_OP_LESS );
vkCmdSetPrimitiveTopologyEXT ( cmd, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST );
vkCmdSetRasterizerDiscardEnableEXT ( cmd, VK_FALSE );
vkCmdSetPolygonModeEXT ( cmd, VK_POLYGON_MODE_FILL );
vkCmdSetRasterizationSamplesEXT ( cmd, VK_SAMPLE_COUNT_1_BIT );
vkCmdSetAlphaToCoverageEnableEXT ( cmd, VK_FALSE );
vkCmdSetDepthBiasEnableEXT ( cmd, VK_FALSE );
vkCmdSetStencilTestEnableEXT ( cmd, VK_FALSE );
vkCmdSetPrimitiveRestartEnableEXT ( cmd, VK_FALSE );
const uint32_t sampleMask = 0xFF;
vkCmdSetSampleMaskEXT ( cmd, VK_SAMPLE_COUNT_1_BIT, &sampleMask );
const VkBool32 colorBlendEnables = VK_FALSE;
const VkColorComponentFlags colorBlendComponentFlags = 0xf;
const VkColorBlendEquationEXT colorBlendEquation {};
vkCmdSetColorBlendEnableEXT ( cmd, 0, 1, &colorBlendEnables );
vkCmdSetColorWriteMaskEXT ( cmd, 0, 1, &colorBlendComponentFlags );
VkVertexInputBindingDescription2EXT vertexInputBinding {};
vertexInputBinding.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT;
vertexInputBinding.binding = 0;
vertexInputBinding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
vertexInputBinding.stride = sizeof(BasicVertex);
vertexInputBinding.divisor = 1;
std::vector<VkVertexInputAttributeDescription2EXT> vertexAttributes =
{
{ VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, nullptr, 0, 0,
VK_FORMAT_R32G32B32_SFLOAT, offsetof(BasicVertex, pos) },
{ VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT, nullptr, 1, 0,
VK_FORMAT_R32G32_SFLOAT, offsetof(BasicVertex, tex) }
};
vkCmdSetVertexInputEXT ( cmd, 1, &vertexInputBinding, uint32_t ( vertexAttributes.size () ),
vertexAttributes.data () );
// Create pipeline layout and bind it to command buffer
VkPipelineLayoutCreateInfo pipelineLayoutInfo = {};
std::vector<VkDescriptorSetLayout> layouts;
VkDescriptorSet descSet = descriptorSets [i].getHandle ();
layouts.push_back ( descSetLayout.getHandle () );
pipelineLayoutInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
pipelineLayoutInfo.setLayoutCount = 0;
pipelineLayoutInfo.setLayoutCount = (uint32_t) layouts.size ();
pipelineLayoutInfo.pSetLayouts = layouts.data ();
vkCreatePipelineLayout ( device.getDevice (), &pipelineLayoutInfo, nullptr, &pipelineLayout );
vkCmdBindDescriptorSets ( cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &descSet, 0, nullptr );
VkShaderStageFlagBits stages [2] = { VK_SHADER_STAGE_VERTEX_BIT, VK_SHADER_STAGE_FRAGMENT_BIT };
VkShaderEXT shaders [2] = { vertexShader, fragmentShader };
vkCmdBindShadersEXT ( cmd, 2, stages, shaders );
// render mesh
commandBuffers [i].render ( mesh.get () );
vkCmdEndRenderingKHR ( commandBuffers [i].getHandle () );
auto barrierImage2 = imageBarrier ( swapChain.getImages () [i],
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, // srcStageMask
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, // srcAccessMask
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, // oldLayout
VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT, // dstStageMask
0, // dstAccessMask
VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, // newLayout
VK_IMAGE_ASPECT_COLOR_BIT // aspectMask
);
pipelineBarrier ( commandBuffers [i], { barrierImage2 } );
commandBuffers [i].end ();
}
}
void updateUniformBuffer ( uint32_t currentImage )
{
uniformBuffers [currentImage]->model = controller->getModelView ();
uniformBuffers [currentImage]->view = glm::mat4 ( 1 );
uniformBuffers [currentImage]->proj = controller->getProjection ();
}
VkShaderEXT createShader ( Data& data, VkShaderStageFlagBits stage, DescSetLayout * layout = nullptr,
const std::string& name = "main" )
{
VkShaderCreateInfoEXT shaderCreateInfo {};
VkDescriptorSetLayout descSetLayout = layout ? layout -> getHandle () : VK_NULL_HANDLE;
VkShaderEXT shader = VK_NULL_HANDLE;
shaderCreateInfo.sType = VK_STRUCTURE_TYPE_SHADER_CREATE_INFO_EXT;
shaderCreateInfo.flags = VK_SHADER_CREATE_LINK_STAGE_BIT_EXT;
shaderCreateInfo.stage = stage;
//shaderCreateInfo.nextStage = VK_SHADER_STAGE_FRAGMENT_BIT;
shaderCreateInfo.codeType = VK_SHADER_CODE_TYPE_SPIRV_EXT;
shaderCreateInfo.pCode = reinterpret_cast<const uint32_t*>( data.getPtr () );
shaderCreateInfo.codeSize = data.getLength ();
shaderCreateInfo.pName = name.c_str ();
if ( layout != nullptr )
{
shaderCreateInfo.setLayoutCount = 1;
shaderCreateInfo.pSetLayouts = &descSetLayout;
}
if ( vkCreateShadersEXT ( device.getDevice (), 1, &shaderCreateInfo, nullptr, &shader) != VK_SUCCESS )
warning () << "\nError creating shader object " << data.getFileName () << std::endl;
return shader;
}
void loadExtensions ()
{
vkCreateShadersEXT = reinterpret_cast<PFN_vkCreateShadersEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCreateShadersEXT"));
vkDestroyShaderEXT = reinterpret_cast<PFN_vkDestroyShaderEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkDestroyShaderEXT"));
vkCmdBindShadersEXT = reinterpret_cast<PFN_vkCmdBindShadersEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdBindShadersEXT"));
vkGetShaderBinaryDataEXT = reinterpret_cast<PFN_vkGetShaderBinaryDataEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkGetShaderBinaryDataEXT"));
vkCmdBeginRenderingKHR = reinterpret_cast<PFN_vkCmdBeginRenderingKHR>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdBeginRenderingKHR"));
vkCmdEndRenderingKHR = reinterpret_cast<PFN_vkCmdEndRenderingKHR>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdEndRenderingKHR"));
vkCmdSetAlphaToCoverageEnableEXT = reinterpret_cast<PFN_vkCmdSetAlphaToCoverageEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetAlphaToCoverageEnableEXT"));
vkCmdSetColorBlendEnableEXT = reinterpret_cast<PFN_vkCmdSetColorBlendEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetColorBlendEnableEXT"));
vkCmdSetColorWriteMaskEXT = reinterpret_cast<PFN_vkCmdSetColorWriteMaskEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetColorWriteMaskEXT"));
vkCmdSetCullModeEXT = reinterpret_cast<PFN_vkCmdSetCullModeEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetCullModeEXT"));
vkCmdSetDepthBiasEnableEXT = reinterpret_cast<PFN_vkCmdSetDepthBiasEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetDepthBiasEnableEXT"));
vkCmdSetDepthCompareOpEXT = reinterpret_cast<PFN_vkCmdSetDepthCompareOpEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetDepthCompareOpEXT"));
vkCmdSetDepthTestEnableEXT = reinterpret_cast<PFN_vkCmdSetDepthTestEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetDepthTestEnableEXT"));
vkCmdSetDepthWriteEnableEXT = reinterpret_cast<PFN_vkCmdSetDepthWriteEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetDepthWriteEnableEXT"));
vkCmdSetFrontFaceEXT = reinterpret_cast<PFN_vkCmdSetFrontFaceEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetFrontFaceEXT"));
vkCmdSetPolygonModeEXT = reinterpret_cast<PFN_vkCmdSetPolygonModeEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetPolygonModeEXT"));
vkCmdSetPrimitiveRestartEnableEXT = reinterpret_cast<PFN_vkCmdSetPrimitiveRestartEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetPrimitiveRestartEnableEXT"));
vkCmdSetPrimitiveTopologyEXT = reinterpret_cast<PFN_vkCmdSetPrimitiveTopologyEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetPrimitiveTopologyEXT"));
vkCmdSetRasterizationSamplesEXT = reinterpret_cast<PFN_vkCmdSetRasterizationSamplesEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetRasterizationSamplesEXT"));
vkCmdSetRasterizerDiscardEnableEXT = reinterpret_cast<PFN_vkCmdSetRasterizerDiscardEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetRasterizerDiscardEnableEXT"));
vkCmdSetSampleMaskEXT = reinterpret_cast<PFN_vkCmdSetSampleMaskEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetSampleMaskEXT"));
vkCmdSetScissorWithCountEXT = reinterpret_cast<PFN_vkCmdSetScissorWithCountEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetScissorWithCountEXT"));
vkCmdSetStencilTestEnableEXT = reinterpret_cast<PFN_vkCmdSetStencilTestEnableEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetStencilTestEnableEXT"));
vkCmdSetVertexInputEXT = reinterpret_cast<PFN_vkCmdSetVertexInputEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetVertexInputEXT"));
vkCmdSetViewportWithCountEXT = reinterpret_cast<PFN_vkCmdSetViewportWithCountEXT>(vkGetDeviceProcAddr(device.getDevice (), "vkCmdSetViewportWithCountEXT"));;
}
};
int main ( int argc, const char * argv [] )
{
DevicePolicy policy;
VkPhysicalDeviceShaderObjectFeaturesEXT enabledShaderObjectFeaturesEXT {};
enabledShaderObjectFeaturesEXT.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_OBJECT_FEATURES_EXT;
enabledShaderObjectFeaturesEXT.shaderObject = VK_TRUE;
policy.addDeviceExtension ( VK_KHR_DYNAMIC_RENDERING_EXTENSION_NAME );
policy.addDeviceExtension ( VK_EXT_SHADER_OBJECT_EXTENSION_NAME );
policy.addDeviceExtension ( VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME );
policy.addDeviceExtension ( VK_KHR_MAINTENANCE2_EXTENSION_NAME );
policy.addDeviceExtension ( VK_KHR_MULTIVIEW_EXTENSION_NAME );
policy.addDeviceExtension ( VK_KHR_CREATE_RENDERPASS_2_EXTENSION_NAME );
policy.addDeviceExtension ( VK_KHR_DEPTH_STENCIL_RESOLVE_EXTENSION_NAME );
policy.addFeatures ( &enabledShaderObjectFeaturesEXT );
return ShaderObjectWindow ( 800, 600, "Shader objects with dynamic rendering", &policy ).run ();
}