diff --git a/assets/shaders/default.frag b/assets/shaders/default.frag index 571c04e..3f57213 100644 --- a/assets/shaders/default.frag +++ b/assets/shaders/default.frag @@ -1,10 +1,13 @@ #version 450 layout(location = 0) in vec3 fragColor; +layout(location = 1) in vec2 fragTexCoord; layout(location = 0) out vec4 outColor; +layout(binding = 1) uniform sampler2D texSampler; + void main() { - outColor = vec4(fragColor, 1.0); + outColor = texture(texSampler, fragTexCoord); } - + diff --git a/assets/shaders/default.vert b/assets/shaders/default.vert index b68f601..5510aa3 100644 --- a/assets/shaders/default.vert +++ b/assets/shaders/default.vert @@ -8,10 +8,13 @@ layout(binding = 0) uniform UniformBufferObject { 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; + gl_Position = ubo.proj * ubo.view * ubo.model * vec4(inPosition, 0.0, 1.0); + fragColor = inColor; + fragTexCoord = inTexCoord; } diff --git a/assets/textures/SegFault.jpg b/assets/textures/SegFault.jpg new file mode 100644 index 0000000..63819a8 Binary files /dev/null and b/assets/textures/SegFault.jpg differ diff --git a/scripts/compile_shader.py b/scripts/compile_shader.py index ceb7d39..ce0cb75 100644 --- a/scripts/compile_shader.py +++ b/scripts/compile_shader.py @@ -48,7 +48,7 @@ def copy_shader(source, dest): def main(): parser = argparse.ArgumentParser() parser.add_argument('--verbose', action='store_true', default=False, help='The full output will be shown') - parser.add_argument('--shader', type=str, default='./', help='The folder containing the shaders') + parser.add_argument('--shader', type=str, required=True, default='./', help='The folder containing the shaders') args = parser.parse_args() print("shader folder: " + str(args.shader)) @@ -63,7 +63,7 @@ def main(): copy_shader(shader_out, "../bin/shaders") elif sys.platform == "win32": out = Path("../bin/") - if out.exists("debug"): + if os.path.exists("debug"): copy_shader(shader_out, "../bin/debug/shaders") else: copy_shader(shader_out, "../bin/release/shaders") diff --git a/src/contrib/cppcore b/src/contrib/cppcore index 3cbea39..cef37da 160000 --- a/src/contrib/cppcore +++ b/src/contrib/cppcore @@ -1 +1 @@ -Subproject commit 3cbea39a6b70da9a9735a993882270cd5e176460 +Subproject commit cef37da2b2d8d216fb876a4d134f24ab63466b6d diff --git a/src/contrib/vcpkg b/src/contrib/vcpkg index f75c836..e7d7451 160000 --- a/src/contrib/vcpkg +++ b/src/contrib/vcpkg @@ -1 +1 @@ -Subproject commit f75c836a67777a86a2c1116a28b179827f028b66 +Subproject commit e7d7451462697d77ef319ddf2da8ff7320a82662 diff --git a/src/examples/hello_world/hello_world.cpp b/src/examples/hello_world/hello_world.cpp index c8b455b..d183bf8 100644 --- a/src/examples/hello_world/hello_world.cpp +++ b/src/examples/hello_world/hello_world.cpp @@ -6,7 +6,9 @@ using namespace segfault::core; int main(int argc, char* argv[]) { App myApp; - if (!myApp.init("hello_world", 50, 50, 400, 300, "hello, world!", false)) { + uint32_t width = 800; + uint32_t height = 600; + if (!myApp.init("hello_world", 50, 50, width, height, "hello, world!", false)) { return -1; } diff --git a/src/runtime/application/app.cpp b/src/runtime/application/app.cpp index 0920987..16e9705 100644 --- a/src/runtime/application/app.cpp +++ b/src/runtime/application/app.cpp @@ -15,14 +15,14 @@ namespace segfault::application { namespace { std::string getStartLog() { std::string entry = "===========================================================================\n"; - entry.append("| SegFault version 0.0.l |\n"); + entry.append("| SegFault version 0.0.l inited.\n"); entry.append("==========================================================================="); return entry; } std::string getEndLog() { std::string entry = "===========================================================================\n"; - entry.append("|h SegFault run finished ... |\n"); + entry.append("| SegFault run ended.\n"); entry.append("==========================================================================="); return entry; } @@ -71,6 +71,8 @@ namespace segfault::application { return nullptr; } + logMessage(LogType::Info, "SDL window initiated."); + return sdlWindow; } } @@ -130,11 +132,11 @@ namespace segfault::application { } void App::shutdown() { - if (mSdlWindow == nullptr) { - logMessage(LogType::Error, "Invalid application state, cannot shutdown."); - return; + if (mSdlWindow == nullptr || mState == ModuleState::Shutdown) { + logMessage(LogType::Warn, "App already shutdowned."); + return; } - + SDL_DestroyWindow(mSdlWindow); mSdlWindow = nullptr; mState = ModuleState::Shutdown; diff --git a/src/runtime/core/filearchive.h b/src/runtime/core/filearchive.h index fb61414..324ca5b 100644 --- a/src/runtime/core/filearchive.h +++ b/src/runtime/core/filearchive.h @@ -15,7 +15,7 @@ class FileArchive { virtual FILE *getStream() const; private: - FILE *mStream; + FILE *mStream{nullptr}; bool mCanRead{false}; bool mCanWrite{false}; }; diff --git a/src/runtime/core/segfault.h b/src/runtime/core/segfault.h index edbd2a9..d15dab7 100644 --- a/src/runtime/core/segfault.h +++ b/src/runtime/core/segfault.h @@ -62,13 +62,13 @@ namespace segfault::core { inline void logMessage(LogType type, const char* msg) { switch (type) { case LogType::Error: - std::cout << "*Err* : " << msg << std::endl; + std::cout << "*ERR* : " << msg << std::endl; break; case LogType::Warn: - std::cout << "*Warn* : " << msg << std::endl; + std::cout << "*WARN* : " << msg << std::endl; break; case LogType::Info: - std::cout << "*Info* : " << msg << std::endl; + std::cout << "*INFO* : " << msg << std::endl; break; case LogType::Print: std::cout << msg << std::endl; diff --git a/src/runtime/renderer/RHIVulkan.cpp b/src/runtime/renderer/RHIVulkan.cpp index 457f49f..bc621f9 100644 --- a/src/runtime/renderer/RHIVulkan.cpp +++ b/src/runtime/renderer/RHIVulkan.cpp @@ -7,6 +7,9 @@ #include #include +#define STB_IMAGE_IMPLEMENTATION +#include + #include #include #include @@ -22,9 +25,10 @@ namespace segfault::renderer { struct Vertex { glm::vec2 pos{}; glm::vec3 color{}; + glm::vec2 texCoord; - static std::array getAttributeDescriptions() { - std::array attributeDescriptions{}; + static std::array getAttributeDescriptions() { + std::array attributeDescriptions{}; attributeDescriptions[0].binding = 0; attributeDescriptions[0].location = 0; @@ -36,6 +40,11 @@ namespace segfault::renderer { 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; } @@ -51,10 +60,10 @@ namespace segfault::renderer { }; const std::vector 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}} }; const std::vector indices = { @@ -126,6 +135,10 @@ namespace segfault::renderer { VkDeviceMemory vertexBufferMemory{}; VkBuffer indexBuffer{}; VkDeviceMemory indexBufferMemory{}; + VkImage textureImage{}; + VkImageView textureImageView{}; + VkSampler textureSampler; + VkDeviceMemory textureImageMemory{}; RHIImpl() = default; ~RHIImpl() = default; @@ -162,11 +175,22 @@ namespace segfault::renderer { void cleanupSwapChain(); void recreateSwapChain(); uint32_t findMemoryType(uint32_t typeFilter, VkMemoryPropertyFlags properties); + void createImage(uint32_t width, uint32_t height, VkFormat format, VkImageTiling tiling, VkImageUsageFlags usage, VkMemoryPropertyFlags properties, VkImage& image, VkDeviceMemory& imageMemory); + void createTextureImage(); + VkImageView createImageView(VkImage image, VkFormat format); + void createTextureImageView(); + void createTextureSampler(); void createVertexBuffer(); void createIndexBuffer(); void createUniformBuffers(); void createDescriptorPool(); void createDescriptorSets(); + + VkCommandBuffer beginSingleTimeCommands(); + void endSingleTimeCommands(VkCommandBuffer commandBuffer); + void transitionImageLayout(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size); + void transitionImageLayout(VkImage image, VkFormat format, VkImageLayout oldLayout, VkImageLayout newLayout); + void copyBufferToImage(VkBuffer buffer, VkImage image, uint32_t width, uint32_t height); }; static std::vector readFile(const std::string& filename) { @@ -250,7 +274,11 @@ namespace segfault::renderer { swapChainAdequate = !swapChainSupport.formats.empty() && !swapChainSupport.presentModes.empty(); } - return queueFamilyIndices.isComplete() && extensionsSupported && swapChainAdequate; + VkPhysicalDeviceFeatures supportedFeatures; + vkGetPhysicalDeviceFeatures(physicalDevice, &supportedFeatures); + + return queueFamilyIndices.isComplete() && extensionsSupported && swapChainAdequate + && supportedFeatures.samplerAnisotropy; } bool RHIImpl::checkDeviceExtensionSupport(VkPhysicalDevice device) { @@ -379,6 +407,7 @@ namespace segfault::renderer { VkPhysicalDeviceFeatures deviceFeatures{}; VkDeviceCreateInfo createInfo{}; createInfo.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO; + deviceFeatures.samplerAnisotropy = VK_TRUE; createInfo.pNext = nullptr; createInfo.pQueueCreateInfos = &queueCreateInfo; @@ -506,28 +535,7 @@ namespace segfault::renderer { void RHIImpl::createImageViews() { swapChainImageViews.resize(swapChainImages.size()); for (size_t i = 0; i < swapChainImages.size(); i++) { - VkImageViewCreateInfo createInfo{}; - createInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - createInfo.image = swapChainImages[i]; - - createInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - createInfo.format = swapChainImageFormat; - - createInfo.components.r = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY; - createInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY; - - createInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - createInfo.subresourceRange.baseMipLevel = 0; - createInfo.subresourceRange.levelCount = 1; - createInfo.subresourceRange.baseArrayLayer = 0; - createInfo.subresourceRange.layerCount = 1; - - if (vkCreateImageView(device, &createInfo, nullptr, &swapChainImageViews[i]) != VK_SUCCESS) { - core::logMessage(core::LogType::Error, "failed to create image view"); - return; - } + swapChainImageViews[i] = createImageView(swapChainImages[i], swapChainImageFormat); } } @@ -591,10 +599,18 @@ namespace segfault::renderer { uboLayoutBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; uboLayoutBinding.pImmutableSamplers = nullptr; // Optional + 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 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(bindings.size()); + layoutInfo.pBindings = bindings.data(); if (vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &descriptorSetLayout) != VK_SUCCESS) { throw std::runtime_error("failed to create descriptor set layout!"); @@ -784,38 +800,13 @@ namespace segfault::renderer { } void RHIImpl::copyBuffer(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { - 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); + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); VkBufferCopy copyRegion{}; - copyRegion.srcOffset = 0; // Optional - copyRegion.dstOffset = 0; // Optional copyRegion.size = size; vkCmdCopyBuffer(commandBuffer, srcBuffer, dstBuffer, 1, ©Region); - 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); + endSingleTimeCommands(commandBuffer); } void RHIImpl::createFramebuffers() { @@ -889,7 +880,7 @@ namespace segfault::renderer { renderPassInfo.renderArea.offset = { 0, 0 }; renderPassInfo.renderArea.extent = swapChainExtent; - VkClearValue clearColor = { {{0.0f, 0.0f, 0.0f, 1.0f}} }; + VkClearValue clearColor = { {{0.5f, 0.5f, 0.5f, 1.0f}} }; renderPassInfo.clearValueCount = 1; renderPassInfo.pClearValues = &clearColor; @@ -1063,6 +1054,132 @@ namespace segfault::renderer { throw std::runtime_error("failed to find suitable memory type!"); } + void RHIImpl::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(device, &imageInfo, nullptr, &image) != VK_SUCCESS) { + throw std::runtime_error("failed to create image!"); + } + + 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("failed to allocate image memory!"); + } + + vkBindImageMemory(device, image, imageMemory, 0); + } + + void RHIImpl::createTextureImage() { + int texWidth, texHeight, texChannels; + stbi_uc *pixels = stbi_load("textures/SegFault.jpg", &texWidth, &texHeight, &texChannels, STBI_rgb_alpha); + VkDeviceSize imageSize = texWidth * texHeight * 4; + + if (pixels == nullptr) { + throw std::runtime_error("failed to load texture image!"); + } + + 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{nullptr}; + vkMapMemory(device, stagingBufferMemory, 0, imageSize, 0, &data); + memcpy(data, pixels, static_cast(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(texWidth), static_cast(texHeight)); + transitionImageLayout(textureImage, VK_FORMAT_R8G8B8A8_SRGB, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + 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); + } + + VkImageView RHIImpl::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(device, &viewInfo, nullptr, &imageView) != VK_SUCCESS) { + throw std::runtime_error("failed to create image view!"); + } + + return imageView; + } + + void RHIImpl::createTextureImageView() { + textureImageView = createImageView(textureImage, VK_FORMAT_R8G8B8A8_SRGB); + } + + void RHIImpl::createTextureSampler() { + VkSamplerCreateInfo samplerInfo{}; + samplerInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + samplerInfo.magFilter = VK_FILTER_LINEAR; + samplerInfo.minFilter = VK_FILTER_LINEAR; + + samplerInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + samplerInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + + VkPhysicalDeviceProperties properties{}; + vkGetPhysicalDeviceProperties(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(device, &samplerInfo, nullptr, &textureSampler) != VK_SUCCESS) { + throw std::runtime_error("failed to create texture sampler!"); + } + } + void RHIImpl::createVertexBuffer() { VkDeviceSize bufferSize = sizeof(vertices[0]) * vertices.size(); @@ -1095,7 +1212,8 @@ namespace segfault::renderer { memcpy(data, indices.data(), (size_t)bufferSize); vkUnmapMemory(device, stagingBufferMemory); - createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); + createBuffer(bufferSize, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, + VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, indexBuffer, indexBufferMemory); copyBuffer(stagingBuffer, indexBuffer, bufferSize); @@ -1112,24 +1230,23 @@ namespace segfault::renderer { for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) { createBuffer(bufferSize, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, - VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, - uniformBuffers[i], - uniformBuffersMemory[i]); - + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, + uniformBuffers[i], uniformBuffersMemory[i]); vkMapMemory(device, uniformBuffersMemory[i], 0, bufferSize, 0, &uniformBuffersMapped[i]); } } void RHIImpl::createDescriptorPool() { - VkDescriptorPoolSize poolSize{}; - poolSize.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; - poolSize.descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); + std::array poolSizes{}; + poolSizes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + poolSizes[0].descriptorCount = static_cast(MAX_FRAMES_IN_FLIGHT); + poolSizes[1].type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSizes[1].descriptorCount = static_cast(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(poolSizes.size()); + poolInfo.pPoolSizes = poolSizes.data(); poolInfo.maxSets = static_cast(MAX_FRAMES_IN_FLIGHT); if (vkCreateDescriptorPool(device, &poolInfo, nullptr, &descriptorPool) != VK_SUCCESS) { @@ -1156,7 +1273,31 @@ namespace segfault::renderer { bufferInfo.offset = 0; bufferInfo.range = sizeof(UniformBufferObject); - VkWriteDescriptorSet descriptorWrite{}; + VkDescriptorImageInfo imageInfo{}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = textureImageView; + imageInfo.sampler = textureSampler; + + std::array descriptorWrites{}; + + descriptorWrites[0].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[0].dstSet = 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; + + descriptorWrites[1].sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrites[1].dstSet = 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(device, static_cast(descriptorWrites.size()), descriptorWrites.data(), 0, nullptr); + /*VkWriteDescriptorSet descriptorWrite{}; descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; descriptorWrite.dstSet = descriptorSets[i]; descriptorWrite.dstBinding = 0; @@ -1169,8 +1310,139 @@ namespace segfault::renderer { descriptorWrite.pImageInfo = nullptr; // Optional descriptorWrite.pTexelBufferView = nullptr; // Optional - vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); + vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr);*/ + } + } + + VkCommandBuffer RHIImpl::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 RHIImpl::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 RHIImpl::transitionImageLayout(VkBuffer srcBuffer, VkBuffer dstBuffer, VkDeviceSize size) { + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + endSingleTimeCommands(commandBuffer); + } + + void RHIImpl::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; + + barrier.srcAccessMask = 0; // TODO + barrier.dstAccessMask = 0; // TODO + + vkCmdPipelineBarrier( + commandBuffer, + 0 /* TODO */, 0 /* TODO */, + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier + ); + + 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("unsupported layout transition!"); } + + vkCmdPipelineBarrier( + commandBuffer, + sourceStage, destinationStage, + 0, + 0, nullptr, + 0, nullptr, + 1, &barrier + ); + endSingleTimeCommands(commandBuffer); + } + + void RHIImpl::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, + ®ion + ); + + endSingleTimeCommands(commandBuffer); } RHI::RHI() : mImpl(nullptr) { @@ -1261,6 +1533,8 @@ namespace segfault::renderer { mImpl->createCommandPool(mImpl->queueFamilyIndices); mImpl->createCommandBuffer(); mImpl->createSyncObjects(); + mImpl->createTextureImage(); + mImpl->createTextureImageView(); mImpl->createVertexBuffer(); mImpl->createIndexBuffer(); @@ -1269,6 +1543,11 @@ namespace segfault::renderer { bool RHI::shutdown() { mImpl->cleanupSwapChain(); + vkDestroyImage(mImpl->device, mImpl->textureImage, nullptr); + vkDestroySampler(mImpl->device, mImpl->textureSampler, nullptr); + vkDestroyImageView(mImpl->device, mImpl->textureImageView, nullptr); + + vkFreeMemory(mImpl->device, mImpl->textureImageMemory, nullptr); for (size_t i = 0; i < RHIImpl::MAX_FRAMES_IN_FLIGHT; i++) { vkDestroyBuffer(mImpl->device, mImpl->uniformBuffers[i], nullptr); vkFreeMemory(mImpl->device, mImpl->uniformBuffersMemory[i], nullptr); diff --git a/vcpkg.json b/vcpkg.json index fae77d5..6a0a087 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -3,6 +3,7 @@ "glew", "glm", "gtest", + "nlohmann-json", { "name": "sdl2", "features": [ @@ -10,6 +11,6 @@ ] }, "volk", - "nlohmann-json" + "stb" ] }