diff --git a/mdlviewer/include/mainwindow.h b/mdlviewer/include/mainwindow.h index f9af2ac..0f50f7e 100644 --- a/mdlviewer/include/mainwindow.h +++ b/mdlviewer/include/mainwindow.h @@ -1,20 +1,30 @@ #pragma once -#include -#include #include +#include +#include #include +#include #include "renderer.hpp" struct ModelInfo { int primaryID; + int gearVersion = 1; }; struct GearInfo { std::string name; Slot slot; ModelInfo modelInfo; + + std::string getMtrlPath(int raceID) { + return fmt::format("chara/equipment/e{gearId:04d}/material/v{gearVersion:04d}/mt_c{raceId:04d}e{gearId:04d}_{slot}_a.mtrl", + fmt::arg("gearId", modelInfo.primaryID), + fmt::arg("gearVersion", modelInfo.gearVersion), + fmt::arg("raceId", raceID), + fmt::arg("slot", physis_get_slot_name(slot))); + } }; class GameData; @@ -39,7 +49,9 @@ private: struct LoadedGear { GearInfo* gearInfo; physis_MDL model; + physis_Material material; RenderModel renderModel; + RenderTexture renderTexture; }; struct BoneExtra { diff --git a/mdlviewer/src/mainwindow.cpp b/mdlviewer/src/mainwindow.cpp index 4169cd9..edb6c1c 100644 --- a/mdlviewer/src/mainwindow.cpp +++ b/mdlviewer/src/mainwindow.cpp @@ -458,6 +458,14 @@ void MainWindow::reloadGearModel() { loadedGear.model = physis_mdl_parse(mdl_data.size, mdl_data.data); + std::string mtrl_path = loadedGear.gearInfo->getMtrlPath(101); + qDebug() << "MTRL path: " << mtrl_path.c_str(); + + if(physis_gamedata_exists(&data, mtrl_path.c_str())) { + qDebug() << "loading mtrl..."; + loadedGear.material = physis_material_parse(physis_gamedata_extract_file(&data, mtrl_path.c_str())); + } + lodCombo->clear(); for(int i = 0; i < loadedGear.model.num_lod; i++) lodCombo->addItem(QString::number(i)); @@ -486,6 +494,14 @@ void MainWindow::calculate_bone(physis_Skeleton& skeleton, physis_Bone& bone, co void MainWindow::reloadGearAppearance() { loadedGear.renderModel = renderer->addModel(loadedGear.model, currentLod); + if(loadedGear.material.num_textures > 0) { + auto texture = physis_texture_parse(physis_gamedata_extract_file(&data, loadedGear.material.textures[0])); + + loadedGear.renderTexture = renderer->addTexture(texture.width, texture.height, texture.rgba, texture.rgba_size); + + loadedGear.renderModel.texture = &loadedGear.renderTexture; + } + calculate_bone(skeleton, *skeleton.root_bone, nullptr); // we want to map the actual affected bones to bone ids diff --git a/renderer/include/renderer.hpp b/renderer/include/renderer.hpp index aca28f8..4219f11 100644 --- a/renderer/include/renderer.hpp +++ b/renderer/include/renderer.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include @@ -14,10 +15,19 @@ struct RenderPart { VkDeviceMemory vertexMemory, indexMemory; }; +struct RenderTexture { + VkImage handle = VK_NULL_HANDLE; + VkDeviceMemory memory = VK_NULL_HANDLE; + VkImageView view = VK_NULL_HANDLE; + VkSampler sampler = VK_NULL_HANDLE; +}; + struct RenderModel { physis_MDL model; std::vector parts; std::array boneData; + + RenderTexture* texture = nullptr; }; class Renderer { @@ -31,6 +41,7 @@ public: void resize(VkSurfaceKHR surface, int width, int height); RenderModel addModel(const physis_MDL& model, int lod); + RenderTexture addTexture(uint32_t width, uint32_t height, const uint8_t* data, uint32_t data_size); void render(std::vector models); @@ -59,7 +70,8 @@ public: VkBuffer boneInfoBuffer = VK_NULL_HANDLE; VkDeviceMemory boneInfoMemory = VK_NULL_HANDLE; VkDescriptorSetLayout setLayout = VK_NULL_HANDLE; - VkDescriptorSet set = VK_NULL_HANDLE; + + std::map cachedDescriptors; VkPipeline pipeline; VkPipelineLayout pipelineLayout; @@ -71,4 +83,16 @@ public: VkShaderModule createShaderModule(const uint32_t *code, const int length); VkShaderModule loadShaderFromDisk(const std::string_view path); + + VkCommandBuffer beginSingleTimeCommands(); + + void endSingleTimeCommands(VkCommandBuffer pT); + + void inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, + VkImageAspectFlags aspect, VkImageSubresourceRange range, + VkImageLayout oldLayout, VkImageLayout newLayout, + VkPipelineStageFlags src_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, + VkPipelineStageFlags dst_stage_mask = VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); + + VkDescriptorSet createDescriptorFor(RenderTexture& texture); }; \ No newline at end of file diff --git a/renderer/shaders/mesh.frag b/renderer/shaders/mesh.frag index efbe98f..08a7978 100644 --- a/renderer/shaders/mesh.frag +++ b/renderer/shaders/mesh.frag @@ -2,9 +2,12 @@ layout(location = 0) in vec3 inNormal; layout(location = 1) in vec3 inFragPos; +layout(location = 2) in vec2 inUV; layout(location = 0) out vec4 outColor; +layout(binding = 3) uniform sampler2D tex; + void main() { const vec3 lightPos = vec3(3); @@ -13,5 +16,5 @@ void main() { float diff = max(dot(norm, lightDir), 0.0); - outColor = vec4(1.0) * diff; + outColor = texture(tex, inUV) * diff; } diff --git a/renderer/shaders/mesh.frag.spv b/renderer/shaders/mesh.frag.spv index 1bac883..79cf7db 100644 Binary files a/renderer/shaders/mesh.frag.spv and b/renderer/shaders/mesh.frag.spv differ diff --git a/renderer/shaders/mesh.vert b/renderer/shaders/mesh.vert index bbf192a..28a5ab3 100644 --- a/renderer/shaders/mesh.vert +++ b/renderer/shaders/mesh.vert @@ -2,11 +2,13 @@ layout(location = 0) in vec3 inPosition; layout(location = 1) in vec3 inNormal; -layout(location = 2) in vec4 inBoneWeights; -layout(location = 3) in uvec4 inBoneIds; +layout(location = 2) in vec2 inUV; +layout(location = 3) in vec4 inBoneWeights; +layout(location = 4) in uvec4 inBoneIds; layout(location = 0) out vec3 outNormal; layout(location = 1) out vec3 outFragPos; +layout(location = 2) out vec2 outUV; layout(push_constant) uniform PushConstant { mat4 vp, model; @@ -31,4 +33,5 @@ void main() { gl_Position = vp * bPos; outNormal = bNor.xyz; outFragPos = vec3(model * vec4(inPosition, 1.0)); + outUV = inUV; } diff --git a/renderer/shaders/mesh.vert.spv b/renderer/shaders/mesh.vert.spv index 77595fd..e1b82a6 100644 Binary files a/renderer/shaders/mesh.vert.spv and b/renderer/shaders/mesh.vert.spv differ diff --git a/renderer/src/renderer.cpp b/renderer/src/renderer.cpp index aca280c..c328aab 100644 --- a/renderer/src/renderer.cpp +++ b/renderer/src/renderer.cpp @@ -9,6 +9,33 @@ #include #include +VkResult CreateDebugUtilsMessengerEXT( + VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo, + const VkAllocationCallbacks* pAllocator, + VkDebugUtilsMessengerEXT* pCallback) { + + // Note: It seems that static_cast<...> doesn't work. Use the C-style forced + // cast. + auto func = (PFN_vkCreateDebugUtilsMessengerEXT)vkGetInstanceProcAddr( + instance, "vkCreateDebugUtilsMessengerEXT"); + if (func != nullptr) { + return func(instance, pCreateInfo, pAllocator, pCallback); + } else { + return VK_ERROR_EXTENSION_NOT_PRESENT; + } +} + +VKAPI_ATTR VkBool32 VKAPI_CALL +DebugCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity, + VkDebugUtilsMessageTypeFlagsEXT messageType, + const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData, + void* pUserData) { + + fmt::print("{}\n", pCallbackData->pMessage); + + return VK_FALSE; +} + Renderer::Renderer() { VkApplicationInfo applicationInfo = {}; @@ -30,13 +57,28 @@ Renderer::Renderer() { } } + VkDebugUtilsMessengerCreateInfoEXT debugCreateInfo = {}; + debugCreateInfo.sType = + VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT; + debugCreateInfo.messageSeverity = + VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | + VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT; + debugCreateInfo.messageType = + VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT; + debugCreateInfo.pfnUserCallback = DebugCallback; + VkInstanceCreateInfo createInfo = {}; + createInfo.pNext = &debugCreateInfo; createInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; createInfo.ppEnabledExtensionNames = instanceExtensions.data(); createInfo.enabledExtensionCount = instanceExtensions.size(); vkCreateInstance(&createInfo, nullptr, &instance); + VkDebugUtilsMessengerEXT callback; + CreateDebugUtilsMessengerEXT(instance, &debugCreateInfo, nullptr, + &callback); + // pick physical device uint32_t deviceCount = 0; vkEnumeratePhysicalDevices(instance, &deviceCount, nullptr); @@ -440,7 +482,13 @@ void Renderer::render(std::vector models) { vkUnmapMemory(device, boneInfoMemory); } - vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &set, 0, nullptr); + if(model.texture == nullptr) + continue; + + if(!cachedDescriptors.count(model.texture->handle)) + cachedDescriptors[model.texture->handle] = createDescriptorFor(*model.texture); + + vkCmdBindDescriptorSets(commandBuffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &cachedDescriptors[model.texture->handle], 0, nullptr); for(const auto& part : model.parts) { VkDeviceSize offsets[] = {0}; @@ -646,17 +694,22 @@ void Renderer::initPipeline() { normalAttribute.location = 1; normalAttribute.offset = offsetof(Vertex, normal); + VkVertexInputAttributeDescription uvAttribute = {}; + uvAttribute.format = VK_FORMAT_R32G32_SFLOAT; + uvAttribute.location = 2; + uvAttribute.offset = offsetof(Vertex, uv); + VkVertexInputAttributeDescription boneWeightAttribute = {}; boneWeightAttribute.format = VK_FORMAT_R32G32B32_SFLOAT; - boneWeightAttribute.location = 2; + boneWeightAttribute.location = 3; boneWeightAttribute.offset = offsetof(Vertex, bone_weight); VkVertexInputAttributeDescription boneIdAttribute = {}; boneIdAttribute.format = VK_FORMAT_R8G8B8A8_UINT; - boneIdAttribute.location = 3; + boneIdAttribute.location = 4; boneIdAttribute.offset = offsetof(Vertex, bone_id); - std::array attributes = {positionAttribute, normalAttribute, boneWeightAttribute, boneIdAttribute}; + const std::array attributes = {positionAttribute, normalAttribute, uvAttribute, boneWeightAttribute, boneIdAttribute}; VkPipelineVertexInputStateCreateInfo vertexInputState = {}; vertexInputState.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; @@ -774,13 +827,19 @@ VkShaderModule Renderer::loadShaderFromDisk(const std::string_view path) { void Renderer::initDescriptors() { VkDescriptorPoolSize poolSize = {}; poolSize.type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - poolSize.descriptorCount = 1; + poolSize.descriptorCount = 50; + + VkDescriptorPoolSize poolSize2 = {}; + poolSize2.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + poolSize2.descriptorCount = 50; + + const std::array poolSizes = {poolSize, poolSize2}; VkDescriptorPoolCreateInfo poolCreateInfo = {}; poolCreateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO; - poolCreateInfo.poolSizeCount = 1; - poolCreateInfo.pPoolSizes = &poolSize; - poolCreateInfo.maxSets = 1; + poolCreateInfo.poolSizeCount = poolSizes.size(); + poolCreateInfo.pPoolSizes = poolSizes.data(); + poolCreateInfo.maxSets = 50; vkCreateDescriptorPool(device, &poolCreateInfo, nullptr, &descriptorPool); @@ -790,10 +849,18 @@ void Renderer::initDescriptors() { boneInfoBufferBinding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT; boneInfoBufferBinding.binding = 2; - VkDescriptorSetLayoutCreateInfo layoutInfo{}; + VkDescriptorSetLayoutBinding textureBinding = {}; + textureBinding.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + textureBinding.descriptorCount = 1; + textureBinding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + textureBinding.binding = 3; + + const std::array bindings = {boneInfoBufferBinding, textureBinding}; + + VkDescriptorSetLayoutCreateInfo layoutInfo = {}; layoutInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO; - layoutInfo.bindingCount = 1; - layoutInfo.pBindings = &boneInfoBufferBinding; + layoutInfo.bindingCount = bindings.size(); + layoutInfo.pBindings = bindings.data(); vkCreateDescriptorSetLayout(device, &layoutInfo, nullptr, &setLayout); @@ -802,28 +869,6 @@ void Renderer::initDescriptors() { boneInfoBuffer = buffer; boneInfoMemory = memory; - - VkDescriptorSetAllocateInfo allocateInfo = {}; - allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; - allocateInfo.descriptorPool = descriptorPool; - allocateInfo.descriptorSetCount = 1; - allocateInfo.pSetLayouts = &setLayout; - - vkAllocateDescriptorSets(device, &allocateInfo, &set); - - VkDescriptorBufferInfo bufferInfo = {}; - bufferInfo.buffer = boneInfoBuffer; - bufferInfo.range = bufferSize; - - VkWriteDescriptorSet descriptorWrite{}; - descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; - descriptorWrite.dstSet = set; - descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; - descriptorWrite.descriptorCount = 1; - descriptorWrite.pBufferInfo = &bufferInfo; - descriptorWrite.dstBinding = 2; - - vkUpdateDescriptorSets(device, 1, &descriptorWrite, 0, nullptr); } void Renderer::initDepth(int width, int height) { @@ -867,3 +912,257 @@ void Renderer::initDepth(int width, int height) { vkCreateImageView(device, &viewCreateInfo, nullptr, &depthView); } + +RenderTexture Renderer::addTexture(const uint32_t width, const uint32_t height, const uint8_t* data, const uint32_t data_size) { + RenderTexture newTexture = {}; + + 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 = VK_FORMAT_R8G8B8A8_UNORM; + imageInfo.tiling = VK_IMAGE_TILING_OPTIMAL; + imageInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; + imageInfo.usage = VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT; + imageInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + imageInfo.samples = VK_SAMPLE_COUNT_1_BIT; + + vkCreateImage(device, &imageInfo, nullptr, &newTexture.handle); + + VkMemoryRequirements memRequirements; + vkGetImageMemoryRequirements(device, newTexture.handle, &memRequirements); + + VkMemoryAllocateInfo allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = findMemoryType( + memRequirements.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + + vkAllocateMemory(device, &allocInfo, nullptr, &newTexture.memory); + + vkBindImageMemory(device, newTexture.handle, newTexture.memory, 0); + + // copy image data + VkBuffer stagingBuffer; + VkDeviceMemory stagingBufferMemory; + + VkBufferCreateInfo bufferInfo = {}; + bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO; + bufferInfo.size = data_size; + bufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; + bufferInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; + + vkCreateBuffer(device, &bufferInfo, nullptr, &stagingBuffer); + + // allocate staging memory + vkGetBufferMemoryRequirements(device, stagingBuffer, &memRequirements); + + allocInfo = {}; + allocInfo.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + allocInfo.allocationSize = memRequirements.size; + allocInfo.memoryTypeIndex = + findMemoryType(memRequirements.memoryTypeBits, + VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | + VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); + + vkAllocateMemory(device, &allocInfo, nullptr, &stagingBufferMemory); + + vkBindBufferMemory(device, stagingBuffer, stagingBufferMemory, 0); + + // copy to staging buffer + void* mapped_data; + vkMapMemory(device, stagingBufferMemory, 0, data_size, 0, &mapped_data); + memcpy(mapped_data, data, data_size); + vkUnmapMemory(device, stagingBufferMemory); + + // copy staging buffer to image + VkCommandBuffer commandBuffer = beginSingleTimeCommands(); + + VkImageSubresourceRange range = {}; + range.baseMipLevel = 0; + range.levelCount = 1; + range.baseArrayLayer = 0; + range.layerCount = 1; + + inlineTransitionImageLayout(commandBuffer, newTexture.handle, + imageInfo.format, VK_IMAGE_ASPECT_COLOR_BIT, + range, VK_IMAGE_LAYOUT_UNDEFINED, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + + VkBufferImageCopy region = {}; + region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = 0; + region.imageSubresource.layerCount = 1; + region.imageExtent = {(uint32_t)width, + (uint32_t)height, 1}; + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer, newTexture.handle, + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion); + + inlineTransitionImageLayout(commandBuffer, newTexture.handle, + imageInfo.format, VK_IMAGE_ASPECT_COLOR_BIT, + range, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); + + endSingleTimeCommands(commandBuffer); + + range = {}; + range.levelCount = 1; + range.layerCount = 1; + range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + + VkImageViewCreateInfo viewInfo = {}; + viewInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; + viewInfo.image = newTexture.handle; + viewInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; + viewInfo.format = imageInfo.format; + viewInfo.subresourceRange = range; + + vkCreateImageView(device, &viewInfo, nullptr, &newTexture.view); + + 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; + samplerInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + samplerInfo.maxLod = 1.0f; + + vkCreateSampler(device, &samplerInfo, nullptr, &newTexture.sampler); + + return newTexture; +} + +VkCommandBuffer Renderer::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 Renderer::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 Renderer::inlineTransitionImageLayout(VkCommandBuffer commandBuffer, VkImage image, VkFormat format, + VkImageAspectFlags aspect, VkImageSubresourceRange range, + VkImageLayout oldLayout, VkImageLayout newLayout, + VkPipelineStageFlags src_stage_mask, VkPipelineStageFlags dst_stage_mask) { + 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 = range; + barrier.subresourceRange.aspectMask = aspect; + + switch (oldLayout) { + case VK_IMAGE_LAYOUT_UNDEFINED: + barrier.srcAccessMask = 0; + break; + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + break; + default: + break; + } + + switch (newLayout) { + case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + break; + case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + case VK_IMAGE_LAYOUT_GENERAL: + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + break; + default: + break; + } + + vkCmdPipelineBarrier(commandBuffer, src_stage_mask, dst_stage_mask, 0, 0, + nullptr, 0, nullptr, 1, &barrier); +} + +VkDescriptorSet Renderer::createDescriptorFor(RenderTexture &texture) { + VkDescriptorSet set; + + VkDescriptorSetAllocateInfo allocateInfo = {}; + allocateInfo.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO; + allocateInfo.descriptorPool = descriptorPool; + allocateInfo.descriptorSetCount = 1; + allocateInfo.pSetLayouts = &setLayout; + + vkAllocateDescriptorSets(device, &allocateInfo, &set); + + const size_t bufferSize = sizeof(glm::mat4) * 128; + + VkDescriptorBufferInfo bufferInfo = {}; + bufferInfo.buffer = boneInfoBuffer; + bufferInfo.range = bufferSize; + + VkWriteDescriptorSet descriptorWrite = {}; + descriptorWrite.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite.dstSet = set; + descriptorWrite.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; + descriptorWrite.descriptorCount = 1; + descriptorWrite.pBufferInfo = &bufferInfo; + descriptorWrite.dstBinding = 2; + + VkDescriptorImageInfo imageInfo = {}; + imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + imageInfo.imageView = texture.view; + imageInfo.sampler = texture.sampler; + + VkWriteDescriptorSet descriptorWrite2 = {}; + descriptorWrite2.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET; + descriptorWrite2.dstSet = set; + descriptorWrite2.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + descriptorWrite2.descriptorCount = 1; + descriptorWrite2.pImageInfo = &imageInfo; + descriptorWrite2.dstBinding = 3; + + const std::array writes = {descriptorWrite, descriptorWrite2}; + + vkUpdateDescriptorSets(device, writes.size(), writes.data(), 0, nullptr); + + return set; +}