Add Texture loading and extend original functionality! this needs HEAVY documentation, which I will do tomorrow.
This commit is contained in:
parent
e2a732c98c
commit
9878070b4c
@ -5,7 +5,7 @@ caption
|
||||
//**This dictates basic flow of the vulkan boilerplate system. **//
|
||||
endcaption
|
||||
|
||||
:main;
|
||||
://**main()**//; <<procedure>>
|
||||
://**run()**//; <<procedure>>
|
||||
split
|
||||
://**initWindow()**//; <<procedure>>
|
||||
|
File diff suppressed because one or more lines are too long
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 59 KiB |
2
Makefile
2
Makefile
@ -27,7 +27,7 @@ debug: $(BIN)
|
||||
|
||||
.PHONY: dep
|
||||
dep:
|
||||
sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm gdb shaderc
|
||||
sudo pacman -S gcc glfw glm shaderc libxi libxxf86vm gdb shaderc stb
|
||||
.PHONY: info
|
||||
info:
|
||||
@echo "make: Build executable"
|
||||
|
BIN
assets/textures/test.png
Normal file
BIN
assets/textures/test.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
7988
lib/stb_image.h
Normal file
7988
lib/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,12 +1,12 @@
|
||||
#include "devicelibrary.h"
|
||||
#include "global.h"
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
|
||||
namespace DeviceControl {
|
||||
|
||||
|
||||
VkPhysicalDeviceProperties deviceProperties;
|
||||
VkPhysicalDeviceFeatures deviceFeatures;
|
||||
|
||||
std::vector<VkImage> swapChainImages;
|
||||
VkFormat swapChainImageFormat;
|
||||
@ -74,7 +74,8 @@ namespace DeviceControl {
|
||||
vkGetPhysicalDeviceProperties(device, &deviceProperties);
|
||||
// Similarly, we can pass in the device and a deviceFeatures struct, this is quite special, it holds a struct of optional features the GPU can perform.
|
||||
// Some, like a geometry shader, and stereoscopic rendering (multiViewport) we want, so we dont return true without them.
|
||||
vkGetPhysicalDeviceFeatures(device, &deviceFeatures);
|
||||
VkPhysicalDeviceFeatures supportedFeatures;
|
||||
vkGetPhysicalDeviceFeatures(device, &supportedFeatures);
|
||||
// We need to find a device that supports graphical operations, or else we cant do much with it! This function just runs over all the queueFamilies and sees if there
|
||||
// is a queue family with the VK_QUEUE_GRAPHICS_BIT flipped!
|
||||
Global::QueueFamilyIndices indices = Global::findQueueFamilies(device);
|
||||
@ -87,7 +88,7 @@ namespace DeviceControl {
|
||||
}
|
||||
|
||||
return deviceProperties.deviceType == VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU
|
||||
&& deviceFeatures.multiViewport
|
||||
&& supportedFeatures.samplerAnisotropy
|
||||
&& indices.isComplete()
|
||||
&& extensionSupported
|
||||
&& swapChainAdequate;
|
||||
@ -195,6 +196,9 @@ namespace DeviceControl {
|
||||
queueCreateSingularInfo.pQueuePriorities = &queuePriority;
|
||||
queueCreateInfos.push_back(queueCreateSingularInfo);
|
||||
}
|
||||
VkPhysicalDeviceFeatures deviceFeatures{};
|
||||
deviceFeatures.samplerAnisotropy = VK_TRUE;
|
||||
|
||||
VkDeviceCreateInfo createDeviceInfo = {};
|
||||
createDeviceInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
createDeviceInfo.pQueueCreateInfos = queueCreateInfos.data();
|
||||
@ -287,33 +291,30 @@ namespace DeviceControl {
|
||||
vkDestroySwapchainKHR(Global::device, Global::swapChain, nullptr);
|
||||
if(Global::enableValidationLayers) std::cout << "Destroyed Swap Chain safely\n" << std::endl;
|
||||
}
|
||||
VkImageView devicelibrary::createImageView(VkImage image, VkFormat format) {
|
||||
VkImageViewCreateInfo viewInfo{};
|
||||
viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
viewInfo.image = image;
|
||||
viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
viewInfo.format = format;
|
||||
viewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
viewInfo.subresourceRange.baseMipLevel = 0;
|
||||
viewInfo.subresourceRange.levelCount = 1;
|
||||
viewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
viewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageView imageView;
|
||||
if (vkCreateImageView(Global::device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image view!");
|
||||
}
|
||||
|
||||
return imageView;
|
||||
}
|
||||
void devicelibrary::createImageViews() {
|
||||
swapChainImageViews.resize(swapChainImages.size());
|
||||
for(size_t i = 0; i < swapChainImages.size(); i++) {
|
||||
VkImageViewCreateInfo createImageViewInfo{};
|
||||
createImageViewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
createImageViewInfo.image = swapChainImages[i];
|
||||
// Are we treating images as 1D, 2D or 3D?
|
||||
createImageViewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
createImageViewInfo.format = swapChainImageFormat;
|
||||
// Allow us to swizzle color channels
|
||||
createImageViewInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createImageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createImageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
createImageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
|
||||
createImageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
createImageViewInfo.subresourceRange.baseMipLevel = 0;
|
||||
createImageViewInfo.subresourceRange.levelCount = 1;
|
||||
createImageViewInfo.subresourceRange.baseArrayLayer = 0;
|
||||
// Yet another setting we would increase for VR applications, and specifically create a swap chain with more layers as well. The other layers would be the eye outputs.
|
||||
createImageViewInfo.subresourceRange.layerCount = 1;
|
||||
|
||||
if(vkCreateImageView(Global::device, &createImageViewInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image views!");
|
||||
}
|
||||
if(Global::enableValidationLayers) std::cout << "Image views created successfully\n" << std::endl;
|
||||
for (uint32_t i = 0; i < swapChainImages.size(); i++) {
|
||||
swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat);
|
||||
}
|
||||
}
|
||||
void devicelibrary::destroyImageViews() {
|
||||
|
@ -16,6 +16,7 @@ class devicelibrary {
|
||||
void destroySurface(VkInstance& instance);
|
||||
void createSwapChain(GLFWwindow* window);
|
||||
void destroySwapChain();
|
||||
VkImageView createImageView(VkImage image, VkFormat format);
|
||||
void createImageViews();
|
||||
void destroyImageViews();
|
||||
void createCommandPool();
|
||||
|
@ -3,7 +3,8 @@ DeviceControl::devicelibrary deviceLibs;
|
||||
Debug::vulkandebuglibs debugController;
|
||||
Graphics::graphicspipeline graphicsPipeline;
|
||||
RenderPresent::render renderPresentation;
|
||||
Buffers::bufferslibrary buffers;
|
||||
BuffersLibraries::buffers buffers;
|
||||
TextureLibraries::texture texture;
|
||||
VkInstance vulkaninstance;
|
||||
|
||||
// Getters and Setters!
|
||||
@ -48,7 +49,6 @@ void createInstance() {
|
||||
debugController.vulkanDebugSetup(createInfo, vulkaninstance); // Handoff to the debug library to wrap the validation libs in! (And set the window up!)
|
||||
}
|
||||
|
||||
|
||||
void initVulkan() {
|
||||
createInstance();
|
||||
debugController.setupDebugMessenger(vulkaninstance); // The debug messenger is out holy grail, it gives us Vulkan related debug info when built with the -DDEBUG flag (as per the makefile)
|
||||
@ -62,6 +62,9 @@ void initVulkan() {
|
||||
graphicsPipeline.createGraphicsPipeline();
|
||||
graphicsPipeline.createFramebuffers();
|
||||
graphicsPipeline.createCommandPool();
|
||||
texture.createTextureImage();
|
||||
texture.createTextureImageView();
|
||||
texture.createTextureSampler();
|
||||
buffers.createVertexBuffer();
|
||||
buffers.createIndexBuffer();
|
||||
buffers.createUniformBuffers();
|
||||
@ -81,6 +84,8 @@ void mainLoop() { // This loop jus
|
||||
|
||||
void cleanup() { // Similar to the last handoff, destroy the utils in a safe manner in the library!
|
||||
renderPresentation.cleanupSwapChain();
|
||||
texture.createTextureSampler();
|
||||
texture.destroyTextureImage();
|
||||
buffers.destroyUniformBuffer();
|
||||
buffers.destroyDescriptorPool();
|
||||
vkDestroyDescriptorSetLayout(Global::device, Global::descriptorSetLayout, nullptr);
|
||||
@ -95,7 +100,6 @@ void cleanup() { // Similar to th
|
||||
if(Global::enableValidationLayers) {
|
||||
debugController.DestroyDebugUtilsMessengerEXT(vulkaninstance, nullptr);
|
||||
}
|
||||
|
||||
deviceLibs.destroySurface(vulkaninstance);
|
||||
vkDestroyInstance(vulkaninstance, nullptr);
|
||||
glfwDestroyWindow(Global::window);
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "debug/vulkandebuglibs.h"
|
||||
#include "graphics/graphicspipeline.h"
|
||||
#include "graphics/render.h"
|
||||
#include "graphics/texture.h"
|
||||
#include "global.h"
|
||||
class EntryApp {
|
||||
public:
|
||||
|
@ -24,6 +24,8 @@ namespace Global {
|
||||
VkDescriptorSetLayout descriptorSetLayout;
|
||||
std::vector<VkDescriptorSet> descriptorSets;
|
||||
uint32_t currentFrame = 0;
|
||||
VkImageView textureImageView;
|
||||
VkSampler textureSampler;
|
||||
|
||||
Global::QueueFamilyIndices findQueueFamilies(VkPhysicalDevice device) {
|
||||
// First we feed in a integer we want to use to hold the number of queued items, that fills it, then we create that amount of default constructed *VkQueueFamilyProperties* structs.
|
||||
|
13
src/global.h
13
src/global.h
@ -30,6 +30,9 @@ namespace Global {
|
||||
extern VkDescriptorSetLayout descriptorSetLayout;
|
||||
extern uint32_t currentFrame;
|
||||
extern std::vector<VkDescriptorSet> descriptorSets;
|
||||
extern VkImageView textureImageView;
|
||||
extern VkSampler textureSampler;
|
||||
|
||||
struct UniformBufferObject {
|
||||
float time;
|
||||
alignas(16) glm::mat4 model;
|
||||
@ -39,6 +42,7 @@ namespace Global {
|
||||
struct Vertex {
|
||||
glm::vec2 pos;
|
||||
glm::vec3 color;
|
||||
glm::vec2 texCoord;
|
||||
|
||||
static VkVertexInputBindingDescription getBindingDescription() {
|
||||
VkVertexInputBindingDescription bindingDescription{};
|
||||
@ -48,8 +52,8 @@ namespace Global {
|
||||
|
||||
return bindingDescription;
|
||||
}
|
||||
static std::array<VkVertexInputAttributeDescription, 2> getAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 2> attributeDescriptions{};
|
||||
static std::array<VkVertexInputAttributeDescription, 3> getAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 3> attributeDescriptions{};
|
||||
|
||||
attributeDescriptions[0].binding = 0;
|
||||
attributeDescriptions[0].location = 0;
|
||||
@ -60,6 +64,11 @@ namespace Global {
|
||||
attributeDescriptions[1].location = 1;
|
||||
attributeDescriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
attributeDescriptions[1].offset = offsetof(Vertex, color);
|
||||
|
||||
attributeDescriptions[2].binding = 0;
|
||||
attributeDescriptions[2].location = 2;
|
||||
attributeDescriptions[2].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
attributeDescriptions[2].offset = offsetof(Vertex, texCoord);
|
||||
return attributeDescriptions;
|
||||
}
|
||||
};
|
||||
|
@ -16,21 +16,21 @@ std::vector<VkDeviceMemory> uniformBuffersMemory;
|
||||
std::vector<void*> uniformBuffersMapped;
|
||||
|
||||
|
||||
namespace Buffers {
|
||||
namespace BuffersLibraries {
|
||||
|
||||
|
||||
const std::vector<Global::Vertex> vertices = {
|
||||
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}}
|
||||
{{-0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}, {1.0f, 0.0f}},
|
||||
{{0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}, {0.0f, 0.0f}},
|
||||
{{0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}, {0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f}}
|
||||
};
|
||||
// Index buffer definition, showing which points to reuse.
|
||||
const std::vector<uint16_t> indices = {
|
||||
0, 1, 2, 2, 3, 0
|
||||
};
|
||||
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
||||
uint32_t buffers::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties) {
|
||||
// Graphics cards offer different types of memory to allocate from, here we query to find the right type of memory for our needs.
|
||||
// Query the available types of memory to iterate over.
|
||||
VkPhysicalDeviceMemoryProperties memProperties;
|
||||
@ -77,7 +77,7 @@ namespace Buffers {
|
||||
vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
|
||||
void buffers::createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer& buffer, VkDeviceMemory& bufferMemory) {
|
||||
VkBufferCreateInfo bufferInfo{};
|
||||
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
bufferInfo.size = size;
|
||||
@ -103,7 +103,7 @@ namespace Buffers {
|
||||
vkBindBufferMemory(Global::device, buffer, bufferMemory, 0);
|
||||
}
|
||||
|
||||
void bufferslibrary::createIndexBuffer() {
|
||||
void buffers::createIndexBuffer() {
|
||||
VkDeviceSize bufferSize = sizeof(indices[0]) * indices.size();
|
||||
|
||||
VkBuffer stagingBuffer;
|
||||
@ -123,7 +123,7 @@ namespace Buffers {
|
||||
vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
|
||||
}
|
||||
void bufferslibrary::createVertexBuffer() {
|
||||
void buffers::createVertexBuffer() {
|
||||
// Create a Vertex Buffer to hold the vertex information in memory so it doesn't have to be hardcoded!
|
||||
// Size denotes the size of the buffer in bytes, usage in this case is the buffer behaviour, using a bitwise OR.
|
||||
// Sharing mode denostes the same as the images in the swap chain! in this case, only the graphics queue uses this buffer, so we make it exclusive.
|
||||
@ -146,28 +146,29 @@ namespace Buffers {
|
||||
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
|
||||
}
|
||||
|
||||
void bufferslibrary::destroyBuffers() {
|
||||
void buffers::destroyBuffers() {
|
||||
vkDestroyBuffer(Global::device, indexBuffer, nullptr);
|
||||
vkFreeMemory(Global::device, indexBufferMemory, nullptr);
|
||||
|
||||
vkDestroyBuffer(Global::device, vertexBuffer, nullptr);
|
||||
vkFreeMemory(Global::device, vertexBufferMemory, nullptr);
|
||||
}
|
||||
VkBuffer bufferslibrary::getVertexBuffer() {
|
||||
VkBuffer buffers::getVertexBuffer() {
|
||||
return vertexBuffer;
|
||||
}
|
||||
VkBuffer bufferslibrary::getIndexBuffer() {
|
||||
VkBuffer buffers::getIndexBuffer() {
|
||||
return indexBuffer;
|
||||
}
|
||||
std::vector<Global::Vertex> bufferslibrary::getVertices() {
|
||||
std::vector<Global::Vertex> buffers::getVertices() {
|
||||
return vertices;
|
||||
}
|
||||
std::vector<uint16_t> bufferslibrary::getIndices() {
|
||||
std::vector<uint16_t> buffers::getIndices() {
|
||||
return indices;
|
||||
}
|
||||
// ------------------------------ Uniform Buffer Setup -------------------------------- //
|
||||
void bufferslibrary::createDescriptorSetLayout() {
|
||||
void buffers::createDescriptorSetLayout() {
|
||||
// Create a table of pointers to data, a Descriptor Set!
|
||||
// --------------------- UBO Layout --------------------- //
|
||||
VkDescriptorSetLayoutBinding uboLayoutBinding{};
|
||||
uboLayoutBinding.binding = 0;
|
||||
uboLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
@ -178,16 +179,25 @@ namespace Buffers {
|
||||
// Immutable Samplers is relevant for image sampling.
|
||||
uboLayoutBinding.pImmutableSamplers = nullptr;
|
||||
|
||||
// --------------- Texture Sampler Layout --------------- //
|
||||
VkDescriptorSetLayoutBinding samplerLayoutBinding{};
|
||||
samplerLayoutBinding.binding = 1;
|
||||
samplerLayoutBinding.descriptorCount = 1;
|
||||
samplerLayoutBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
samplerLayoutBinding.pImmutableSamplers = nullptr;
|
||||
samplerLayoutBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
std::array<VkDescriptorSetLayoutBinding, 2> bindings = {uboLayoutBinding, samplerLayoutBinding};
|
||||
VkDescriptorSetLayoutCreateInfo layoutInfo{};
|
||||
layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
layoutInfo.bindingCount = 1;
|
||||
layoutInfo.pBindings = &uboLayoutBinding;
|
||||
layoutInfo.bindingCount = static_cast<uint32_t>(bindings.size());
|
||||
layoutInfo.pBindings = bindings.data();
|
||||
|
||||
if(vkCreateDescriptorSetLayout(Global::device, &layoutInfo, nullptr, &Global::descriptorSetLayout) != VK_SUCCESS) {
|
||||
throw std::runtime_error("Failed to create descriptor set layout!");
|
||||
}
|
||||
}
|
||||
void bufferslibrary::createUniformBuffers() {
|
||||
void buffers::createUniformBuffers() {
|
||||
// Map the uniform buffer to memory as a pointer we can use to write data to later. This stays mapped to memory for the applications lifetime.
|
||||
// This technique is called "persistent mapping", not having to map the buffer every time we need to update it increases performance, though not free
|
||||
VkDeviceSize bufferSize = sizeof(Global::UniformBufferObject);
|
||||
@ -201,7 +211,7 @@ namespace Buffers {
|
||||
vkMapMemory(Global::device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]);
|
||||
}
|
||||
}
|
||||
void bufferslibrary::updateUniformBuffer(uint32_t currentImage) {
|
||||
void buffers::updateUniformBuffer(uint32_t currentImage) {
|
||||
// Update the uniform buffer every frame to change the position, but notably, use chrono to know exactly how much to move
|
||||
// so we aren't locked to the framerate as the world time.
|
||||
|
||||
@ -225,29 +235,31 @@ namespace Buffers {
|
||||
|
||||
memcpy(uniformBuffersMapped[currentImage], &ubo, sizeof(ubo));
|
||||
}
|
||||
void bufferslibrary::destroyUniformBuffer() {
|
||||
void buffers::destroyUniformBuffer() {
|
||||
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
vkDestroyBuffer(Global::device, uniformBuffers[i],nullptr);
|
||||
vkFreeMemory(Global::device, uniformBuffersMemory[i], nullptr);
|
||||
}
|
||||
}
|
||||
void bufferslibrary::createDescriptorPool() {
|
||||
void buffers::createDescriptorPool() {
|
||||
// Create a pool to be used to allocate descriptor sets.
|
||||
VkDescriptorPoolSize poolSize{};
|
||||
poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
poolSize.descriptorCount = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
|
||||
std::array<VkDescriptorPoolSize, 2> poolSizes{};
|
||||
poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
poolSizes[0].descriptorCount = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
|
||||
poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
poolSizes[1].descriptorCount = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
VkDescriptorPoolCreateInfo poolInfo{};
|
||||
poolInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
poolInfo.poolSizeCount = 1;
|
||||
poolInfo.pPoolSizes = &poolSize;
|
||||
poolInfo.poolSizeCount = static_cast<uint32_t>(poolSizes.size());
|
||||
poolInfo.pPoolSizes = poolSizes.data();
|
||||
poolInfo.maxSets = static_cast<uint32_t>(Global::MAX_FRAMES_IN_FLIGHT);
|
||||
|
||||
if (vkCreateDescriptorPool(Global::device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create descriptor pool!");
|
||||
}
|
||||
}
|
||||
void bufferslibrary::createDescriptorSets() {
|
||||
void buffers::createDescriptorSets() {
|
||||
std::vector<VkDescriptorSetLayout> layouts(Global::MAX_FRAMES_IN_FLIGHT, Global::descriptorSetLayout);
|
||||
VkDescriptorSetAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
@ -259,29 +271,40 @@ namespace Buffers {
|
||||
if (vkAllocateDescriptorSets(Global::device, &allocInfo, Global::descriptorSets.data()) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to allocate descriptor sets!");
|
||||
}
|
||||
for(size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
|
||||
for (size_t i = 0; i < Global::MAX_FRAMES_IN_FLIGHT; i++) {
|
||||
VkDescriptorBufferInfo bufferInfo{};
|
||||
bufferInfo.buffer = uniformBuffers[i];
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.range = sizeof(Global::UniformBufferObject);
|
||||
|
||||
VkWriteDescriptorSet descriptorWrite{};
|
||||
descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrite.dstSet = Global::descriptorSets[i];
|
||||
descriptorWrite.dstBinding = 0;
|
||||
descriptorWrite.dstArrayElement = 0;
|
||||
VkDescriptorImageInfo imageInfo{};
|
||||
imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
imageInfo.imageView = Global::textureImageView;
|
||||
imageInfo.sampler = Global::textureSampler;
|
||||
|
||||
descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptorWrite.descriptorCount = 1;
|
||||
std::array<VkWriteDescriptorSet, 2> descriptorWrites{};
|
||||
|
||||
descriptorWrite.pBufferInfo = &bufferInfo;
|
||||
descriptorWrite.pImageInfo = nullptr; // Optional
|
||||
descriptorWrite.pTexelBufferView = nullptr; // Optional
|
||||
descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrites[0].dstSet = Global::descriptorSets[i];
|
||||
descriptorWrites[0].dstBinding = 0;
|
||||
descriptorWrites[0].dstArrayElement = 0;
|
||||
descriptorWrites[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptorWrites[0].descriptorCount = 1;
|
||||
descriptorWrites[0].pBufferInfo = &bufferInfo;
|
||||
|
||||
vkUpdateDescriptorSets(Global::device, 1, &descriptorWrite, 0, nullptr);
|
||||
descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptorWrites[1].dstSet = Global::descriptorSets[i];
|
||||
descriptorWrites[1].dstBinding = 1;
|
||||
descriptorWrites[1].dstArrayElement = 0;
|
||||
descriptorWrites[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptorWrites[1].descriptorCount = 1;
|
||||
descriptorWrites[1].pImageInfo = &imageInfo;
|
||||
|
||||
vkUpdateDescriptorSets(Global::device, static_cast<uint32_t>(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr);
|
||||
}
|
||||
}
|
||||
void bufferslibrary::destroyDescriptorPool() {
|
||||
void buffers::destroyDescriptorPool() {
|
||||
vkDestroyDescriptorPool(Global::device, descriptorPool, nullptr);
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
#pragma once
|
||||
#include "../global.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace Buffers {
|
||||
class bufferslibrary {
|
||||
namespace BuffersLibraries {
|
||||
class buffers {
|
||||
public:
|
||||
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags props, VkBuffer& buffer, VkDeviceMemory& bufferMemory);
|
||||
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags flags);
|
||||
void createIndexBuffer();
|
||||
void createVertexBuffer();
|
||||
void destroyBuffers();
|
||||
|
@ -13,7 +13,7 @@ namespace Graphics {
|
||||
VkPipelineLayout pipelineLayout;
|
||||
VkPipeline graphicsPipeline;
|
||||
DeviceControl::devicelibrary deviceLibs;
|
||||
Buffers::bufferslibrary buffers;
|
||||
BuffersLibraries::buffers buffers;
|
||||
|
||||
std::vector<VkFramebuffer> swapChainFramebuffers;
|
||||
|
||||
@ -97,7 +97,7 @@ namespace Graphics {
|
||||
rasterizer.rasterizerDiscardEnable = VK_FALSE;
|
||||
// MODE_FILL, fill polygons, MODE_LINE, draw wireframe, MODE_POINT, draw vertices. Anything other than fill requires GPU feature *fillModeNonSolid*
|
||||
rasterizer.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterizer.lineWidth = 2.0f;
|
||||
rasterizer.lineWidth = 1.0f;
|
||||
// How to cull the faces, right here we cull the back faces and tell the rasterizer front facing vertices are ordered clockwise.
|
||||
rasterizer.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rasterizer.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
|
@ -9,7 +9,7 @@ namespace RenderPresent {
|
||||
std::vector<VkFence> inFlightFences;
|
||||
Graphics::graphicspipeline pipeline;
|
||||
DeviceControl::devicelibrary deviceLibs;
|
||||
Buffers::bufferslibrary buffers;
|
||||
BuffersLibraries::buffers buffers;
|
||||
|
||||
void recreateSwapChain() {
|
||||
int width = 0, height = 0;
|
||||
|
240
src/graphics/texture.cpp
Normal file
240
src/graphics/texture.cpp
Normal file
@ -0,0 +1,240 @@
|
||||
#include <vulkan/vulkan_core.h>
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include <stb/stb_image.h>
|
||||
#include "texture.h"
|
||||
#include "buffers.h"
|
||||
#include "../devicelibrary.h"
|
||||
|
||||
BuffersLibraries::buffers buffer;
|
||||
DeviceControl::devicelibrary deviceLibraries;
|
||||
VkImage textureImage;
|
||||
VkDeviceMemory textureImageMemory;
|
||||
VkPipelineStageFlags sourceStage;
|
||||
VkPipelineStageFlags destinationStage;
|
||||
|
||||
|
||||
namespace TextureLibraries {
|
||||
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory) {
|
||||
VkImageCreateInfo imageInfo{};
|
||||
imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
imageInfo.imageType = VK_IMAGE_TYPE_2D;
|
||||
imageInfo.extent.width = width;
|
||||
imageInfo.extent.height = height;
|
||||
imageInfo.extent.depth = 1;
|
||||
imageInfo.mipLevels = 1;
|
||||
imageInfo.arrayLayers = 1;
|
||||
imageInfo.format = format;
|
||||
imageInfo.tiling = tiling;
|
||||
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
imageInfo.usage = usage;
|
||||
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
if (vkCreateImage(Global::device, &imageInfo, nullptr, &image) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create image!");
|
||||
}
|
||||
|
||||
VkMemoryRequirements memRequirements;
|
||||
vkGetImageMemoryRequirements(Global::device, image, &memRequirements);
|
||||
|
||||
VkMemoryAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocInfo.allocationSize = memRequirements.size;
|
||||
allocInfo.memoryTypeIndex = buffer.findMemoryType(memRequirements.memoryTypeBits, properties);
|
||||
|
||||
if (vkAllocateMemory(Global::device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to allocate image memory!");
|
||||
}
|
||||
|
||||
vkBindImageMemory(Global::device, image, imageMemory, 0);
|
||||
}
|
||||
|
||||
VkCommandBuffer beginSingleTimeCommands() {
|
||||
// This is a neat function! This sets up a command buffer using our previously set command pool
|
||||
// to return a command buffer to execute commands!
|
||||
VkCommandBufferAllocateInfo allocInfo{};
|
||||
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocInfo.commandPool = Global::commandPool;
|
||||
allocInfo.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer commandBuffer;
|
||||
vkAllocateCommandBuffers(Global::device, &allocInfo, &commandBuffer);
|
||||
|
||||
VkCommandBufferBeginInfo beginInfo{};
|
||||
beginInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
beginInfo.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
vkBeginCommandBuffer(commandBuffer, &beginInfo);
|
||||
|
||||
return commandBuffer;
|
||||
}
|
||||
|
||||
void endSingleTimeCommands(VkCommandBuffer commandBuffer) {
|
||||
// This function takes a command buffer with the data we wish to execute and submits it to the graphics queue.
|
||||
// Afterwards, it purges the command buffer.
|
||||
vkEndCommandBuffer(commandBuffer);
|
||||
|
||||
VkSubmitInfo submitInfo{};
|
||||
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submitInfo.commandBufferCount = 1;
|
||||
submitInfo.pCommandBuffers = &commandBuffer;
|
||||
|
||||
vkQueueSubmit(Global::graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(Global::graphicsQueue);
|
||||
|
||||
vkFreeCommandBuffers(Global::device, Global::commandPool, 1, &commandBuffer);
|
||||
}
|
||||
|
||||
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) {
|
||||
// Copy 1 buffer to another.
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkBufferCopy copyRegion{};
|
||||
copyRegion.size = size;
|
||||
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout) {
|
||||
// This function handles transitioning image layout data from one layout to another.
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkImageMemoryBarrier barrier{};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = oldLayout;
|
||||
barrier.newLayout = newLayout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
if (oldLayout == VK_IMAGE_LAYOUT_UNDEFINED && newLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
} else if (oldLayout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && newLayout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
|
||||
sourceStage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destinationStage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
} else {
|
||||
throw std::invalid_argument("unsupported layout transition!");
|
||||
}
|
||||
|
||||
vkCmdPipelineBarrier(
|
||||
commandBuffer,
|
||||
sourceStage, destinationStage,
|
||||
0,
|
||||
0, nullptr,
|
||||
0, nullptr,
|
||||
1, &barrier
|
||||
);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
|
||||
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height) {
|
||||
//This handles copying from the buffer to the image, specifically what *parts* to copy to the image.
|
||||
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
|
||||
|
||||
VkBufferImageCopy region{};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {
|
||||
width,
|
||||
height,
|
||||
1
|
||||
};
|
||||
|
||||
vkCmdCopyBufferToImage(commandBuffer, buffer, image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
endSingleTimeCommands(commandBuffer);
|
||||
}
|
||||
void texture::createTextureImage() {
|
||||
int textureWidth, textureHeight, textureChannels;
|
||||
stbi_uc* pixels = stbi_load("assets/textures/test.png", &textureWidth, &textureHeight, &textureChannels, STBI_rgb_alpha);
|
||||
|
||||
VkDeviceSize imageSize = textureWidth * textureHeight * 4;
|
||||
|
||||
if(!pixels) {
|
||||
throw std::runtime_error("Failed to load texture!");
|
||||
}
|
||||
VkBuffer stagingBuffer;
|
||||
VkDeviceMemory stagingBufferMemory;
|
||||
buffer.createBuffer(imageSize, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, stagingBuffer, stagingBufferMemory);
|
||||
|
||||
void* data;
|
||||
vkMapMemory(Global::device, stagingBufferMemory, 0, imageSize, 0, &data);
|
||||
memcpy(data, pixels, static_cast<size_t>(imageSize));
|
||||
vkUnmapMemory(Global::device, stagingBufferMemory);
|
||||
|
||||
stbi_image_free(pixels);
|
||||
|
||||
createImage(textureWidth, textureHeight, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, textureImage, textureImageMemory);
|
||||
|
||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
copyBufferToImage(stagingBuffer, textureImage, static_cast<uint32_t>(textureWidth), static_cast<uint32_t>(textureHeight));
|
||||
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
vkDestroyBuffer(Global::device, stagingBuffer, nullptr);
|
||||
vkFreeMemory(Global::device, stagingBufferMemory, nullptr);
|
||||
}
|
||||
void texture::createTextureImageView() {
|
||||
Global::textureImageView = deviceLibraries.createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB);
|
||||
}
|
||||
void texture::createTextureSampler() {
|
||||
VkSamplerCreateInfo samplerInfo{};
|
||||
samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
samplerInfo.magFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
||||
samplerInfo.minFilter = VK_FILTER_LINEAR; // TODO: CUBIC
|
||||
|
||||
samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
|
||||
VkPhysicalDeviceProperties properties{};
|
||||
vkGetPhysicalDeviceProperties(Global::physicalDevice, &properties);
|
||||
samplerInfo.anisotropyEnable = VK_TRUE;
|
||||
samplerInfo.maxAnisotropy = properties.limits.maxSamplerAnisotropy;
|
||||
|
||||
samplerInfo.borderColor = VK_BORDER_COLOR_INT_OPAQUE_BLACK;
|
||||
samplerInfo.unnormalizedCoordinates = VK_FALSE;
|
||||
samplerInfo.compareEnable = VK_FALSE;
|
||||
samplerInfo.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
|
||||
samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
samplerInfo.mipLodBias = 0.0f;
|
||||
samplerInfo.minLod = 0.0f;
|
||||
samplerInfo.maxLod = 0.0f;
|
||||
|
||||
if (vkCreateSampler(Global::device, &samplerInfo, nullptr, &Global::textureSampler) != VK_SUCCESS) {
|
||||
throw std::runtime_error("failed to create texture sampler!");
|
||||
}
|
||||
}
|
||||
void texture::destroyTextureSampler() {
|
||||
vkDestroySampler(Global::device, Global::textureSampler, nullptr);
|
||||
vkDestroyImageView(Global::device, Global::textureImageView, nullptr);
|
||||
}
|
||||
void texture::destroyTextureImage() {
|
||||
vkDestroyImage(Global::device, textureImage, nullptr);
|
||||
vkFreeMemory(Global::device, textureImageMemory, nullptr);
|
||||
}
|
||||
|
||||
}
|
13
src/graphics/texture.h
Normal file
13
src/graphics/texture.h
Normal file
@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include "../global.h"
|
||||
|
||||
namespace TextureLibraries {
|
||||
class texture {
|
||||
public:
|
||||
void createTextureImage();
|
||||
void createTextureImageView();
|
||||
void createTextureSampler();
|
||||
void destroyTextureImage();
|
||||
void destroyTextureSampler();
|
||||
};
|
||||
}
|
@ -1,9 +1,11 @@
|
||||
#version 450
|
||||
layout(binding = 1) uniform sampler2D texSampler;
|
||||
|
||||
layout(location = 0) in vec3 fragColor;
|
||||
layout(location = 1) in vec2 fragTexCoord;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
void main() {
|
||||
outColor = vec4(fragColor, 1.0);
|
||||
outColor = vec4(texture(texSampler, fragTexCoord).rgb, 1.0);
|
||||
}
|
||||
|
@ -10,10 +10,13 @@ layout(binding = 0) uniform UniformBufferObject {
|
||||
// Layout assigns indices to access these inputs, dvec3 takes 2 slots so we must index it at 2. https://www.khronos.org/opengl/wiki/Layout_Qualifier_(GLSL)
|
||||
layout(location = 0) in vec2 inPosition;
|
||||
layout(location = 1) in vec3 inColor;
|
||||
layout(location = 2) in vec2 inTexCoord;
|
||||
|
||||
layout(location = 0) out vec3 fragColor;
|
||||
layout(location = 1) out vec2 fragTexCoord;
|
||||
|
||||
void main() {
|
||||
gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0);
|
||||
fragColor = inColor + sin(ubo.time*2);
|
||||
fragColor = inColor;
|
||||
fragTexCoord = inTexCoord;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user