From e18d4818cfd6cfd73a540c30dc6a87ac5b8cd7ca Mon Sep 17 00:00:00 2001 From: Karol Suprynowicz Date: Fri, 13 Dec 2024 23:32:28 +0100 Subject: [PATCH] Cleanup and fix for reflections --- .../display-plugins/VulkanDisplayPlugin.cpp | 4 +- libraries/gpu-vk/src/gpu/vk/VKBackend.cpp | 164 ++++- libraries/gpu-vk/src/gpu/vk/VKBackend.h | 61 +- libraries/gpu-vk/src/gpu/vk/VKBuffer.cpp | 3 +- libraries/gpu-vk/src/gpu/vk/VKTexture.cpp | 1 + libraries/gpu/src/gpu/Forward.h | 10 +- libraries/render-utils/src/LightingModel.cpp | 1 + libraries/vk/src/vk/Context.cpp | 11 +- libraries/vk/src/vk/Context.h | 16 - libraries/vk/src/vk/VulkanBuffer.cpp | 118 ---- libraries/vk/src/vk/VulkanBuffer.h | 2 - libraries/vk/src/vk/VulkanTexture.cpp | 661 ------------------ libraries/vk/src/vk/VulkanTexture.h | 32 - tools/gpu-frame-player/src/RenderThread.cpp | 12 +- 14 files changed, 231 insertions(+), 865 deletions(-) diff --git a/libraries/display-plugins/src/display-plugins/VulkanDisplayPlugin.cpp b/libraries/display-plugins/src/display-plugins/VulkanDisplayPlugin.cpp index 1a34589bab..b01f13716f 100644 --- a/libraries/display-plugins/src/display-plugins/VulkanDisplayPlugin.cpp +++ b/libraries/display-plugins/src/display-plugins/VulkanDisplayPlugin.cpp @@ -351,8 +351,8 @@ void VulkanDisplayPlugin::deactivate() { _container->currentDisplayActions().clear(); } - // VKTODO: Should this be here? - uncustomizeContext(); + // VKTODO: This shouldn't be here, because it's wrong thread, but then where? + //uncustomizeContext(); Parent::deactivate(); } diff --git a/libraries/gpu-vk/src/gpu/vk/VKBackend.cpp b/libraries/gpu-vk/src/gpu/vk/VKBackend.cpp index f2304ba13c..2d86921615 100644 --- a/libraries/gpu-vk/src/gpu/vk/VKBackend.cpp +++ b/libraries/gpu-vk/src/gpu/vk/VKBackend.cpp @@ -64,6 +64,8 @@ BackendPointer VKBackend::createBackend() { // FIXME provide a mechanism to override the backend for testing // Where the gpuContext is initialized and where the TRUE Backend is created and assigned std::shared_ptr result = std::make_shared(); + result->initTransform(); + result->initDefaultTexture(); INSTANCE = result.get(); void* voidInstance = &(*result); qApp->setProperty(VK_BACKEND_PROPERTY_NAME, QVariant::fromValue(voidInstance)); @@ -111,8 +113,6 @@ VKBackend::VKBackend() { _framePool.push_back(std::make_shared(this)); _framesToReuse.push_back(_framePool.back()); } - initTransform(); - initDefaultTexture(); } VKBackend::~VKBackend() { @@ -832,9 +832,8 @@ void VKBackend::setDrawCommandBuffer(VkCommandBuffer commandBuffer) { _currentCommandBuffer = commandBuffer; } -void VKBackend::trash(VKBuffer& buffer) { - // VKTODO: thread safety for this and similar calls - buffer.destroy(); +VkDescriptorImageInfo VKBackend::getDefaultTextureDescriptorInfo() { + return _defaultTextureVk->getDescriptorImageInfo(); } void VKBackend::TransformStageState::preUpdate(size_t commandIndex, const StereoState& stereo, Vec2u framebufferSize) { @@ -1224,7 +1223,7 @@ void VKBackend::updateVkDescriptorWriteSetsTexture(VkDescriptorSet target) { qDebug() << "Texture is null during descriptor " << i << " write: " << _resource._textures[i].texture->source(); } - imageInfo = _defaultTexture.descriptor; + imageInfo = _defaultTextureImageInfo; } //imageInfo.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; //imageInfo.imageView = texture->; @@ -1251,7 +1250,7 @@ void VKBackend::updateVkDescriptorWriteSetsTexture(VkDescriptorSet target) { descriptorWriteSet.dstArrayElement = 0; descriptorWriteSet.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorWriteSet.descriptorCount = 1; - descriptorWriteSet.pImageInfo = &_defaultTexture.descriptor; + descriptorWriteSet.pImageInfo = &_defaultTextureImageInfo; sets.push_back(descriptorWriteSet); } } @@ -1993,7 +1992,13 @@ void VKBackend::initDefaultTexture() { buffer[x + y * width + 3] = 255; } } - _defaultTexture.fromBuffer(buffer.data(), buffer.size(), VK_FORMAT_R8G8B8A8_SRGB, width, height, _context.device.get(), _context.transferQueue); + + _defaultTexture = gpu::Texture::create2D(gpu::Element{ gpu::VEC4, gpu::NUINT8, gpu::RGBA }, width, height, 1U, + gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR, gpu::Sampler::WRAP_CLAMP)); + _defaultTexture->setStoredMipFormat(_defaultTexture->getTexelFormat()); + _defaultTexture->assignStoredMip(0, width * height * sizeof(uint8_t) * 4, (const gpu::Byte*)buffer.data()); + _defaultTextureVk = syncGPUObject(*_defaultTexture); + _defaultTextureImageInfo = _defaultTextureVk->getDescriptorImageInfo(); } void VKBackend::acquireFrameData() { @@ -2016,6 +2021,149 @@ void VKBackend::waitForGPU() { VK_CHECK_RESULT(vkDeviceWaitIdle(_context.device->logicalDevice)); } +void VKBackend::Recycler::trashVkSampler(VkSampler& sampler) { + std::lock_guard lockGuard(recyclerMutex); + vkSamplers.push_back(sampler); +} + +void VKBackend::Recycler::trashVkFramebuffer(VkFramebuffer& framebuffer) { + std::lock_guard lockGuard(recyclerMutex); + vkFramebuffer.push_back(framebuffer); +} + +void VKBackend::Recycler::trashVkImageView(VkImageView& imageView) { + std::lock_guard lockGuard(recyclerMutex); + vkImageViews.push_back(imageView); +} + +void VKBackend::Recycler::trashVkImage(VkImage& image) { + std::lock_guard lockGuard(recyclerMutex); + vkImages.push_back(image); +} + +void VKBackend::Recycler::trashVkBuffer(VkBuffer& buffer) { + std::lock_guard lockGuard(recyclerMutex); + vkBuffers.push_back(buffer); +} + +void VKBackend::Recycler::trashVkRenderPass(VkRenderPass& renderPass) { + std::lock_guard lockGuard(recyclerMutex); + vkRenderPasses.push_back(renderPass); +} + +void VKBackend::Recycler::trashVkPipeline(VkPipeline& pipeline) { + std::lock_guard lockGuard(recyclerMutex); + vkPipelines.push_back(pipeline); +} + +void VKBackend::Recycler::trashVkShaderModule(VkShaderModule& module) { + std::lock_guard lockGuard(recyclerMutex); + vkShaderModules.push_back(module); +} + +void VKBackend::Recycler::trashVmaAllocation(VmaAllocation& allocation) { + std::lock_guard lockGuard(recyclerMutex); +} + +void VKBackend::perFrameCleanup() { + std::lock_guard lockGuard(recycler.recyclerMutex); + // Remove pointers to objects that were deleted during the frame. + for (auto framebuffer : recycler.deletedFramebuffers) { + framebuffers.erase(framebuffer); + } + + size_t capacityBeforeClear = recycler.deletedFramebuffers.capacity(); + recycler.deletedFramebuffers.resize(0); + recycler.deletedFramebuffers.reserve(capacityBeforeClear); + for (auto buffer : recycler.deletedBuffers) { + buffers.erase(buffer); + } + + capacityBeforeClear = recycler.deletedBuffers.capacity(); + recycler.deletedBuffers.resize(0); + recycler.deletedBuffers.reserve(capacityBeforeClear); + for (auto texture : recycler.deletedTextures) { + textures.erase(texture); + } + + capacityBeforeClear = recycler.deletedTextures.capacity(); + recycler.deletedTextures.resize(0); + recycler.deletedTextures.reserve(capacityBeforeClear); + for (auto query : recycler.deletedQueries) { + queries.erase(query); + } + + capacityBeforeClear = recycler.deletedQueries.capacity(); + recycler.deletedQueries.resize(0); + recycler.deletedQueries.reserve(capacityBeforeClear); + + auto device = _context.device->logicalDevice; + for (auto sampler : recycler.vkSamplers) { + vkDestroySampler(device, sampler, nullptr); + } + + for (auto imageView : recycler.vkImageViews) { + vkDestroyImageView(device, imageView, nullptr); + } + + for (auto image : recycler.vkImages) { + vkDestroyImage(device, image, nullptr); + } + + for (auto buffer : recycler.vkBuffers) { + vkDestroyBuffer(device, buffer, nullptr); + } + + for (auto renderPass: recycler.vkRenderPasses) { + vkDestroyRenderPass(device, renderPass, nullptr); + } + + for (auto pipeline: recycler.vkPipelines) { + vkDestroyPipeline(device, pipeline, nullptr); + } + + for (auto allocation : recycler.vmaAllocations) { + vmaFreeMemory(vks::Allocation::getAllocator(), allocation); + } +} + +void VKBackend::beforeShutdownCleanup() { + // Lock prevents destroying objects while hashes + std::lock_guard lockGuard(recycler.recyclerMutex); + // Remove pointers to objects that were deleted during the frame. + // This prevents access-after-delete. + perFrameCleanup(); + + // Delete remaining backend objects. + for (auto framebuffer : framebuffers) { + framebuffer->_gpuObject.gpuObject.setGPUObject(nullptr); + } + framebuffers.clear(); + + for (auto buffer : buffers) { + buffer->_gpuObject.gpuObject.setGPUObject(nullptr); + } + buffers.clear(); + + for (auto texture : textures) { + texture->_gpuObject.gpuObject.setGPUObject(nullptr); + } + textures.clear(); + + for (auto query : queries) { + query->_gpuObject.gpuObject.setGPUObject(nullptr); + } + queries.clear(); + + // Deleted objects got added to recycler, so they need to be cleaned since sets are already empty. + recycler.deletedFramebuffers.clear(); + recycler.deletedBuffers.clear(); + recycler.deletedTextures.clear(); + recycler.deletedQueries.clear(); + + // One more cleanup to destroy Vulkan objects released by backend objects. + perFrameCleanup(); +} void VKBackend::initTransform() { diff --git a/libraries/gpu-vk/src/gpu/vk/VKBackend.h b/libraries/gpu-vk/src/gpu/vk/VKBackend.h index 79313c5af5..953ae7dc79 100644 --- a/libraries/gpu-vk/src/gpu/vk/VKBackend.h +++ b/libraries/gpu-vk/src/gpu/vk/VKBackend.h @@ -263,7 +263,6 @@ protected: void updateRenderPass(); void resetRenderPass(); - // VKTODO: one instance per each frame // Contains objects that are created per frame and need to be deleted after the frame is rendered class FrameData { public: @@ -289,6 +288,46 @@ protected: VKBackend *_backend; }; + // Contains objects that need to be deleted on Vulkan backend thread after frame is rendered. + // It's filled by destructors of objects like gpu::Texture and gpu::Buffer, since these destroy + // backend counterpart of their objects. +public: + class Recycler { + public: + // This means that for every GPU object mutex will be locked and unlocked several times. + // VKTODO: It would be good to do profiling and check if it impacts performance or not. + void trashVkSampler(VkSampler &sampler); + void trashVkFramebuffer(VkFramebuffer &framebuffer); + void trashVkImageView(VkImageView &imageView); + void trashVkImage(VkImage &image); + void trashVkBuffer(VkBuffer &buffer); + void trashVkRenderPass(VkRenderPass &renderPass); + void trashVkPipeline(VkPipeline &pipeline); + void trashVkShaderModule(VkShaderModule &module); + void trashVmaAllocation(VmaAllocation &allocation); + + private: + std::recursive_mutex recyclerMutex; + + std::vector vkSamplers; + std::vector vkFramebuffer; + std::vector vkImageViews; + std::vector vkImages; + std::vector vkBuffers; + std::vector vkRenderPasses; + std::vector vkPipelines; + std::vector vkShaderModules; + std::vector vmaAllocations; + + // List of pointers to objects that were deleted and need to be removed from backend object sets. + std::vector deletedFramebuffers; + std::vector deletedBuffers; + std::vector deletedTextures; + std::vector deletedQueries; + friend class VKBackend; + } recycler; + +private: void draw(VkPrimitiveTopology mode, uint32 numVertices, uint32 startVertex); void renderPassTransfer(const Batch& batch); void renderPassDraw(const Batch& batch); @@ -320,13 +359,10 @@ public: void downloadFramebuffer(const FramebufferPointer& srcFramebuffer, const Vec4i& region, QImage& destImage) final; void setDrawCommandBuffer(VkCommandBuffer commandBuffer); size_t getNumInputBuffers() const { return _input._invalidBuffers.size(); } - VkDescriptorImageInfo getDefaultTextureDescriptorInfo() { return _defaultTexture.descriptor; }; + VkDescriptorImageInfo getDefaultTextureDescriptorInfo() ; // Used by GPU frame player to move camera around void enableContextViewCorrectionForFramePlayer() { _transform._viewCorrectionEnabledForFramePlayer = true; }; - - void trash(VKBuffer& buffer); - static gpu::Primitive getPrimitiveTopologyFromCommand(Batch::Command command, const Batch& batch, size_t paramOffset); // Draw Stage @@ -422,6 +458,17 @@ public: VKFramebuffer *_outputTexture{ nullptr }; protected: + // These are filled by syncGPUObject() calls, and are needed to track backend objects so that they can be destroyed before + // destroying backend. + // Access to these objects happens only from the backend thread. Destructors don't access them directly, but through a recycler. + std::unordered_set framebuffers; + std::unordered_set buffers; + std::unordered_set textures; + std::unordered_set queries; + void perFrameCleanup(); + // Called by the destructor + void beforeShutdownCleanup(); + // Logical device, application's view of the physical device (GPU) // VkPipeline cache object VkPipelineCache _pipelineCache; @@ -429,7 +476,9 @@ protected: vks::Context& _context{ vks::Context::get() }; //VkQueue _graphicsQueue; //TODO: initialize from device //VkQueue _transferQueue; //TODO: initialize from device - vks::Texture2D _defaultTexture; + std::shared_ptr _defaultTexture; + VKTexture* _defaultTextureVk{ nullptr }; + VkDescriptorImageInfo _defaultTextureImageInfo{}; friend class VKBuffer; friend class VKFramebuffer; VkCommandBuffer _currentCommandBuffer; diff --git a/libraries/gpu-vk/src/gpu/vk/VKBuffer.cpp b/libraries/gpu-vk/src/gpu/vk/VKBuffer.cpp index cbf6339372..f28103e30a 100644 --- a/libraries/gpu-vk/src/gpu/vk/VKBuffer.cpp +++ b/libraries/gpu-vk/src/gpu/vk/VKBuffer.cpp @@ -92,7 +92,8 @@ VKBuffer::~VKBuffer() { Backend::bufferCount.decrement(); auto backend = _backend.lock(); if (backend) { - backend->trash(*this); + backend->recycler.trashVkBuffer(buffer); + backend->recycler.trashVmaAllocation(allocation); } } diff --git a/libraries/gpu-vk/src/gpu/vk/VKTexture.cpp b/libraries/gpu-vk/src/gpu/vk/VKTexture.cpp index 7a736e9411..19a1617e26 100644 --- a/libraries/gpu-vk/src/gpu/vk/VKTexture.cpp +++ b/libraries/gpu-vk/src/gpu/vk/VKTexture.cpp @@ -241,6 +241,7 @@ void VKAttachmentTexture::createTexture(VKBackend &backend) { } VKAttachmentTexture::~VKAttachmentTexture() { + // VKTODO: Redo destructors for cleanup to happen on present thread auto backend = _backend.lock(); auto device = backend->getContext().device->logicalDevice; if (_vkImageView) { diff --git a/libraries/gpu/src/gpu/Forward.h b/libraries/gpu/src/gpu/Forward.h index a571445f27..6cc1ce3030 100644 --- a/libraries/gpu/src/gpu/Forward.h +++ b/libraries/gpu/src/gpu/Forward.h @@ -95,6 +95,11 @@ namespace gpu { class TextureTable; using TextureTablePointer = std::shared_ptr; + namespace vk { + class VKBackend; + class VKBuffer; + } + struct StereoState { StereoState() {} bool isStereo() const { @@ -127,6 +132,7 @@ namespace gpu { GPUObject* getGPUObject() const { return _gpuObject.get(); } friend class Backend; + friend class vk::VKBackend; friend class Texture; }; @@ -150,10 +156,6 @@ namespace gpu { class GLESBuffer; } - namespace vk { - class VKBackend; - class VKBuffer; - } } #endif diff --git a/libraries/render-utils/src/LightingModel.cpp b/libraries/render-utils/src/LightingModel.cpp index c1cc7c9bb4..d215a9c705 100644 --- a/libraries/render-utils/src/LightingModel.cpp +++ b/libraries/render-utils/src/LightingModel.cpp @@ -88,6 +88,7 @@ LightingModel::LightingModel() { } }); + _ambientFresnelLUT->setStoredMipFormat(_ambientFresnelLUT->getTexelFormat()); _ambientFresnelLUT->assignStoredMip(0, N_roughness * N_NdotV * sizeof(LUTVector::value_type), (const gpu::Byte*)lut.data()); } #endif diff --git a/libraries/vk/src/vk/Context.cpp b/libraries/vk/src/vk/Context.cpp index 13bafafbe1..3ad6e2f19e 100644 --- a/libraries/vk/src/vk/Context.cpp +++ b/libraries/vk/src/vk/Context.cpp @@ -193,13 +193,6 @@ void Context::createInstance() { void Context::destroyContext() { VK_CHECK_RESULT(vkQueueWaitIdle(graphicsQueue)); - for (const auto& trash : dumpster) { - trash(); - } - - while (!recycler.empty()) { - recycle(); - } device.reset(); if (enableValidation) { @@ -235,7 +228,7 @@ void Context::destroyContext() { return bestMatch; }*/ -void Context::trashCommandBuffers(const std::vector& cmdBuffers, VkCommandPool commandPool) const { +/*void Context::trashCommandBuffers(const std::vector& cmdBuffers, VkCommandPool commandPool) const { Q_ASSERT(commandPool); using DtorLambda = std::function&)>; @@ -244,7 +237,7 @@ void Context::trashCommandBuffers(const std::vector& cmdBuffers vkFreeCommandBuffers(device->logicalDevice, commandPool, cmdBuffers.size(), cmdBuffers.data()); }; trashAll(cmdBuffers, destructor); -} +}*/ void Context::emptyDumpster(VkFence fence) { VoidLambdaList newDumpster; diff --git a/libraries/vk/src/vk/Context.h b/libraries/vk/src/vk/Context.h index d5b09fc8ac..f2cde93731 100644 --- a/libraries/vk/src/vk/Context.h +++ b/libraries/vk/src/vk/Context.h @@ -131,22 +131,6 @@ public: uint32_t findQueue(const VkQueueFlags& desiredFlags, const VkSurfaceKHR& presentSurface = VkSurfaceKHR()) const; - template - void trash(T value, std::function destructor = [](T t) { t.destroy(); }) const { - if (!value) { - return; - } - dumpster.push_back([=] { destructor(value); }); - } - - template - void trashAll(const std::vector& values, std::function&)> destructor) const { - if (values.empty()) { - return; - } - dumpster.push_back([=] { destructor(values); }); - } - // // Convenience functions for trashing specific types. These functions know what kind of function // call to make for destroying a given Vulkan object. diff --git a/libraries/vk/src/vk/VulkanBuffer.cpp b/libraries/vk/src/vk/VulkanBuffer.cpp index 2adaaf1d95..e0a4fce8bf 100644 --- a/libraries/vk/src/vk/VulkanBuffer.cpp +++ b/libraries/vk/src/vk/VulkanBuffer.cpp @@ -13,40 +13,6 @@ namespace vks { - /** - * Map a memory range of this buffer. If successful, mapped points to the specified buffer range. - * - * @param size (Optional) Size of the memory range to map. Pass VK_WHOLE_SIZE to map the complete buffer range. - * @param offset (Optional) Byte offset from beginning - * - * @return VkResult of the buffer mapping call - */ - /*VkResult Buffer::map(VkDeviceSize size, VkDeviceSize offset) - { -#if VULKAN_USE_VMA - return vmaMapMemory(getAllocator(),allocation, &mapped); -#else - return vkMapMemory(device, memory, offset, size, 0, &mapped); -#endif - }*/ - - /** - * Unmap a mapped memory range - * - * @note Does not return a result as vkUnmapMemory can't fail - */ - /*void Buffer::unmap() - { - if (mapped) - { -#if VULKAN_USE_VMA - vmaUnmapMemory(getAllocator(), allocation); -#else - vkUnmapMemory(device, memory); -#endif - mapped = nullptr; - } - }*/ /** * Attach the allocated memory block to the buffer @@ -122,88 +88,4 @@ namespace vks return newBuffer; } - /** - * Copies the specified data to the mapped buffer - * - * @param data Pointer to the data to copy - * @param size Size of the data to copy in machine units - * - */ - void Buffer::copyTo(void* data, VkDeviceSize size) - { - assert(mapped); - memcpy(mapped, data, size); - } - - /** - * Flush a memory range of the buffer to make it visible to the device - * - * @note Only required for non-coherent memory - * - * @param size (Optional) Size of the memory range to flush. Pass VK_WHOLE_SIZE to flush the complete buffer range. - * @param offset (Optional) Byte offset from beginning - * - * @return VkResult of the flush call - */ - /*VkResult Buffer::flush(VkDeviceSize size, VkDeviceSize offset) - { -#if VULKAN_USE_VMA - vmaFlushAllocation(getAllocator(), allocation, offset, size); - return VK_SUCCESS; -#else - VkMappedMemoryRange mappedRange = {}; - mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mappedRange.memory = memory; - mappedRange.offset = offset; - mappedRange.size = size; - return vkFlushMappedMemoryRanges(device, 1, &mappedRange); -#endif - }*/ - - /** - * Invalidate a memory range of the buffer to make it visible to the host - * - * @note Only required for non-coherent memory - * - * @param size (Optional) Size of the memory range to invalidate. Pass VK_WHOLE_SIZE to invalidate the complete buffer range. - * @param offset (Optional) Byte offset from beginning - * - * @return VkResult of the invalidate call - */ - /*VkResult Buffer::invalidate(VkDeviceSize size, VkDeviceSize offset) - { -#if VULKAN_USE_VMA - vmaInvalidateAllocation(getAllocator(), allocation, offset, size); - return VK_SUCCESS; -#else - VkMappedMemoryRange mappedRange = {}; - mappedRange.sType = VK_STRUCTURE_TYPE_MAPPED_MEMORY_RANGE; - mappedRange.memory = memory; - mappedRange.offset = offset; - mappedRange.size = size; - return vkInvalidateMappedMemoryRanges(device, 1, &mappedRange); -#endif - }*/ - - /** - * Release all Vulkan resources held by this buffer - */ - void Buffer::destroy() - { - if (buffer) - { - vkDestroyBuffer(device, buffer, nullptr); - } - Allocation::destroy(); -#if VULKAN_USE_VMA - if (allocation) { - vmaFreeMemory(getAllocator(), allocation); - } -#else - if (memory) - { - vkFreeMemory(device, memory, nullptr); - } -#endif - } }; diff --git a/libraries/vk/src/vk/VulkanBuffer.h b/libraries/vk/src/vk/VulkanBuffer.h index 51ade4f895..5986c2fb0e 100644 --- a/libraries/vk/src/vk/VulkanBuffer.h +++ b/libraries/vk/src/vk/VulkanBuffer.h @@ -46,9 +46,7 @@ namespace vks static std::shared_ptr createUniform(VkDeviceSize bufferSize); static std::shared_ptr createStorage(VkDeviceSize bufferSize); static std::shared_ptr createVertex(VkDeviceSize bufferSize); - void copyTo(void* data, VkDeviceSize size); //VkResult flush(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); //VkResult invalidate(VkDeviceSize size = VK_WHOLE_SIZE, VkDeviceSize offset = 0); - void destroy() override; }; } \ No newline at end of file diff --git a/libraries/vk/src/vk/VulkanTexture.cpp b/libraries/vk/src/vk/VulkanTexture.cpp index 83ae6a1861..d42943118f 100644 --- a/libraries/vk/src/vk/VulkanTexture.cpp +++ b/libraries/vk/src/vk/VulkanTexture.cpp @@ -28,308 +28,6 @@ namespace vks vkFreeMemory(device->logicalDevice, deviceMemory, nullptr); } - /*ktxResult Texture::loadKTXFile(std::string filename, ktxTexture **target) - { - ktxResult result = KTX_SUCCESS; -#if defined(__ANDROID__) - AAsset* asset = AAssetManager_open(androidApp->activity->assetManager, filename.c_str(), AASSET_MODE_STREAMING); - if (!asset) { - vks::tools::exitFatal("Could not load texture from " + filename + "\n\nMake sure the assets submodule has been checked out and is up-to-date.", -1); - } - size_t size = AAsset_getLength(asset); - assert(size > 0); - ktx_uint8_t *textureData = new ktx_uint8_t[size]; - AAsset_read(asset, textureData, size); - AAsset_close(asset); - result = ktxTexture_CreateFromMemory(textureData, size, KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target); - delete[] textureData; -#else - if (!vks::tools::fileExists(filename)) { - vks::tools::exitFatal("Could not load texture from " + filename + "\n\nMake sure the assets submodule has been checked out and is up-to-date.", -1); - } - result = ktxTexture_CreateFromNamedFile(filename.c_str(), KTX_TEXTURE_CREATE_LOAD_IMAGE_DATA_BIT, target); -#endif - return result; - }*/ - - /** - * Load a 2D texture including all mip levels - * - * @param filename File to load (supports .ktx) - * @param format Vulkan format of the image data stored in the file - * @param device Vulkan device to create the texture on - * @param copyQueue Queue used for the texture staging copy commands (must support transfer) - * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT) - * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - * @param (Optional) forceLinear Force linear tiling (not advised, defaults to false) - * - */ - /*void Texture2D::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout, bool forceLinear) - { - ktxTexture* ktxTexture; - ktxResult result = loadKTXFile(filename, &ktxTexture); - assert(result == KTX_SUCCESS); - - this->device = device; - width = ktxTexture->baseWidth; - height = ktxTexture->baseHeight; - mipLevels = ktxTexture->numLevels; - - ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); - ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture); - - // Get device properties for the requested texture format - VkFormatProperties formatProperties; - vkGetPhysicalDeviceFormatProperties(device->physicalDevice, format, &formatProperties); - - // Only use linear tiling if requested (and supported by the device) - // Support for linear tiling is mostly limited, so prefer to use - // optimal tiling instead - // On most implementations linear tiling will only support a very - // limited amount of formats and features (mip maps, cubemaps, arrays, etc.) - VkBool32 useStaging = !forceLinear; - - VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - - // Use a separate command buffer for texture loading - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - if (useStaging) - { - // Create a host-visible staging buffer that contains the raw image data - VkBuffer stagingBuffer; - VkDeviceMemory stagingMemory; - - VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(); - bufferCreateInfo.size = ktxTextureSize; - // This buffer is used as a transfer source for the buffer copy - bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); - - // Get memory requirements for the staging buffer (alignment, memory type bits) - vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - // Get memory type index for a host visible buffer - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); - VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); - - // Copy texture data into staging buffer - uint8_t *data; - VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data)); - memcpy(data, ktxTextureData, ktxTextureSize); - vkUnmapMemory(device->logicalDevice, stagingMemory); - - // Setup buffer copy regions for each mip level - std::vector bufferCopyRegions; - - for (uint32_t i = 0; i < mipLevels; i++) - { - ktx_size_t offset; - KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, i, 0, 0, &offset); - assert(result == KTX_SUCCESS); - - VkBufferImageCopy bufferCopyRegion = {}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = i; - bufferCopyRegion.imageSubresource.baseArrayLayer = 0; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent.width = std::max(1u, ktxTexture->baseWidth >> i); - bufferCopyRegion.imageExtent.height = std::max(1u, ktxTexture->baseHeight >> i); - bufferCopyRegion.imageExtent.depth = 1; - bufferCopyRegion.bufferOffset = offset; - - bufferCopyRegions.push_back(bufferCopyRegion); - } - - // Create optimal tiled target image - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.mipLevels = mipLevels; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.extent = { width, height, 1 }; - imageCreateInfo.usage = imageUsageFlags; - // Ensure that the TRANSFER_DST bit is set for staging - if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) - { - imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image)); - - vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); - - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = mipLevels; - subresourceRange.layerCount = 1; - - // Image barrier for optimal image (target) - // Optimal image will be used as destination for the copy - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange); - - // Copy mip levels from staging buffer - vkCmdCopyBufferToImage( - copyCmd, - stagingBuffer, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(bufferCopyRegions.size()), - bufferCopyRegions.data() - ); - - // Change texture image layout to shader read after all mip levels have been copied - this->imageLayout = imageLayout; - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - imageLayout, - subresourceRange); - - device->flushCommandBuffer(copyCmd, copyQueue); - - // Clean up staging resources - vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); - vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); - } - else - { - // Prefer using optimal tiling, as linear tiling - // may support only a small set of features - // depending on implementation (e.g. no mip maps, only one layer, etc.) - - // Check if this support is supported for linear tiling - assert(formatProperties.linearTilingFeatures & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT); - - VkImage mappableImage; - VkDeviceMemory mappableMemory; - - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.extent = { width, height, 1 }; - imageCreateInfo.mipLevels = 1; - imageCreateInfo.arrayLayers = 1; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_LINEAR; - imageCreateInfo.usage = imageUsageFlags; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - - // Load mip map level 0 to linear tiling image - VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &mappableImage)); - - // Get memory requirements for this image - // like size and alignment - vkGetImageMemoryRequirements(device->logicalDevice, mappableImage, &memReqs); - // Set memory allocation size to required memory size - memAllocInfo.allocationSize = memReqs.size; - - // Get memory type that can be mapped to host memory - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - // Allocate host memory - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &mappableMemory)); - - // Bind allocated image for use - VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, mappableImage, mappableMemory, 0)); - - // Get sub resource layout - // Mip map count, array layer, etc. - VkImageSubresource subRes = {}; - subRes.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subRes.mipLevel = 0; - - VkSubresourceLayout subResLayout; - void *data; - - // Get sub resources layout - // Includes row pitch, size offsets, etc. - vkGetImageSubresourceLayout(device->logicalDevice, mappableImage, &subRes, &subResLayout); - - // Map image memory - VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, mappableMemory, 0, memReqs.size, 0, &data)); - - // Copy image data into memory - memcpy(data, ktxTextureData, memReqs.size); - - vkUnmapMemory(device->logicalDevice, mappableMemory); - - // Linear tiled images don't need to be staged - // and can be directly used as textures - image = mappableImage; - deviceMemory = mappableMemory; - this->imageLayout = imageLayout; - - // Setup image memory barrier - vks::tools::setImageLayout(copyCmd, image, VK_IMAGE_ASPECT_COLOR_BIT, VK_IMAGE_LAYOUT_UNDEFINED, imageLayout); - - device->flushCommandBuffer(copyCmd, copyQueue); - } - - ktxTexture_Destroy(ktxTexture); - - // Create a default sampler - VkSamplerCreateInfo samplerCreateInfo = {}; - samplerCreateInfo.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; - samplerCreateInfo.minLod = 0.0f; - // Max level-of-detail should match mip level count - samplerCreateInfo.maxLod = (useStaging) ? (float)mipLevels : 0.0f; - // Only enable anisotropic filtering if enabled on the device - samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; - samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler)); - - // Create image view - // Textures are not directly accessed by the shaders and - // are abstracted by image views containing additional - // information and sub resource ranges - VkImageViewCreateInfo viewCreateInfo = {}; - viewCreateInfo.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; - viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D; - viewCreateInfo.format = format; - viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - // Linear tiling usually won't support mip maps - // Only set mip map count if optimal tiling is used - viewCreateInfo.subresourceRange.levelCount = (useStaging) ? mipLevels : 1; - viewCreateInfo.image = image; - VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); - - // Update descriptor image info member that can be used for setting up descriptor sets - updateDescriptor(); - }*/ - /** * Creates a 2D texture from a buffer * @@ -506,364 +204,5 @@ namespace vks * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) * */ - /*void Texture2DArray::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout) - { - ktxTexture* ktxTexture; - ktxResult result = loadKTXFile(filename, &ktxTexture); - assert(result == KTX_SUCCESS); - - this->device = device; - width = ktxTexture->baseWidth; - height = ktxTexture->baseHeight; - layerCount = ktxTexture->numLayers; - mipLevels = ktxTexture->numLevels; - - ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); - ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture); - - VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - - // Create a host-visible staging buffer that contains the raw image data - VkBuffer stagingBuffer; - VkDeviceMemory stagingMemory; - - VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(); - bufferCreateInfo.size = ktxTextureSize; - // This buffer is used as a transfer source for the buffer copy - bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); - - // Get memory requirements for the staging buffer (alignment, memory type bits) - vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - // Get memory type index for a host visible buffer - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); - VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); - - // Copy texture data into staging buffer - uint8_t *data; - VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data)); - memcpy(data, ktxTextureData, ktxTextureSize); - vkUnmapMemory(device->logicalDevice, stagingMemory); - - // Setup buffer copy regions for each layer including all of its miplevels - std::vector bufferCopyRegions; - - for (uint32_t layer = 0; layer < layerCount; layer++) - { - for (uint32_t level = 0; level < mipLevels; level++) - { - ktx_size_t offset; - KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, level, layer, 0, &offset); - assert(result == KTX_SUCCESS); - - VkBufferImageCopy bufferCopyRegion = {}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = level; - bufferCopyRegion.imageSubresource.baseArrayLayer = layer; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> level; - bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> level; - bufferCopyRegion.imageExtent.depth = 1; - bufferCopyRegion.bufferOffset = offset; - - bufferCopyRegions.push_back(bufferCopyRegion); - } - } - - // Create optimal tiled target image - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.extent = { width, height, 1 }; - imageCreateInfo.usage = imageUsageFlags; - // Ensure that the TRANSFER_DST bit is set for staging - if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) - { - imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - imageCreateInfo.arrayLayers = layerCount; - imageCreateInfo.mipLevels = mipLevels; - - VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image)); - - vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); - - // Use a separate command buffer for texture loading - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Image barrier for optimal image (target) - // Set initial layout for all array layers (faces) of the optimal (target) tiled texture - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = mipLevels; - subresourceRange.layerCount = layerCount; - - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange); - - // Copy the layers and mip levels from the staging buffer to the optimal tiled image - vkCmdCopyBufferToImage( - copyCmd, - stagingBuffer, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(bufferCopyRegions.size()), - bufferCopyRegions.data()); - - // Change texture image layout to shader read after all faces have been copied - this->imageLayout = imageLayout; - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - imageLayout, - subresourceRange); - - device->flushCommandBuffer(copyCmd, copyQueue); - - // Create sampler - VkSamplerCreateInfo samplerCreateInfo = vks::initializers::samplerCreateInfo(); - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU; - samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; - samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; - samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; - samplerCreateInfo.minLod = 0.0f; - samplerCreateInfo.maxLod = (float)mipLevels; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler)); - - // Create image view - VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo(); - viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_2D_ARRAY; - viewCreateInfo.format = format; - viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - viewCreateInfo.subresourceRange.layerCount = layerCount; - viewCreateInfo.subresourceRange.levelCount = mipLevels; - viewCreateInfo.image = image; - VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); - - // Clean up staging resources - ktxTexture_Destroy(ktxTexture); - vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); - vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); - - // Update descriptor image info member that can be used for setting up descriptor sets - updateDescriptor(); - }*/ - - /** - * Load a cubemap texture including all mip levels from a single file - * - * @param filename File to load (supports .ktx) - * @param format Vulkan format of the image data stored in the file - * @param device Vulkan device to create the texture on - * @param copyQueue Queue used for the texture staging copy commands (must support transfer) - * @param (Optional) imageUsageFlags Usage flags for the texture's image (defaults to VK_IMAGE_USAGE_SAMPLED_BIT) - * @param (Optional) imageLayout Usage layout for the texture (defaults VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) - * - */ - /*void TextureCubeMap::loadFromFile(std::string filename, VkFormat format, vks::VulkanDevice *device, VkQueue copyQueue, VkImageUsageFlags imageUsageFlags, VkImageLayout imageLayout) - { - ktxTexture* ktxTexture; - ktxResult result = loadKTXFile(filename, &ktxTexture); - assert(result == KTX_SUCCESS); - - this->device = device; - width = ktxTexture->baseWidth; - height = ktxTexture->baseHeight; - mipLevels = ktxTexture->numLevels; - - ktx_uint8_t *ktxTextureData = ktxTexture_GetData(ktxTexture); - ktx_size_t ktxTextureSize = ktxTexture_GetSize(ktxTexture); - - VkMemoryAllocateInfo memAllocInfo = vks::initializers::memoryAllocateInfo(); - VkMemoryRequirements memReqs; - - // Create a host-visible staging buffer that contains the raw image data - VkBuffer stagingBuffer; - VkDeviceMemory stagingMemory; - - VkBufferCreateInfo bufferCreateInfo = vks::initializers::bufferCreateInfo(); - bufferCreateInfo.size = ktxTextureSize; - // This buffer is used as a transfer source for the buffer copy - bufferCreateInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT; - bufferCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - - VK_CHECK_RESULT(vkCreateBuffer(device->logicalDevice, &bufferCreateInfo, nullptr, &stagingBuffer)); - - // Get memory requirements for the staging buffer (alignment, memory type bits) - vkGetBufferMemoryRequirements(device->logicalDevice, stagingBuffer, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - // Get memory type index for a host visible buffer - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT); - - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &stagingMemory)); - VK_CHECK_RESULT(vkBindBufferMemory(device->logicalDevice, stagingBuffer, stagingMemory, 0)); - - // Copy texture data into staging buffer - uint8_t *data; - VK_CHECK_RESULT(vkMapMemory(device->logicalDevice, stagingMemory, 0, memReqs.size, 0, (void **)&data)); - memcpy(data, ktxTextureData, ktxTextureSize); - vkUnmapMemory(device->logicalDevice, stagingMemory); - - // Setup buffer copy regions for each face including all of its mip levels - std::vector bufferCopyRegions; - - for (uint32_t face = 0; face < 6; face++) - { - for (uint32_t level = 0; level < mipLevels; level++) - { - ktx_size_t offset; - KTX_error_code result = ktxTexture_GetImageOffset(ktxTexture, level, 0, face, &offset); - assert(result == KTX_SUCCESS); - - VkBufferImageCopy bufferCopyRegion = {}; - bufferCopyRegion.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - bufferCopyRegion.imageSubresource.mipLevel = level; - bufferCopyRegion.imageSubresource.baseArrayLayer = face; - bufferCopyRegion.imageSubresource.layerCount = 1; - bufferCopyRegion.imageExtent.width = ktxTexture->baseWidth >> level; - bufferCopyRegion.imageExtent.height = ktxTexture->baseHeight >> level; - bufferCopyRegion.imageExtent.depth = 1; - bufferCopyRegion.bufferOffset = offset; - - bufferCopyRegions.push_back(bufferCopyRegion); - } - } - - // Create optimal tiled target image - VkImageCreateInfo imageCreateInfo = vks::initializers::imageCreateInfo(); - imageCreateInfo.imageType = VK_IMAGE_TYPE_2D; - imageCreateInfo.format = format; - imageCreateInfo.mipLevels = mipLevels; - imageCreateInfo.samples = VK_SAMPLE_COUNT_1_BIT; - imageCreateInfo.tiling = VK_IMAGE_TILING_OPTIMAL; - imageCreateInfo.sharingMode = VK_SHARING_MODE_EXCLUSIVE; - imageCreateInfo.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - imageCreateInfo.extent = { width, height, 1 }; - imageCreateInfo.usage = imageUsageFlags; - // Ensure that the TRANSFER_DST bit is set for staging - if (!(imageCreateInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) - { - imageCreateInfo.usage |= VK_IMAGE_USAGE_TRANSFER_DST_BIT; - } - // Cube faces count as array layers in Vulkan - imageCreateInfo.arrayLayers = 6; - // This flag is required for cube map images - imageCreateInfo.flags = VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT; - - - VK_CHECK_RESULT(vkCreateImage(device->logicalDevice, &imageCreateInfo, nullptr, &image)); - - vkGetImageMemoryRequirements(device->logicalDevice, image, &memReqs); - - memAllocInfo.allocationSize = memReqs.size; - memAllocInfo.memoryTypeIndex = device->getMemoryType(memReqs.memoryTypeBits, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); - - VK_CHECK_RESULT(vkAllocateMemory(device->logicalDevice, &memAllocInfo, nullptr, &deviceMemory)); - VK_CHECK_RESULT(vkBindImageMemory(device->logicalDevice, image, deviceMemory, 0)); - - // Use a separate command buffer for texture loading - VkCommandBuffer copyCmd = device->createCommandBuffer(VK_COMMAND_BUFFER_LEVEL_PRIMARY, true); - - // Image barrier for optimal image (target) - // Set initial layout for all array layers (faces) of the optimal (target) tiled texture - VkImageSubresourceRange subresourceRange = {}; - subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - subresourceRange.baseMipLevel = 0; - subresourceRange.levelCount = mipLevels; - subresourceRange.layerCount = 6; - - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_UNDEFINED, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - subresourceRange); - - // Copy the cube map faces from the staging buffer to the optimal tiled image - vkCmdCopyBufferToImage( - copyCmd, - stagingBuffer, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(bufferCopyRegions.size()), - bufferCopyRegions.data()); - - // Change texture image layout to shader read after all faces have been copied - this->imageLayout = imageLayout; - vks::tools::setImageLayout( - copyCmd, - image, - VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - imageLayout, - subresourceRange); - - device->flushCommandBuffer(copyCmd, copyQueue); - - // Create sampler - VkSamplerCreateInfo samplerCreateInfo = vks::initializers::samplerCreateInfo(); - samplerCreateInfo.magFilter = VK_FILTER_LINEAR; - samplerCreateInfo.minFilter = VK_FILTER_LINEAR; - samplerCreateInfo.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; - samplerCreateInfo.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; - samplerCreateInfo.addressModeV = samplerCreateInfo.addressModeU; - samplerCreateInfo.addressModeW = samplerCreateInfo.addressModeU; - samplerCreateInfo.mipLodBias = 0.0f; - samplerCreateInfo.maxAnisotropy = device->enabledFeatures.samplerAnisotropy ? device->properties.limits.maxSamplerAnisotropy : 1.0f; - samplerCreateInfo.anisotropyEnable = device->enabledFeatures.samplerAnisotropy; - samplerCreateInfo.compareOp = VK_COMPARE_OP_NEVER; - samplerCreateInfo.minLod = 0.0f; - samplerCreateInfo.maxLod = (float)mipLevels; - samplerCreateInfo.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_WHITE; - VK_CHECK_RESULT(vkCreateSampler(device->logicalDevice, &samplerCreateInfo, nullptr, &sampler)); - - // Create image view - VkImageViewCreateInfo viewCreateInfo = vks::initializers::imageViewCreateInfo(); - viewCreateInfo.viewType = VK_IMAGE_VIEW_TYPE_CUBE; - viewCreateInfo.format = format; - viewCreateInfo.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; - viewCreateInfo.subresourceRange.layerCount = 6; - viewCreateInfo.subresourceRange.levelCount = mipLevels; - viewCreateInfo.image = image; - VK_CHECK_RESULT(vkCreateImageView(device->logicalDevice, &viewCreateInfo, nullptr, &view)); - - // Clean up staging resources - ktxTexture_Destroy(ktxTexture); - vkDestroyBuffer(device->logicalDevice, stagingBuffer, nullptr); - vkFreeMemory(device->logicalDevice, stagingMemory, nullptr); - - // Update descriptor image info member that can be used for setting up descriptor sets - updateDescriptor(); - }*/ } diff --git a/libraries/vk/src/vk/VulkanTexture.h b/libraries/vk/src/vk/VulkanTexture.h index 62d388abf2..399d35928a 100644 --- a/libraries/vk/src/vk/VulkanTexture.h +++ b/libraries/vk/src/vk/VulkanTexture.h @@ -51,14 +51,6 @@ class Texture class Texture2D : public Texture { public: - /*void loadFromFile( - std::string filename, - VkFormat format, - vks::VulkanDevice *device, - VkQueue copyQueue, - VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, - VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, - bool forceLinear = false);*/ void fromBuffer( void * buffer, VkDeviceSize bufferSize, @@ -71,28 +63,4 @@ class Texture2D : public Texture VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); }; - -class Texture2DArray : public Texture -{ - public: - /*void loadFromFile( - std::string filename, - VkFormat format, - vks::VulkanDevice *device, - VkQueue copyQueue, - VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, - VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);*/ -}; - -class TextureCubeMap : public Texture -{ - public: - /*void loadFromFile( - std::string filename, - VkFormat format, - vks::VulkanDevice *device, - VkQueue copyQueue, - VkImageUsageFlags imageUsageFlags = VK_IMAGE_USAGE_SAMPLED_BIT, - VkImageLayout imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);*/ -}; } // namespace vks diff --git a/tools/gpu-frame-player/src/RenderThread.cpp b/tools/gpu-frame-player/src/RenderThread.cpp index 3d5671f67e..58505c2a68 100644 --- a/tools/gpu-frame-player/src/RenderThread.cpp +++ b/tools/gpu-frame-player/src/RenderThread.cpp @@ -357,7 +357,7 @@ void RenderThread::renderFrame(gpu::FramePointer& frame) { vkBackend->waitForGPU(); vkBackend->recycleFrame(); _vkcontext.emptyDumpster(frameFence); - _vkcontext.recycle(); + //_vkcontext.recycle(); if (frame && !frame->batches.empty()) { if (rdoc_api) rdoc_api->EndFrameCapture(NULL, NULL); @@ -406,11 +406,11 @@ bool RenderThread::process() { void RenderThread::setupFramebuffers() { // Recreate the frame buffers - _vkcontext.trashAll(_framebuffers, [this](const std::vector& framebuffers) { - for (const auto& framebuffer : framebuffers) { - vkDestroyFramebuffer(_vkcontext.device->logicalDevice, framebuffer, nullptr); - } - }); + auto vkBackend = std::dynamic_pointer_cast(_gpuContext->getBackend()); + for (auto framebuffer : _framebuffers) { + vkBackend->recycler.trashVkFramebuffer(framebuffer); + } + _framebuffers.clear(); std::vector attachments; attachments.resize(1);