Compare commits

...

3 Commits

Author SHA1 Message Date
Ano-sys 45b362be82 Texture mapping functionallity implemented 2025-04-05 14:01:42 +02:00
Ano-sys b1c47589bc Added library requirements info at the top 2025-04-05 14:00:50 +02:00
Ano-sys 997e32f9bf Added entries to copy textures to cmake output dir 2025-04-05 14:00:19 +02:00
4 changed files with 204 additions and 11 deletions
+9 -9
View File
@@ -7,26 +7,29 @@ set(GLFW_USE_WAYLAND ON)
find_package(Vulkan REQUIRED) find_package(Vulkan REQUIRED)
find_package(glfw3 3.3 REQUIRED) find_package(glfw3 3.3 REQUIRED)
# Suche nach dem glslc Compiler
find_program(GLSLC glslc) find_program(GLSLC glslc)
if(NOT GLSLC) if(NOT GLSLC)
message(FATAL_ERROR "glslc compiler not found. Please install the Vulkan SDK.") message(FATAL_ERROR "glslc compiler not found. Please install the Vulkan SDK.")
endif() endif()
# Alle Shader-Dateien im Verzeichnis ./shaders sammeln # Copy textures into cmake output
file(GLOB TEXTURE_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/textures/*"
)
foreach(TEXTURE ${TEXTURE_FILES})
file(COPY ${TEXTURE_FILES} DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/textures/")
endforeach()
# Copy shaders into cmake output
file(GLOB SHADER_FILES file(GLOB SHADER_FILES
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert" "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert"
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.frag" "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.frag"
) )
set(SPIRV_SHADERS "")
foreach(SHADER ${SHADER_FILES}) foreach(SHADER ${SHADER_FILES})
# Dateiname extrahieren
get_filename_component(SHADER_NAME ${SHADER} NAME) get_filename_component(SHADER_NAME ${SHADER} NAME)
# Zielpfad für die kompilierten Shader im Build-Verzeichnis
set(SPIRV "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_NAME}.spv") set(SPIRV "${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_NAME}.spv")
# Custom Command zum Kompilieren des Shaders
add_custom_command( add_custom_command(
OUTPUT ${SPIRV} OUTPUT ${SPIRV}
COMMAND ${GLSLC} ${SHADER} -o ${SPIRV} COMMAND ${GLSLC} ${SHADER} -o ${SPIRV}
@@ -37,10 +40,8 @@ foreach(SHADER ${SHADER_FILES})
list(APPEND SPIRV_SHADERS ${SPIRV}) list(APPEND SPIRV_SHADERS ${SPIRV})
endforeach() endforeach()
# Custom Target, das alle Shader kompiliert
add_custom_target(compile_shaders ALL DEPENDS ${SPIRV_SHADERS}) add_custom_target(compile_shaders ALL DEPENDS ${SPIRV_SHADERS})
# Das eigentliche Executable
add_executable(vulkan_test add_executable(vulkan_test
main.cpp main.cpp
vulkan/vulkan_app.cpp vulkan/vulkan_app.cpp
@@ -49,5 +50,4 @@ add_executable(vulkan_test
target_link_libraries(vulkan_test PRIVATE Vulkan::Vulkan glfw) target_link_libraries(vulkan_test PRIVATE Vulkan::Vulkan glfw)
# Sicherstellen, dass die Shader vor dem Bauen des Executables kompiliert werden
add_dependencies(vulkan_test compile_shaders) add_dependencies(vulkan_test compile_shaders)
+8 -1
View File
@@ -1,6 +1,13 @@
/**
* Required external Libraries:
* - Vulkan
* - glfw
* - glm
* - stb
*/
#define DEBUG 1 #define DEBUG 1
#include <iostream>
#include "vulkan/vulkan_app.hpp" #include "vulkan/vulkan_app.hpp"
int main(int argc, char **argv){ int main(int argc, char **argv){
+177 -1
View File
@@ -3,6 +3,9 @@
// //
#include "vulkan_app.hpp" #include "vulkan_app.hpp"
// throws duplicate include errors when in vulkan_app.hpp
#define STB_IMAGE_IMPLEMENTATION
#include <stb/stb_image.h>
namespace vapp{ namespace vapp{
const std::vector<const char*> validationLayers = { const std::vector<const char*> validationLayers = {
@@ -694,6 +697,175 @@ namespace vapp{
} }
} }
VkCommandBuffer Vulkan::beginSingleTimeCommands(){
VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
allocInfo.commandPool = commandPool;
allocInfo.commandBufferCount = 1;
VkCommandBuffer commandBuffer;
vkAllocateCommandBuffers(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 Vulkan::endSingleTimeCommands(VkCommandBuffer commandBuffer){
vkEndCommandBuffer(commandBuffer);
VkSubmitInfo submitInfo{};
submitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submitInfo.commandBufferCount = 1;
submitInfo.pCommandBuffers = &commandBuffer;
vkQueueSubmit(graphicsQueue, 1, &submitInfo, VK_NULL_HANDLE);
vkQueueWaitIdle(graphicsQueue);
vkFreeCommandBuffers(device, commandPool, 1, &commandBuffer);
}
void Vulkan::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size){
VkCommandBuffer commandBuffer = beginSingleTimeCommands();
VkBufferCopy copyRegion{};
copyRegion.size = size;
vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, &copyRegion);
endSingleTimeCommands(commandBuffer);
}
void Vulkan::transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout){
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;
VkPipelineStageFlags sourceStage;
VkPipelineStageFlags destinationStage;
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("Func: transitionImageLayout\nError: Unsupported Layout Transition!\n");
}
vkCmdPipelineBarrier(commandBuffer, sourceStage, destinationStage, 0, 0, nullptr, 0, nullptr, 1, &barrier);
endSingleTimeCommands(commandBuffer);
}
void Vulkan::copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height){
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, &region);
endSingleTimeCommands(commandBuffer);
}
void Vulkan::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; // 3D is used to store voxel volumes
imageInfo.extent.width = width;
imageInfo.extent.height = height;
imageInfo.extent.depth = 1;
imageInfo.mipLevels = 1;
imageInfo.arrayLayers = 1;
imageInfo.format = format;
imageInfo.tiling = tiling; // or LINEAR for direct memory access of texels, OPTIMAL provides efficient access from shader
imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
imageInfo.usage = usage;
imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
imageInfo.samples = VK_SAMPLE_COUNT_1_BIT;
imageInfo.flags = 0; // something tells me this has another value when using voxels
if(vkCreateImage(device, &imageInfo, nullptr, &image) != VK_SUCCESS){
throw std::runtime_error("Func: createTextureImage\nError: Failed to create Image!\n");
}
VkMemoryRequirements memRequirements;
vkGetImageMemoryRequirements(device, image, &memRequirements);
VkMemoryAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
allocInfo.allocationSize = memRequirements.size;
allocInfo.memoryTypeIndex = findMemoryType(memRequirements.memoryTypeBits, properties);
if(vkAllocateMemory(device, &allocInfo, nullptr, &imageMemory) != VK_SUCCESS){
throw std::runtime_error("Func: createTextureImage\nError: Failed to allocate memory for Image!\n");
}
vkBindImageMemory(device, image, imageMemory, 0);
}
void Vulkan::createTextureImage(){
int texWidth, texHeight, texChannels;
stbi_uc *pixels = stbi_load("textures/texture.jpeg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha);
VkDeviceSize imageSize = texWidth * texHeight * 4; // 4 bytes per pixel
if(!pixels) throw std::runtime_error("Func: createTextureImage\nError: Failed to load Texture Image!\n");
VkBuffer stagingBuffer;
VkDeviceMemory stagingBufferMemory;
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(device, stagingBufferMemory, 0, imageSize, 0, &data);
memcpy(data, pixels, static_cast<size_t>(imageSize));
vkUnmapMemory(device, stagingBufferMemory);
stbi_image_free(pixels);
createImage(texWidth, texHeight, 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>(texWidth), static_cast<uint32_t>(texHeight));
transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
vkDestroyBuffer(device, stagingBuffer, nullptr);
vkFreeMemory(device, stagingBufferMemory, nullptr);
}
uint32_t Vulkan::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties){ uint32_t Vulkan::findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties){
VkPhysicalDeviceMemoryProperties memProperties; VkPhysicalDeviceMemoryProperties memProperties;
vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties); vkGetPhysicalDeviceMemoryProperties(physicalDevice, &memProperties);
@@ -731,7 +903,7 @@ namespace vapp{
vkBindBufferMemory(device, buffer, bufferMemory, 0); vkBindBufferMemory(device, buffer, bufferMemory, 0);
} }
void Vulkan::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size){ void Vulkan::copyBufferOld(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size){
VkCommandBufferAllocateInfo allocInfo{}; VkCommandBufferAllocateInfo allocInfo{};
allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; allocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; allocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
@@ -1093,6 +1265,7 @@ namespace vapp{
createGraphicsPipeline(); createGraphicsPipeline();
createFrameBuffers(); createFrameBuffers();
createCommandPool(); createCommandPool();
createTextureImage();
createVertexBuffer(); createVertexBuffer();
createIndexBuffer(); createIndexBuffer();
createUniformBuffers(); createUniformBuffers();
@@ -1115,6 +1288,9 @@ namespace vapp{
// Vulkan // Vulkan
cleanupSwapChain(); cleanupSwapChain();
vkDestroyImage(device, textureImage, nullptr);
vkFreeMemory(device, textureImageMemory, nullptr);
for(size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++){ for(size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++){
vkDestroyBuffer(device, uniformBuffers[i], nullptr); vkDestroyBuffer(device, uniformBuffers[i], nullptr);
vkFreeMemory(device, uniformBuffersMemory[i], nullptr); vkFreeMemory(device, uniformBuffersMemory[i], nullptr);
+10
View File
@@ -149,6 +149,9 @@ namespace vapp{
VkDescriptorPool descriptorPool; VkDescriptorPool descriptorPool;
std::vector<VkDescriptorSet> descriptorSets; std::vector<VkDescriptorSet> descriptorSets;
VkImage textureImage;
VkDeviceMemory textureImageMemory;
#pragma endregion #pragma endregion
bool checkValidationLayerSupport(); bool checkValidationLayerSupport();
@@ -174,9 +177,16 @@ namespace vapp{
void createRenderPass(); void createRenderPass();
void createFrameBuffers(); void createFrameBuffers();
void createCommandPool(); void createCommandPool();
VkCommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(VkCommandBuffer commandBuffer);
void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout);
void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height);
void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory &imageMemory);
void createTextureImage();
uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties);
void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory); void createBuffer(VkDeviceSize size, VkBufferUsageFlags usage, VkMemoryPropertyFlags properties, VkBuffer &buffer, VkDeviceMemory &bufferMemory);
void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); void copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
void copyBufferOld(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size);
void createVertexBuffer(); void createVertexBuffer();
void createIndexBuffer(); void createIndexBuffer();
void createUniformBuffers(); void createUniformBuffers();