Implement graphics pipeline utilities, port Overv's triangle demo
This commit is contained in:
parent
1986d3c171
commit
575d1acbf7
5 changed files with 674 additions and 107 deletions
10
triangle.frag
Normal file
10
triangle.frag
Normal file
|
@ -0,0 +1,10 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec3 inColor;
|
||||
|
||||
layout (location = 0) out vec4 outFragColor;
|
||||
|
||||
void main()
|
||||
{
|
||||
outFragColor = vec4(inColor, 1.0);
|
||||
}
|
23
triangle.vert
Normal file
23
triangle.vert
Normal file
|
@ -0,0 +1,23 @@
|
|||
#version 450
|
||||
|
||||
layout (location = 0) in vec3 inPos;
|
||||
layout (location = 1) in vec3 inColor;
|
||||
|
||||
layout (binding = 0) uniform UBO
|
||||
{
|
||||
mat4 transformMatrix;
|
||||
} ubo;
|
||||
|
||||
layout (location = 0) out vec3 outColor;
|
||||
|
||||
out gl_PerVertex
|
||||
{
|
||||
vec4 gl_Position;
|
||||
};
|
||||
|
||||
|
||||
void main()
|
||||
{
|
||||
outColor = inColor;
|
||||
gl_Position = ubo.transformMatrix * vec4(inPos.xyz, 1.0);
|
||||
}
|
|
@ -52,7 +52,10 @@ struct ComputeApplicationPipeline: BaseVulkanPipeline
|
|||
CreatePool(CHAIN_SIZE,
|
||||
BasicPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_IMAGE,CHAIN_SIZE*2),
|
||||
BasicPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, CHAIN_SIZE*1));
|
||||
|
||||
VkShaderModule shader;
|
||||
CreateComputePipeline(ShaderFromFile(shader, "image.spv", VK_SHADER_STAGE_COMPUTE_BIT));
|
||||
// todo: should not we destroy shader internally?
|
||||
vkDestroyShaderModule(device, shader, NULL);
|
||||
}
|
||||
void UpdateDescriptors(VkDescriptorSet dstSet, VkImageView imageView0, VkImageView imageView1, const VkDescriptorBufferInfo &buffer)
|
||||
{
|
||||
|
@ -82,7 +85,6 @@ struct ComputeApplication {
|
|||
VulkanContext context;
|
||||
VulkanDevice dev;
|
||||
ComputeApplicationPipeline computePipeline;
|
||||
VkShaderModule computeShaderModule;
|
||||
|
||||
struct UBO{
|
||||
float frameNum;
|
||||
|
@ -171,54 +173,6 @@ struct ComputeApplication {
|
|||
computePipeline.UpdateDescriptors(chain[chidx].descriptorSet, chain[chidx].texture0.view, chain[chidx].texture1.view, chain[chidx].uboBuf.descriptor);
|
||||
}
|
||||
|
||||
// Read file into array of bytes, and cast to uint32_t*, then return.
|
||||
// The data has been padded, so that it fits into an array uint32_t.
|
||||
uint32_t* readFile(uint32_t& length, const char* filename) {
|
||||
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if (fp == NULL) {
|
||||
printf("Could not find or open file: %s\n", filename);
|
||||
}
|
||||
|
||||
// get file size.
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long filesize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
long filesizepadded = long(ceil(filesize / 4.0)) * 4;
|
||||
|
||||
// read file contents.
|
||||
char *str = (char*)malloc(filesizepadded);
|
||||
fread(str, filesize, sizeof(char), fp);
|
||||
fclose(fp);
|
||||
|
||||
// data padding.
|
||||
for (int i = filesize; i < filesizepadded; i++) {
|
||||
str[i] = 0;
|
||||
}
|
||||
|
||||
length = filesizepadded;
|
||||
return (uint32_t *)str;
|
||||
}
|
||||
|
||||
void createComputePipeline() {
|
||||
/*
|
||||
We create a compute pipeline here.
|
||||
*/
|
||||
uint32_t filelength;
|
||||
// the code in comp.spv was created by running the command:
|
||||
// glslangValidator.exe -V shader.comp
|
||||
uint32_t* code = readFile(filelength, "image.spv");
|
||||
/*
|
||||
Create a shader module. A shader module basically just encapsulates some shader code.
|
||||
*/
|
||||
// todo: it is very strange API...
|
||||
VkPipelineShaderStageCreateInfo shaderStageCreateInfo = LoadShader(dev.device, code, filelength, VK_SHADER_STAGE_COMPUTE_BIT);
|
||||
computeShaderModule = shaderStageCreateInfo.module;
|
||||
computePipeline.CreateComputePipeline(shaderStageCreateInfo);
|
||||
free(code);
|
||||
}
|
||||
|
||||
void prepareImage(int chidx)
|
||||
{
|
||||
VkCommandBuffer commandBuffer = dev.CreateCommandBuffer();
|
||||
|
@ -319,7 +273,6 @@ struct ComputeApplication {
|
|||
}
|
||||
|
||||
computePipeline.Init(dev.device);
|
||||
createComputePipeline();
|
||||
for(int i = 0; i < CHAIN_SIZE; i++)
|
||||
{
|
||||
prepareImage(i);
|
||||
|
@ -366,7 +319,6 @@ struct ComputeApplication {
|
|||
/*
|
||||
Clean up all Vulkan Resources.
|
||||
*/
|
||||
vkDestroyShaderModule(dev.device, computeShaderModule, NULL);
|
||||
computePipeline.Destroy();
|
||||
dev.Destroy();
|
||||
context.Destroy();
|
||||
|
|
333
vkgraphics.cpp
Normal file
333
vkgraphics.cpp
Normal file
|
@ -0,0 +1,333 @@
|
|||
#include "vulkan_utl.h"
|
||||
#include <X11/Xlib.h>
|
||||
#include <vulkan/vulkan_xlib.h>
|
||||
// use glfw for temporary swapchain window
|
||||
// todo: GET RID OF THIS, IT SOMEHOW INCLUDES GL!!!
|
||||
#include <GLFW/glfw3.h>
|
||||
#define GLFW_EXPOSE_NATIVE_X11
|
||||
#include <GLFW/glfw3native.h>
|
||||
// todo: REMOVE THIS. Why "simpliest triangle" demos even use this????
|
||||
// It does not "HELP" drawing 2D triangle!!! It is not useful in engines using own matrix transform code!
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#define MAX_SWAPCHAIN_IMAGES 32
|
||||
|
||||
struct Vertex
|
||||
{
|
||||
float position[3];
|
||||
float color[3];
|
||||
};
|
||||
|
||||
struct GraphicsApplicationPipeline: BaseVulkanPipeline
|
||||
{
|
||||
|
||||
void Init(VkDevice dev, VkRenderPass renderPass)
|
||||
{
|
||||
|
||||
device = dev;
|
||||
CreateDescriptorSetLayout(
|
||||
BasicBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,1,VK_SHADER_STAGE_VERTEX_BIT)
|
||||
);
|
||||
CreatePool(1,
|
||||
BasicPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, 1)
|
||||
);
|
||||
VkShaderModule vp, fp;
|
||||
CreateGraphicsPipeline(renderPass, Stages(
|
||||
ShaderFromFile(vp, "triangle.vert.spv", VK_SHADER_STAGE_VERTEX_BIT),
|
||||
ShaderFromFile(fp, "triangle.frag.spv", VK_SHADER_STAGE_FRAGMENT_BIT)),
|
||||
VertexBindings(VertexBinding(0, sizeof(Vertex))),
|
||||
VertexAttributes(
|
||||
VertAttrib(0, 0, offsetof(Vertex,position)),
|
||||
VertAttrib(1, 0, offsetof(Vertex,color))
|
||||
),
|
||||
DynamicStates(
|
||||
VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR));
|
||||
vkDestroyShaderModule(device, vp, NULL);
|
||||
vkDestroyShaderModule(device, fp, NULL);
|
||||
}
|
||||
void UpdateDescriptors(VkDescriptorSet dstSet, const VkDescriptorBufferInfo &buffer)
|
||||
{
|
||||
WriteDescriptors(
|
||||
BufferWrite(dstSet, 0, buffer)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
struct GraphicsApplication
|
||||
{
|
||||
VulkanContext context;
|
||||
VulkanDevice dev;
|
||||
GLFWwindow *window = NULL;
|
||||
VkSwapchainKHR swapchain;
|
||||
VkSurfaceKHR surface;
|
||||
VkImage swapchainImages[MAX_SWAPCHAIN_IMAGES];
|
||||
unsigned int numSwapchainImages;
|
||||
VulkanFramebuffer swapchainFbs[MAX_SWAPCHAIN_IMAGES];
|
||||
VkCommandBuffer commandBuffers[MAX_SWAPCHAIN_IMAGES];
|
||||
VkFence chainFences[MAX_SWAPCHAIN_IMAGES];
|
||||
VkSemaphore swapchainRenderSemaphore, swapchainPresentSemaphore;
|
||||
struct UBO
|
||||
{
|
||||
glm::mat4 transformationMatrix;
|
||||
};
|
||||
|
||||
GraphicsApplicationPipeline graphicsPipeline;
|
||||
VkDescriptorSet descriptorSet;
|
||||
VulkanBuffer uboBuf;
|
||||
VulkanBuffer stagingVert;
|
||||
VulkanBuffer stagingInd;
|
||||
//VkFence swapchainFence;
|
||||
void CreateWindow(const char* windowTitle, int& outWidth, int& outHeight, bool resizable)
|
||||
{
|
||||
if (!glfwInit()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const bool wantsWholeArea = outWidth <= 0 || outHeight <= 0;
|
||||
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
glfwWindowHint(GLFW_RESIZABLE, wantsWholeArea || !resizable ? GLFW_FALSE : GLFW_TRUE);
|
||||
|
||||
// render full screen without overlapping taskbar
|
||||
GLFWmonitor* monitor = glfwGetPrimaryMonitor();
|
||||
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
int w = outWidth;
|
||||
int h = outHeight;
|
||||
|
||||
if (wantsWholeArea) {
|
||||
int areaW = 0;
|
||||
int areaH = 0;
|
||||
glfwGetMonitorWorkarea(monitor, &x, &y, &areaW, &areaH);
|
||||
auto getPercent = [](int value, int percent) {
|
||||
assert(percent > 0 && percent <= 100);
|
||||
return static_cast<int>(static_cast<float>(value) * static_cast<float>(percent) / 100.0f);
|
||||
};
|
||||
if (outWidth < 0) {
|
||||
w = getPercent(areaW, -outWidth);
|
||||
x = (areaW - w) / 2;
|
||||
} else {
|
||||
w = areaW;
|
||||
}
|
||||
if (outHeight < 0) {
|
||||
h = getPercent(areaH, -outHeight);
|
||||
y = (areaH - h) / 2;
|
||||
} else {
|
||||
h = areaH;
|
||||
}
|
||||
}
|
||||
|
||||
window = glfwCreateWindow(w, h, windowTitle, nullptr, nullptr);
|
||||
|
||||
if (!window) {
|
||||
glfwTerminate();
|
||||
return;
|
||||
}
|
||||
|
||||
if (wantsWholeArea) {
|
||||
glfwSetWindowPos(window, x, y);
|
||||
}
|
||||
|
||||
glfwGetWindowSize(window, &outWidth, &outHeight);
|
||||
|
||||
glfwSetKeyCallback(window, [](GLFWwindow* window, int key, int, int action, int) {
|
||||
if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
|
||||
glfwSetWindowShouldClose(window, GLFW_TRUE);
|
||||
}
|
||||
});
|
||||
|
||||
glfwSetErrorCallback([](int error, const char* description) { printf("GLFW Error (%i): %s\n", error, description); });
|
||||
//glfwShowWindow(window);
|
||||
}
|
||||
void DestroyWindow()
|
||||
{
|
||||
if(window)
|
||||
glfwDestroyWindow(window);
|
||||
glfwTerminate();
|
||||
}
|
||||
void CreateSwapchain(int width, int height)
|
||||
{
|
||||
const VkXlibSurfaceCreateInfoKHR surfaceinfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR,
|
||||
.flags = 0,
|
||||
.dpy = glfwGetX11Display(),
|
||||
.window = glfwGetX11Window(window),
|
||||
};
|
||||
VK_CHECK_RESULT(vkCreateXlibSurfaceKHR(context.instance, &surfaceinfo, nullptr, &surface));
|
||||
const VkSwapchainCreateInfoKHR swapchain_create_info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR,
|
||||
.surface = surface,
|
||||
.minImageCount = 4,
|
||||
// todo: guess format
|
||||
.imageFormat = VK_FORMAT_B8G8R8A8_UNORM,
|
||||
.imageColorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR,
|
||||
.imageExtent = {.width = width, .height = height},
|
||||
.imageArrayLayers = 1,
|
||||
.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT,
|
||||
.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 1,
|
||||
.pQueueFamilyIndices = &dev.defaultFamilyIndex,
|
||||
.preTransform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR,
|
||||
.compositeAlpha = VK_COMPOSITE_ALPHA_INHERIT_BIT_KHR,
|
||||
.presentMode = VK_PRESENT_MODE_FIFO_KHR,
|
||||
.clipped = VK_TRUE,
|
||||
.oldSwapchain = VK_NULL_HANDLE,
|
||||
};
|
||||
vkCreateSwapchainKHR(dev.device, &swapchain_create_info, nullptr, &swapchain);
|
||||
|
||||
numSwapchainImages = MAX_SWAPCHAIN_IMAGES;
|
||||
|
||||
VK_CHECK_RESULT(vkGetSwapchainImagesKHR(dev.device, swapchain, &numSwapchainImages, swapchainImages));
|
||||
for(int i = 0; i < numSwapchainImages; i++)
|
||||
{
|
||||
swapchainFbs[i].Create(dev.device);
|
||||
swapchainFbs[i].CreateDepthAttachment(dev, VK_FORMAT_D32_SFLOAT, width, height);
|
||||
swapchainFbs[i].Init(swapchainImages[i], VK_FORMAT_B8G8R8A8_UNORM, width, height);
|
||||
}
|
||||
VkSemaphoreCreateInfo semaphoreCreateInfo = {VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO};
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(dev.device, &semaphoreCreateInfo, nullptr, &swapchainPresentSemaphore));
|
||||
VK_CHECK_RESULT(vkCreateSemaphore(dev.device, &semaphoreCreateInfo, nullptr, &swapchainRenderSemaphore));
|
||||
}
|
||||
unsigned int AcquireImage()
|
||||
{
|
||||
unsigned int index;
|
||||
vkAcquireNextImageKHR(dev.device, swapchain, UINT64_MAX, swapchainRenderSemaphore, (VkFence)nullptr, &index);
|
||||
return index;
|
||||
}
|
||||
void PresentImage(unsigned int index)
|
||||
{
|
||||
VkPresentInfoKHR presentInfo = {VK_STRUCTURE_TYPE_PRESENT_INFO_KHR};
|
||||
presentInfo.swapchainCount = 1;
|
||||
presentInfo.pSwapchains = &swapchain;
|
||||
presentInfo.pImageIndices = &index;
|
||||
presentInfo.pWaitSemaphores = &swapchainPresentSemaphore;
|
||||
presentInfo.waitSemaphoreCount = 1;
|
||||
vkQueuePresentKHR(dev.defautQueue, &presentInfo);
|
||||
}
|
||||
void DestroySwapchain()
|
||||
{
|
||||
for(int i = 0; i < numSwapchainImages; i++)
|
||||
swapchainFbs[i].Destroy();
|
||||
vkDestroySwapchainKHR(dev.device, swapchain, NULL);
|
||||
vkDestroySurfaceKHR(context.instance,surface,NULL);
|
||||
vkDestroySemaphore(dev.device, swapchainPresentSemaphore, NULL);
|
||||
vkDestroySemaphore(dev.device, swapchainRenderSemaphore, NULL);
|
||||
}
|
||||
|
||||
// todo: NUKE THIS!!!
|
||||
void updateUniformData() {
|
||||
static unsigned int frameNum;
|
||||
// Rotate based on time
|
||||
long long millis = frameNum++;
|
||||
float angle = (millis % 400) / 400.0f * glm::radians(360.f);
|
||||
|
||||
glm::mat4 modelMatrix = glm::identity<glm::mat4>();
|
||||
modelMatrix = glm::rotate(modelMatrix, angle, glm::vec3(0, 0, 1));
|
||||
//((UBO*)uboBuf.mapped)->transformationMatrix = modelMatrix;
|
||||
modelMatrix = glm::translate(modelMatrix, glm::vec3(0.5f / 3.0f, -0.5f / 3.0f, 0.0f));
|
||||
|
||||
// Set up view
|
||||
auto viewMatrix = glm::lookAt(glm::vec3(1, 1, 1), glm::vec3(0, 0, 0), glm::vec3(0, 0, -1));
|
||||
|
||||
// Set up projection
|
||||
auto projMatrix = glm::perspective(glm::radians(70.f), 800.0f / 600.0f, 0.1f, 10.0f);
|
||||
((UBO*)uboBuf.mapped)->transformationMatrix = projMatrix * viewMatrix * modelMatrix;
|
||||
}
|
||||
|
||||
void waitFence(int chidx)
|
||||
{
|
||||
VK_CHECK_RESULT(vkWaitForFences(dev.device, 1, &chainFences[chidx], VK_TRUE, 100000000000));
|
||||
}
|
||||
|
||||
void Run()
|
||||
{
|
||||
context.Create("streamingengine", "vulkan-playground-server");
|
||||
dev.Create(context.FindPhysicalDevice(), VK_QUEUE_GRAPHICS_BIT);
|
||||
dev.CreateDevice(context);
|
||||
int width = 800;
|
||||
int height = 600;
|
||||
CreateWindow("demo", width, height, false);
|
||||
CreateSwapchain(width,height);
|
||||
dev.CreateAndMap(uboBuf, sizeof(UBO));
|
||||
graphicsPipeline.Init(dev.device, swapchainFbs[0].render_pass);
|
||||
descriptorSet = graphicsPipeline.AllocateSingleDescriptorSet();
|
||||
graphicsPipeline.UpdateDescriptors(descriptorSet, uboBuf.descriptor);
|
||||
updateUniformData();
|
||||
|
||||
Vertex vertices[] = {
|
||||
{ { -0.5f, -0.5f, 0.0f }, { 1.0f, 0.0f, 0.0f } },
|
||||
{ { -0.5f, 0.5f, 0.0f }, { 0.0f, 1.0f, 0.0f } },
|
||||
{ { 0.5f, 0.5f, 0.0f }, { 0.0f, 0.0f, 1.0f } }
|
||||
};
|
||||
|
||||
uint32_t indices[] = { 0, 1, 2 };
|
||||
|
||||
dev.CreateBuffer(stagingVert, VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, sizeof(vertices), vertices);
|
||||
dev.CreateBuffer(stagingInd, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT, sizeof(indices), indices);
|
||||
for(int i = 0; i < numSwapchainImages; i++)
|
||||
{
|
||||
commandBuffers[i] = dev.CreateCommandBuffer();
|
||||
//VulkanTexture::SetImageLayout(commandBuffers[i], swapchainImages[i], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
|
||||
VkImageSubresourceRange range = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 };
|
||||
VkClearColorValue color;
|
||||
color.uint32[0] = 45243524;
|
||||
color.uint32[1] = 45234545;
|
||||
color.uint32[2] = 54353453;
|
||||
|
||||
//vkCmdClearColorImage(commandBuffers[i], swapchainImages[i],VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, &color, 1, &range );
|
||||
swapchainFbs[i].BeginRenderPass(commandBuffers[i]);
|
||||
swapchainFbs[i].SetViewportAndScissor(commandBuffers[i]);
|
||||
|
||||
vkCmdBindDescriptorSets(commandBuffers[i],VK_PIPELINE_BIND_POINT_GRAPHICS,graphicsPipeline.pipelineLayout, 0, 1, &descriptorSet, 0, nullptr);
|
||||
vkCmdBindPipeline(commandBuffers[i], VK_PIPELINE_BIND_POINT_GRAPHICS,graphicsPipeline.pipeline);
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindVertexBuffers(commandBuffers[i],0, 1, &stagingVert.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(commandBuffers[i], stagingInd.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(commandBuffers[i], 3, 1, 0, 0, 0);
|
||||
vkCmdEndRenderPass(commandBuffers[i]);
|
||||
VulkanTexture::SetImageLayout(commandBuffers[i], swapchainImages[i], VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 });
|
||||
vkEndCommandBuffer(commandBuffers[i]);
|
||||
VkFenceCreateInfo fenceCreateInfo = {};
|
||||
fenceCreateInfo.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fenceCreateInfo.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
VK_CHECK_RESULT(vkCreateFence(dev.device, &fenceCreateInfo, NULL, &chainFences[i]));
|
||||
}
|
||||
while(true)
|
||||
{
|
||||
updateUniformData();
|
||||
uint32_t idx = AcquireImage();
|
||||
VkSubmitInfo submitInfo = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
|
||||
submitInfo.pWaitSemaphores = &swapchainRenderSemaphore;
|
||||
submitInfo.waitSemaphoreCount = 1;
|
||||
submitInfo.pSignalSemaphores = &swapchainPresentSemaphore;
|
||||
submitInfo.signalSemaphoreCount = 1;
|
||||
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffers[idx];
|
||||
VkPipelineStageFlags waitDstStageMask = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
submitInfo.pWaitDstStageMask = &waitDstStageMask;
|
||||
waitFence(idx);
|
||||
vkResetFences(dev.device,1, &chainFences[idx]);
|
||||
vkQueueSubmit(dev.defautQueue, 1, &submitInfo, chainFences[idx]);
|
||||
PresentImage(idx);
|
||||
}
|
||||
vkDeviceWaitIdle(dev.device);
|
||||
graphicsPipeline.Destroy();
|
||||
stagingVert.Destroy();
|
||||
stagingInd.Destroy();
|
||||
uboBuf.Destroy();
|
||||
DestroySwapchain();
|
||||
DestroyWindow();
|
||||
dev.Destroy();
|
||||
context.Destroy();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
GraphicsApplication app;
|
||||
app.Run();
|
||||
return EXIT_SUCCESS;
|
||||
}
|
359
vulkan_utl.h
359
vulkan_utl.h
|
@ -91,6 +91,9 @@ struct VulkanContext
|
|||
enabledExtensions[enabledExtensionsCount++] = VK_KHR_EXTERNAL_MEMORY_CAPABILITIES_EXTENSION_NAME;
|
||||
enabledExtensions[enabledExtensionsCount++] = VK_KHR_EXTERNAL_SEMAPHORE_CAPABILITIES_EXTENSION_NAME;
|
||||
enabledExtensions[enabledExtensionsCount++] = VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME;
|
||||
enabledExtensions[enabledExtensionsCount++] = VK_KHR_SURFACE_EXTENSION_NAME;
|
||||
enabledExtensions[enabledExtensionsCount++] = "VK_KHR_xlib_surface";
|
||||
|
||||
if (enableValidationLayers) {
|
||||
/*
|
||||
We get all supported layers with vkEnumerateInstanceLayerProperties.
|
||||
|
@ -157,8 +160,9 @@ struct VulkanContext
|
|||
.ppEnabledExtensionNames = (const char* const*)enabledExtensions,
|
||||
};
|
||||
|
||||
VkResult res = vkCreateInstance(&instance_info, NULL, &instance);
|
||||
if (res == VK_SUCCESS && enableValidationLayers) {
|
||||
VkResult res1 = vkCreateInstance(&instance_info, NULL, &instance);
|
||||
VK_CHECK_RESULT(res1);
|
||||
if (enableValidationLayers) {
|
||||
VkDebugReportCallbackCreateInfoEXT createInfo = {};
|
||||
createInfo.sType = VK_STRUCTURE_TYPE_DEBUG_REPORT_CALLBACK_CREATE_INFO_EXT;
|
||||
createInfo.flags = VK_DEBUG_REPORT_ERROR_BIT_EXT | VK_DEBUG_REPORT_WARNING_BIT_EXT | VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT;
|
||||
|
@ -174,7 +178,7 @@ struct VulkanContext
|
|||
else
|
||||
printf("Failed to register debug callback: null function\n");
|
||||
}
|
||||
return res;
|
||||
return res1;
|
||||
}
|
||||
VkPhysicalDevice FindPhysicalDevice()
|
||||
{
|
||||
|
@ -259,25 +263,6 @@ struct VulkanBuffer
|
|||
}
|
||||
};
|
||||
|
||||
VkPipelineShaderStageCreateInfo LoadShader(VkDevice device, const uint32_t* code, size_t size, VkShaderStageFlagBits stage)
|
||||
{
|
||||
VkShaderModuleCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = size,
|
||||
.pCode = code
|
||||
};
|
||||
|
||||
VkShaderModule module;
|
||||
VK_CHECK_RESULT(vkCreateShaderModule(device, &info, NULL, &module));
|
||||
|
||||
return VkPipelineShaderStageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = stage,
|
||||
.module = module,
|
||||
.pName = "main"
|
||||
};
|
||||
}
|
||||
|
||||
struct VulkanDevice
|
||||
{
|
||||
VkPhysicalDevice physicalDevice = NULL;
|
||||
|
@ -360,7 +345,6 @@ struct VulkanDevice
|
|||
|
||||
*out_index = 0;
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
int GetAvailiableModifiersList(uint64_t *modifiers2, size_t len, VkFormat fmt)
|
||||
|
@ -405,6 +389,7 @@ struct VulkanDevice
|
|||
deviceExtensions[deviceExtensionsCount++] = VK_EXT_EXTERNAL_MEMORY_DMA_BUF_EXTENSION_NAME;
|
||||
deviceExtensions[deviceExtensionsCount++] = VK_EXT_IMAGE_DRM_FORMAT_MODIFIER_EXTENSION_NAME;
|
||||
deviceExtensions[deviceExtensionsCount++] = VK_KHR_IMAGE_FORMAT_LIST_EXTENSION_NAME;
|
||||
deviceExtensions[deviceExtensionsCount++] = VK_KHR_SWAPCHAIN_EXTENSION_NAME;
|
||||
|
||||
VkPhysicalDeviceFeatures enabled_features = {
|
||||
.samplerAnisotropy = VK_TRUE,
|
||||
|
@ -433,7 +418,7 @@ struct VulkanDevice
|
|||
return result;
|
||||
|
||||
}
|
||||
VkResult CreateBuffer(VulkanBuffer &buffer, VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_flags, VkDeviceSize size, void *data)
|
||||
VkResult CreateBuffer(VulkanBuffer &buffer, VkBufferUsageFlags usage, VkMemoryPropertyFlags memory_flags, VkDeviceSize size, void *data = NULL)
|
||||
{
|
||||
buffer.device = device;
|
||||
|
||||
|
@ -562,29 +547,113 @@ struct VulkanDevice
|
|||
|
||||
struct VulkanFramebuffer
|
||||
{
|
||||
VkDevice device;
|
||||
VkDevice device = NULL;
|
||||
struct
|
||||
{
|
||||
VkImage image;
|
||||
VkDeviceMemory mem;
|
||||
VkImageView view;
|
||||
VkFormat format;
|
||||
bool allocated = false;
|
||||
} depth = {};
|
||||
|
||||
VkImageView color_view;
|
||||
VkImageView depth_view;
|
||||
|
||||
VkImageView color_view = NULL;
|
||||
|
||||
uint32_t width, height;
|
||||
VkFramebuffer frame_buffer;
|
||||
VkRenderPass render_pass;
|
||||
VkFramebuffer frame_buffer = NULL;
|
||||
VkRenderPass render_pass = NULL;
|
||||
void Create(VkDevice d)
|
||||
{
|
||||
device = d;
|
||||
}
|
||||
void Destroy()
|
||||
{
|
||||
vkDestroyImageView(device, color_view, NULL);
|
||||
vkDestroyImageView(device, depth_view, NULL);
|
||||
if(!device)
|
||||
return;
|
||||
if(color_view)
|
||||
vkDestroyImageView(device, color_view, NULL);
|
||||
color_view = NULL;
|
||||
if(depth.view)
|
||||
vkDestroyImageView(device, depth.view, NULL);
|
||||
depth.view = NULL;
|
||||
if(depth.allocated)
|
||||
{
|
||||
if(depth.image)
|
||||
vkDestroyImage(device, depth.image, NULL);
|
||||
depth.image = NULL;
|
||||
vkFreeMemory(device, depth.mem, NULL);
|
||||
depth.mem = NULL;
|
||||
depth.allocated = false;
|
||||
}
|
||||
|
||||
vkDestroyFramebuffer(device, frame_buffer, NULL);
|
||||
if(frame_buffer)
|
||||
vkDestroyFramebuffer(device, frame_buffer, NULL);
|
||||
frame_buffer = NULL;
|
||||
|
||||
vkDestroyRenderPass(device, render_pass, NULL);
|
||||
if(render_pass)
|
||||
vkDestroyRenderPass(device, render_pass, NULL);
|
||||
render_pass = NULL;
|
||||
}
|
||||
void ImportDepthAttachment(VkImage image, VkFormat format)
|
||||
{
|
||||
depth.image = image;
|
||||
VkImageViewCreateInfo image_view = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = depth.image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = format,
|
||||
.subresourceRange =
|
||||
{
|
||||
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &image_view, NULL, &depth.view));
|
||||
}
|
||||
|
||||
void Init(VkImage color_image, VkFormat color_format, VkImage depth_image, VkFormat depth_format, uint32_t w, uint32_t h)
|
||||
void CreateDepthAttachment(VulkanDevice &dev, VkFormat format, uint32_t w, uint32_t h)
|
||||
{
|
||||
depth.format = format;
|
||||
|
||||
VkImageCreateInfo image = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO,
|
||||
.imageType = VK_IMAGE_TYPE_2D,
|
||||
.format = format,
|
||||
.extent = { .width = w, .height = h, .depth = 1 },
|
||||
.mipLevels = 1,
|
||||
.arrayLayers = 1,
|
||||
.samples = VK_SAMPLE_COUNT_1_BIT,
|
||||
.tiling = VK_IMAGE_TILING_OPTIMAL,
|
||||
.usage = VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
};
|
||||
VkImage dimage;
|
||||
VK_CHECK_RESULT(vkCreateImage(device, &image, NULL, &dimage));
|
||||
|
||||
VkMemoryRequirements mem_reqs;
|
||||
vkGetImageMemoryRequirements(device, dimage, &mem_reqs);
|
||||
|
||||
VkMemoryAllocateInfo mem_alloc = {
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO,
|
||||
.allocationSize = mem_reqs.size,
|
||||
};
|
||||
|
||||
if (!dev.GetMemoryType(mem_reqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT,
|
||||
&mem_alloc.memoryTypeIndex))
|
||||
printf("Could not find memory type.\n");
|
||||
|
||||
VK_CHECK_RESULT(vkAllocateMemory(device, &mem_alloc, NULL, &depth.mem));
|
||||
VK_CHECK_RESULT(vkBindImageMemory(device, dimage, depth.mem, 0));
|
||||
ImportDepthAttachment(dimage, format);
|
||||
depth.allocated = true;
|
||||
}
|
||||
|
||||
|
||||
void Init(VkImage color_image, VkFormat color_format, uint32_t w, uint32_t h)
|
||||
{
|
||||
width = w;
|
||||
height = h;
|
||||
|
@ -612,7 +681,7 @@ struct VulkanFramebuffer
|
|||
|
||||
// Formats
|
||||
attachmentDescs[0].format = color_format;
|
||||
attachmentDescs[1].format = depth_format;
|
||||
attachmentDescs[1].format = depth.format;
|
||||
|
||||
VkAttachmentReference colorReferences[1] = {
|
||||
{ .attachment = 0, .layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }
|
||||
|
@ -680,24 +749,7 @@ struct VulkanFramebuffer
|
|||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &imageView, NULL, &color_view));
|
||||
|
||||
|
||||
VkImageViewCreateInfo depthImageView = {
|
||||
.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO,
|
||||
.image = depth_image,
|
||||
.viewType = VK_IMAGE_VIEW_TYPE_2D,
|
||||
.format = depth_format,
|
||||
.subresourceRange = {
|
||||
.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT,
|
||||
.baseMipLevel = 0,
|
||||
.levelCount = 1,
|
||||
.baseArrayLayer = 0,
|
||||
.layerCount = 1,
|
||||
},
|
||||
};
|
||||
|
||||
VK_CHECK_RESULT(vkCreateImageView(device, &depthImageView, NULL, &depth_view));
|
||||
|
||||
VkImageView attachments[2] = { color_view, depth_view };
|
||||
VkImageView attachments[2] = { color_view, depth.view };
|
||||
|
||||
VkFramebufferCreateInfo fbufCreateInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO,
|
||||
|
@ -711,6 +763,7 @@ struct VulkanFramebuffer
|
|||
|
||||
VK_CHECK_RESULT(vkCreateFramebuffer(device, &fbufCreateInfo, NULL, &frame_buffer));
|
||||
}
|
||||
|
||||
void BeginRenderPass(VkCommandBuffer cmdBuffer)
|
||||
{
|
||||
VkClearValue clearValues[2] = { { .color = { { 0.0f, 0.0f, 0.0f, 0.0f } } },
|
||||
|
@ -741,6 +794,11 @@ struct VulkanFramebuffer
|
|||
.height = height } };
|
||||
vkCmdSetScissor(cmdBuffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
~VulkanFramebuffer()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
};
|
||||
|
||||
struct VulkanTexture
|
||||
|
@ -761,7 +819,8 @@ struct VulkanTexture
|
|||
static VkAccessFlags GetAccessFlags(VkImageLayout layout)
|
||||
{
|
||||
switch (layout) {
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED: return 0;
|
||||
case VK_IMAGE_LAYOUT_UNDEFINED:
|
||||
case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
|
||||
case VK_IMAGE_LAYOUT_GENERAL: return 0;
|
||||
case VK_IMAGE_LAYOUT_PREINITIALIZED: return VK_ACCESS_HOST_WRITE_BIT;
|
||||
case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
|
||||
|
@ -1009,7 +1068,14 @@ struct VulkanTexture
|
|||
VK_CHECK_RESULT(vkCreateImageView(device, &info, NULL, &view));
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T, typename... Args>
|
||||
struct ArrayInitializer
|
||||
{
|
||||
T array[sizeof... (Args)];
|
||||
constexpr static size_t count = sizeof... (Args);
|
||||
//ArrayInitializer(const Args&... arguments) : array({arguments...}){}
|
||||
};
|
||||
#include <math.h>
|
||||
|
||||
struct BaseVulkanPipeline
|
||||
{
|
||||
|
@ -1061,6 +1127,189 @@ struct BaseVulkanPipeline
|
|||
return ret;
|
||||
}
|
||||
|
||||
VkPipelineShaderStageCreateInfo ShaderFromFile(VkShaderModule &outShaderModule, const char *filename, VkShaderStageFlagBits stage, const char *entrypoint = "main")
|
||||
{
|
||||
// todo: rewrite this in safer way
|
||||
FILE* fp = fopen(filename, "rb");
|
||||
if (fp == NULL) {
|
||||
printf("Could not find or open file: %s\n", filename);
|
||||
}
|
||||
|
||||
// get file size.
|
||||
fseek(fp, 0, SEEK_END);
|
||||
long filesize = ftell(fp);
|
||||
fseek(fp, 0, SEEK_SET);
|
||||
|
||||
long filesizepadded = long(ceil(filesize / 4.0)) * 4;
|
||||
|
||||
uint32_t contents[filesizepadded/4];
|
||||
char *str = (char*) contents;
|
||||
fread(contents, filesize, sizeof(char), fp);
|
||||
fclose(fp);
|
||||
|
||||
// data padding.
|
||||
for (int i = filesize; i < filesizepadded; i++) {
|
||||
str[i] = 0;
|
||||
}
|
||||
|
||||
VkShaderModuleCreateInfo info = {
|
||||
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
|
||||
.codeSize = filesizepadded,
|
||||
.pCode = contents
|
||||
};
|
||||
|
||||
VK_CHECK_RESULT(vkCreateShaderModule(device, &info, NULL, &outShaderModule));
|
||||
|
||||
return VkPipelineShaderStageCreateInfo{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
.stage = stage,
|
||||
.module = outShaderModule,
|
||||
.pName = entrypoint,
|
||||
};
|
||||
}
|
||||
static VkPipelineInputAssemblyStateCreateInfo TriangleListAssembly()
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,
|
||||
.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||
.primitiveRestartEnable = VK_FALSE
|
||||
};
|
||||
}
|
||||
static VkPipelineRasterizationStateCreateInfo DefaultRasterMode()
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.depthClampEnable = VK_FALSE,
|
||||
.polygonMode = VK_POLYGON_MODE_FILL,
|
||||
.cullMode = VK_CULL_MODE_BACK_BIT,
|
||||
.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE, // todo: what default is better?
|
||||
.lineWidth = 1.0f
|
||||
};
|
||||
}
|
||||
static VkPipelineColorBlendAttachmentState DefaultBlendAttachment()
|
||||
{
|
||||
return {
|
||||
.blendEnable = VK_FALSE, .colorWriteMask = 0xf
|
||||
};
|
||||
}
|
||||
static VkPipelineColorBlendStateCreateInfo DefaultColorBlend(const VkPipelineColorBlendAttachmentState& attachment = DefaultBlendAttachment())
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments = &attachment
|
||||
};
|
||||
}
|
||||
|
||||
static VkPipelineDepthStencilStateCreateInfo DefaultDepthStencil()
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
.depthTestEnable = VK_TRUE,
|
||||
.depthWriteEnable = VK_TRUE,
|
||||
.depthCompareOp = VK_COMPARE_OP_LESS_OR_EQUAL,
|
||||
.front = { .compareOp = VK_COMPARE_OP_ALWAYS },
|
||||
.back = { .compareOp = VK_COMPARE_OP_ALWAYS }
|
||||
};
|
||||
}
|
||||
|
||||
static VkPipelineViewportStateCreateInfo DefaultViewportState()
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.viewportCount = 1U,
|
||||
.scissorCount = 1U
|
||||
};
|
||||
}
|
||||
|
||||
static VkPipelineMultisampleStateCreateInfo DefaultMultisampleState()
|
||||
{
|
||||
return {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT
|
||||
};
|
||||
}
|
||||
template <typename... Args>
|
||||
ArrayInitializer<VkDynamicState, Args...> DynamicStates(const Args&... arguments)
|
||||
{
|
||||
return {arguments...};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
ArrayInitializer<VkPipelineShaderStageCreateInfo, Args...> Stages(const Args&... arguments)
|
||||
{
|
||||
return {arguments...};
|
||||
}
|
||||
|
||||
template <typename... Args>
|
||||
ArrayInitializer<VkVertexInputBindingDescription, Args...> VertexBindings(const Args&... arguments)
|
||||
{
|
||||
return {arguments...};
|
||||
}
|
||||
template <typename... Args>
|
||||
ArrayInitializer<VkVertexInputAttributeDescription, Args...> VertexAttributes(const Args&... arguments)
|
||||
{
|
||||
return {arguments...};
|
||||
}
|
||||
VkVertexInputBindingDescription VertexBinding(uint32_t binding, uint32_t stride, VkVertexInputRate inputRate = VK_VERTEX_INPUT_RATE_VERTEX )
|
||||
{
|
||||
|
||||
return {binding, stride, inputRate};
|
||||
}
|
||||
VkVertexInputAttributeDescription VertAttrib(uint32_t location, uint32_t binding, uint32_t offset, VkFormat format = VK_FORMAT_R32G32B32_SFLOAT)
|
||||
{
|
||||
return {location, binding, format, offset};
|
||||
}
|
||||
|
||||
template <typename T1, typename T2, typename T3, typename T4>
|
||||
void CreateGraphicsPipeline(VkRenderPass renderPass, const T1 &stages,
|
||||
//const VkPipelineVertexInputStateCreateInfo &vertexInputState,
|
||||
//const VkPipelineDynamicStateCreateInfo &dynamicState,
|
||||
const T2 &vertexBindings,
|
||||
const T3 &vertexAttributes,
|
||||
const T4 &dynamicStates,
|
||||
const VkPipelineInputAssemblyStateCreateInfo &asmInfo = TriangleListAssembly(),
|
||||
const VkPipelineRasterizationStateCreateInfo &rasterInfo = DefaultRasterMode(),
|
||||
const VkPipelineViewportStateCreateInfo &viewportInfo = DefaultViewportState(),
|
||||
const VkPipelineMultisampleStateCreateInfo &multisampleState = DefaultMultisampleState(),
|
||||
const VkPipelineDepthStencilStateCreateInfo &depthStencilState = DefaultDepthStencil(),
|
||||
const VkPipelineColorBlendStateCreateInfo colorBlendState = DefaultColorBlend()
|
||||
)
|
||||
{
|
||||
VkPipelineDynamicStateCreateInfo dynamic_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.dynamicStateCount = dynamicStates.count,
|
||||
.pDynamicStates = dynamicStates.array
|
||||
};
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_state = {
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,
|
||||
.vertexBindingDescriptionCount = vertexBindings.count,
|
||||
.pVertexBindingDescriptions = vertexBindings.array,
|
||||
.vertexAttributeDescriptionCount = vertexAttributes.count,
|
||||
.pVertexAttributeDescriptions = vertexAttributes.array
|
||||
};
|
||||
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {};
|
||||
pipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipelineLayoutCreateInfo.setLayoutCount = 1;
|
||||
pipelineLayoutCreateInfo.pSetLayouts = &descriptorSetLayout;
|
||||
VK_CHECK_RESULT(vkCreatePipelineLayout(device, &pipelineLayoutCreateInfo, NULL, &pipelineLayout));
|
||||
VkGraphicsPipelineCreateInfo pipelineInfo = {VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO};
|
||||
pipelineInfo.stageCount = stages.count;
|
||||
pipelineInfo.pStages = stages.array;
|
||||
pipelineInfo.pVertexInputState = &vertex_input_state;
|
||||
pipelineInfo.pInputAssemblyState = &asmInfo;
|
||||
pipelineInfo.pViewportState = &viewportInfo;
|
||||
pipelineInfo.pRasterizationState = &rasterInfo;
|
||||
pipelineInfo.pMultisampleState = &multisampleState;
|
||||
pipelineInfo.pDepthStencilState = &depthStencilState;
|
||||
pipelineInfo.pColorBlendState = &colorBlendState;
|
||||
pipelineInfo.pDynamicState = &dynamic_state;
|
||||
pipelineInfo.renderPass = renderPass;
|
||||
pipelineInfo.layout = pipelineLayout;
|
||||
vkCreateGraphicsPipelines(device, VK_NULL_HANDLE, 1, &pipelineInfo, NULL, &pipeline);
|
||||
}
|
||||
|
||||
void CreateComputePipeline(const VkPipelineShaderStageCreateInfo &shaderStageCreateInfo)
|
||||
{
|
||||
VkPipelineLayoutCreateInfo pipelineLayoutCreateInfo = {};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue