diff --git a/CMakeLists.txt b/CMakeLists.txt index 62940f9835..009f56f755 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required(VERSION 3.7) project(vsg - VERSION 1.1.11 + VERSION 1.1.12 DESCRIPTION "VulkanSceneGraph library" LANGUAGES CXX ) -set(VSG_SOVERSION 14) +set(VSG_SOVERSION 15) SET(VSG_RELEASE_CANDIDATE 0) set(Vulkan_MIN_VERSION 1.1.70.0) diff --git a/include/vsg/all.h b/include/vsg/all.h index d97edbcf90..27bf34ff77 100644 --- a/include/vsg/all.h +++ b/include/vsg/all.h @@ -27,6 +27,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include #include diff --git a/include/vsg/app/RecordTraversal.h b/include/vsg/app/RecordTraversal.h index eef180e728..42527d4f55 100644 --- a/include/vsg/app/RecordTraversal.h +++ b/include/vsg/app/RecordTraversal.h @@ -170,7 +170,6 @@ namespace vsg // clear the bins to record a new frame. void clearBins(); - // list of pairs of modelview matrix & region of interest std::vector> regionsOfInterest; diff --git a/include/vsg/app/TransferTask.h b/include/vsg/app/TransferTask.h index 4308f9c852..b098bbb0b6 100644 --- a/include/vsg/app/TransferTask.h +++ b/include/vsg/app/TransferTask.h @@ -118,4 +118,7 @@ namespace vsg }; VSG_type_name(vsg::TransferTask); + /// convenience function that uploads staging buffer data to device including mipmaps. + extern VSG_DECLSPEC void transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device); + } // namespace vsg diff --git a/include/vsg/commands/CopyAndReleaseImage.h b/include/vsg/commands/CopyAndReleaseImage.h index c84c0b42ef..a400aa7d99 100644 --- a/include/vsg/commands/CopyAndReleaseImage.h +++ b/include/vsg/commands/CopyAndReleaseImage.h @@ -40,7 +40,6 @@ namespace vsg uint32_t width = 0; uint32_t height = 0; uint32_t depth = 0; - Data::MipmapOffsets mipmapOffsets; void record(CommandBuffer& commandBuffer) const; }; diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index ebc3209a14..5d6420760a 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -31,7 +31,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - template class Array : public Data { @@ -63,10 +62,14 @@ namespace vsg _data(_allocate(numElements)), _size(numElements) { dirty(); } - Array(uint32_t numElements, value_type* data, Properties in_properties = {}) : + Array(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), - _size(numElements) { dirty(); } + _size(numElements) + { + setMipmapLayout(mipmapLayout); + dirty(); + } Array(uint32_t numElements, const value_type& value, Properties in_properties = {}) : Data(in_properties, sizeof(value_type)), @@ -77,12 +80,12 @@ namespace vsg dirty(); } - Array(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}) : + Array(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(), _data(nullptr), _size(0) { - assign(data, offset, stride, numElements, in_properties); + assign(data, offset, stride, numElements, in_properties, mipmapLayout); } explicit Array(std::initializer_list l) : @@ -165,7 +168,10 @@ namespace vsg if (input.matchPropertyName("data")) { - size_t new_total_size = computeValueCountIncludingMipmaps(width_size, 1, 1, properties.maxNumMipmaps); + properties.stride = sizeof(value_type); + _size = width_size; + _storage = nullptr; + size_t new_total_size = computeValueCountIncludingMipmaps(); if (_data) // if data exists already may be able to reuse it { @@ -181,10 +187,6 @@ namespace vsg _data = _allocate(new_total_size); } - properties.stride = sizeof(value_type); - _size = width_size; - _storage = nullptr; - if (_data) input.read(new_total_size, _data); dirty(); @@ -209,7 +211,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? _size : computeValueCountIncludingMipmaps(_size, 1, 1, properties.maxNumMipmaps); } + size_t size() const { return (properties.mipLevels <= 1) ? _size : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } @@ -229,7 +231,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _size = rhs._size; if (_size != 0) @@ -244,7 +247,7 @@ namespace vsg return *this; } - void assign(uint32_t numElements, value_type* data, Properties in_properties = {}) + void assign(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -254,10 +257,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapLayout(mipmapLayout); + dirty(); } - void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}) + void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -275,6 +280,8 @@ namespace vsg _size = 0; } + setMipmapLayout(mipmapLayout); + dirty(); } @@ -365,6 +372,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + _clear(); } private: diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index 999b423e32..ee19e4405c 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -13,7 +13,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include - #include #include #include @@ -68,11 +67,15 @@ namespace vsg dirty(); } - Array2D(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}) : + Array2D(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), _width(width), - _height(height) { dirty(); } + _height(height) + { + setMipmapLayout(mipmapLayout); + dirty(); + } Array2D(uint32_t width, uint32_t height, const value_type& value, Properties in_properties = {}) : Data(in_properties, sizeof(value_type)), @@ -88,13 +91,13 @@ namespace vsg } } - Array2D(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}) : + Array2D(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(), _data(nullptr), _width(0), _height(0) { - assign(data, offset, stride, width, height, in_properties); + assign(data, offset, stride, width, height, in_properties, mipmapLayout); } template @@ -144,7 +147,12 @@ namespace vsg if (input.matchPropertyName("data")) { - size_t new_size = computeValueCountIncludingMipmaps(w, h, 1, properties.maxNumMipmaps); + properties.stride = sizeof(value_type); + _width = w; + _height = h; + _storage = nullptr; + + size_t new_size = computeValueCountIncludingMipmaps(); if (_data) // if data exists already may be able to reuse it { @@ -159,11 +167,6 @@ namespace vsg _data = _allocate(new_size); } - properties.stride = sizeof(value_type); - _width = w; - _height = h; - _storage = nullptr; - if (_data) input.read(new_size, _data); dirty(); @@ -190,7 +193,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast(_width) * static_cast(_height)) : computeValueCountIncludingMipmaps(_width, _height, 1, properties.maxNumMipmaps); } + size_t size() const { return (properties.mipLevels <= 1) ? (static_cast(_width) * static_cast(_height)) : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } @@ -211,7 +214,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _width = rhs._width; _height = rhs._height; @@ -227,7 +231,7 @@ namespace vsg return *this; } - void assign(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}) + void assign(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -238,10 +242,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapLayout(mipmapLayout); + dirty(); } - void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}) + void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -261,6 +267,8 @@ namespace vsg _height = 0; } + setMipmapLayout(mipmapLayout); + dirty(); } @@ -360,6 +368,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + _clear(); } private: diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 033bf9d84c..08efd30c15 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -70,12 +70,16 @@ namespace vsg dirty(); } - Array3D(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}) : + Array3D(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), _width(width), _height(height), - _depth(depth) { dirty(); } + _depth(depth) + { + setMipmapLayout(mipmapLayout); + dirty(); + } Array3D(uint32_t width, uint32_t height, uint32_t depth, const value_type& value, Properties in_properties = {}) : Data(in_properties, sizeof(value_type)), @@ -92,14 +96,14 @@ namespace vsg } } - Array3D(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}) : + Array3D(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(), _data(nullptr), _width(0), _height(0), _depth(0) { - assign(data, offset, stride, width, height, depth, in_properties); + assign(data, offset, stride, width, height, depth, in_properties, mipmapLayout); } template @@ -150,7 +154,13 @@ namespace vsg if (input.matchPropertyName("data")) { - size_t new_size = computeValueCountIncludingMipmaps(w, h, d, properties.maxNumMipmaps); + properties.stride = sizeof(value_type); + _width = w; + _height = h; + _depth = d; + _storage = nullptr; + + size_t new_size = computeValueCountIncludingMipmaps(); if (_data) // if data exists already may be able to reuse it { @@ -165,12 +175,6 @@ namespace vsg _data = _allocate(new_size); } - properties.stride = sizeof(value_type); - _width = w; - _height = h; - _depth = d; - _storage = nullptr; - if (_data) input.read(new_size, _data); dirty(); @@ -198,7 +202,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast(_width) * _height * _depth) : computeValueCountIncludingMipmaps(_width, _height, _depth, properties.maxNumMipmaps); } + size_t size() const { return (properties.mipLevels <= 1) ? (static_cast(_width) * _height * _depth) : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } @@ -220,7 +224,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _width = rhs._width; _height = rhs._height; _depth = rhs._depth; @@ -237,7 +242,7 @@ namespace vsg return *this; } - void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}) + void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -249,10 +254,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapLayout(mipmapLayout); + dirty(); } - void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}) + void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, uint32_t depth, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -274,6 +281,8 @@ namespace vsg _depth = 0; } + setMipmapLayout(mipmapLayout); + dirty(); } @@ -375,6 +384,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + _clear(); } private: diff --git a/include/vsg/core/Auxiliary.h b/include/vsg/core/Auxiliary.h index 01cc86408f..e57cdbbfbf 100644 --- a/include/vsg/core/Auxiliary.h +++ b/include/vsg/core/Auxiliary.h @@ -39,6 +39,11 @@ namespace vsg virtual int compare(const Auxiliary& rhs) const; + using ObjectMap = std::map>; + + /// container for all user objects + ObjectMap userObjects; + void setObject(const std::string& key, ref_ptr object) { userObjects[key] = object; @@ -76,10 +81,10 @@ namespace vsg return {}; } - using ObjectMap = std::map>; - - /// container for all user objects - ObjectMap userObjects; + void clear() + { + userObjects.clear(); + } protected: explicit Auxiliary(Object* object); diff --git a/include/vsg/core/ConstVisitor.h b/include/vsg/core/ConstVisitor.h index 3f7360bbcf..fb00426ef7 100644 --- a/include/vsg/core/ConstVisitor.h +++ b/include/vsg/core/ConstVisitor.h @@ -23,6 +23,7 @@ namespace vsg // forward declare core Objects class Objects; class External; + class MipmapLayout; // forward declare node classes class Node; @@ -193,6 +194,7 @@ namespace vsg virtual void apply(const Objects&); virtual void apply(const External&); virtual void apply(const Data&); + virtual void apply(const MipmapLayout&); // Values virtual void apply(const stringValue&); diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index d785490fb3..aa3dc6db7c 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -24,6 +24,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { + // forward declaer MipmapLayout + class MipmapLayout; + /// ModifiedCount provides a count value to keep track of modifications to data. struct ModifiedCount { @@ -104,6 +107,8 @@ namespace vsg value_type* operator->() { return reinterpret_cast(ptr); } }; + class MipmapLayout; + /// Data base class for abstracting data such as values, vertices, images etc. /// Main subclasses are vsg::Value, vsg::Array, vsg::Array2D and vsg::Array3D. class VSG_DECLSPEC Data : public Object @@ -121,7 +126,7 @@ namespace vsg VkFormat format = VK_FORMAT_UNDEFINED; uint32_t stride = 0; - uint8_t maxNumMipmaps = 0; + uint8_t mipLevels = 0; uint8_t blockWidth = 1; uint8_t blockHeight = 1; uint8_t blockDepth = 1; @@ -185,13 +190,14 @@ namespace vsg virtual uint32_t height() const = 0; virtual uint32_t depth() const = 0; + /// return the {width, height, depth} pixel extents of an image accounting for blockWidth and any mipmapData assigned to image. + std::tuple pixelExtents() const; + bool contiguous() const { return valueSize() == properties.stride; } uint32_t stride() const { return properties.stride ? properties.stride : static_cast(valueSize()); } - using MipmapOffsets = std::vector; - MipmapOffsets computeMipmapOffsets() const; - static size_t computeValueCountIncludingMipmaps(size_t w, size_t h, size_t d, uint32_t maxNumMipmaps); + size_t computeValueCountIncludingMipmaps() const; /// increment the ModifiedCount to signify the data has been modified void dirty() { ++_modifiedCount; } @@ -211,9 +217,18 @@ namespace vsg /// return true if Data's ModifiedCount is different from the specified ModifiedCount bool differentModifiedCount(const ModifiedCount& mc) const { return _modifiedCount != mc; } + /// set the MipmapLayout, only required when the data contains mipmaps that use block compressed formats and the pixels size doesn't fit exactly to the block size. + void setMipmapLayout(MipmapLayout* mipmapData); + + /// get the MipmapLayout if assigned. + const MipmapLayout* getMipmapLayout() const; + protected: virtual ~Data() {} + void _copy(const Data& rhs); + void _clear(); + ModifiedCount _modifiedCount; #if 1 diff --git a/include/vsg/core/MipmapLayout.h b/include/vsg/core/MipmapLayout.h new file mode 100644 index 0000000000..968114255f --- /dev/null +++ b/include/vsg/core/MipmapLayout.h @@ -0,0 +1,54 @@ +#pragma once + +/* + +Copyright(c) 2025 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include + +#include + +namespace vsg +{ + + class VSG_DECLSPEC MipmapLayout : public Inherit + { + public: + MipmapLayout(); + + explicit MipmapLayout(std::size_t size); + + using Mipmaps = std::vector; + + Mipmaps mipmaps; + + std::size_t size() const { return mipmaps.size(); } + vsg::uivec4& at(size_t i) { return mipmaps[i]; } + const vsg::uivec4& at(size_t i) const { return mipmaps[i]; } + + void set(size_t i, const vsg::uivec4& value) { mipmaps[i] = value; } + + Mipmaps::iterator begin() { return mipmaps.begin(); } + Mipmaps::iterator end() { return mipmaps.end(); } + + Mipmaps::const_iterator begin() const { return mipmaps.begin(); } + Mipmaps::const_iterator end() const { return mipmaps.end(); } + + void read(Input& input) override; + void write(Output& output) const override; + + protected: + virtual ~MipmapLayout(); + }; + VSG_type_name(vsg::MipmapLayout); + +} // namespace vsg diff --git a/include/vsg/core/Value.h b/include/vsg/core/Value.h index c813bd456c..5a6e3c24a6 100644 --- a/include/vsg/core/Value.h +++ b/include/vsg/core/Value.h @@ -142,6 +142,9 @@ namespace vsg Value& operator=(const Value& rhs) { _value = rhs._value; + + _copy(rhs); + return *this; } Value& operator=(const value_type& rhs) diff --git a/include/vsg/core/Visitor.h b/include/vsg/core/Visitor.h index 84abca3d54..ab7ec92b01 100644 --- a/include/vsg/core/Visitor.h +++ b/include/vsg/core/Visitor.h @@ -23,6 +23,7 @@ namespace vsg // forward declare core Objects class Objects; class External; + class MipmapLayout; // forward declare node classes class Node; @@ -193,6 +194,7 @@ namespace vsg virtual void apply(Objects&); virtual void apply(External&); virtual void apply(Data&); + virtual void apply(MipmapLayout&); // Values virtual void apply(stringValue&); diff --git a/include/vsg/state/ImageView.h b/include/vsg/state/ImageView.h index 892f1c5b52..9de4bcbc0c 100644 --- a/include/vsg/state/ImageView.h +++ b/include/vsg/state/ImageView.h @@ -67,7 +67,4 @@ namespace vsg /// convenience function that creates an ImageView and allocates device memory and an Image for it. extern VSG_DECLSPEC ref_ptr createImageView(Device* device, ref_ptr image, VkImageAspectFlags aspectFlags); - /// convenience function that uploads staging buffer data to device including mipmaps. - extern VSG_DECLSPEC void transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, const Data::MipmapOffsets& mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device); - } // namespace vsg diff --git a/include/vsg/state/ShaderModule.h b/include/vsg/state/ShaderModule.h index 43642c9671..a57ff2e295 100644 --- a/include/vsg/state/ShaderModule.h +++ b/include/vsg/state/ShaderModule.h @@ -27,7 +27,6 @@ namespace vsg class VSG_DECLSPEC ShaderCompileSettings : public Inherit { public: - ShaderCompileSettings(); ShaderCompileSettings(const ShaderCompileSettings& rhs, const CopyOp& copyop = {}); diff --git a/include/vsg/vk/State.h b/include/vsg/vk/State.h index 81368df9ab..1f82b20e13 100644 --- a/include/vsg/vk/State.h +++ b/include/vsg/vk/State.h @@ -296,7 +296,7 @@ namespace vsg InheritanceMask inheritanceMask = InheritanceMask::INHERIT_ALL; - void inherit(State& state); + void inherit(const State& state); inline void dirtyStateStacks() { diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 26e87199aa..34ad025dde 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -10,6 +10,7 @@ endif() # set up the source files explicitly. set(SOURCES + core/MipmapLayout.cpp core/Allocator.cpp core/IntrusiveAllocator.cpp core/Auxiliary.cpp diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 45fd522188..a0805b7735 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -12,6 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include #include #include #include @@ -266,8 +267,8 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Transfer auto width = data->width(); auto height = data->height(); auto depth = data->depth(); - auto mipmapOffsets = data->computeMipmapOffsets(); - uint32_t mipLevels = vsg::computeNumMipMapLevels(data, imageInfo.sampler); + + uint32_t mipLevels = imageInfo.imageView->image->mipLevels; auto source_offset = offset; @@ -333,7 +334,7 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Transfer } // transfer data. - transferImageData(imageInfo.imageView, imageInfo.imageLayout, properties, width, height, depth, mipLevels, mipmapOffsets, imageStagingBuffer, source_offset, vk_commandBuffer, device); + transferImageData(imageInfo.imageView, imageInfo.imageLayout, properties, width, height, depth, mipLevels, imageStagingBuffer, source_offset, vk_commandBuffer, device); } TransferTask::TransferResult TransferTask::transferData(TransferMask transferMask) @@ -558,3 +559,306 @@ TransferTask::TransferResult TransferTask::_transferData(DataToCopy& dataToCopy) return TransferResult{VK_SUCCESS, {}}; } } + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// +// vsg::transferImageData(..) +// +void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device) +{ + auto image = imageView->image; + if (!image) return; + + auto data = image->data; + if (!data) return; + + auto vk_image = image->vk(device->deviceID); + auto aspectMask = imageView->subresourceRange.aspectMask; + + uint32_t faceWidth = width; + uint32_t faceHeight = height; + uint32_t faceDepth = depth; + uint32_t arrayLayers = 1; + + //switch(properties.imageViewType) + switch (imageView->viewType) + { + case (VK_IMAGE_VIEW_TYPE_CUBE): + arrayLayers = faceDepth; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_1D_ARRAY): + arrayLayers = faceHeight * faceDepth; + faceHeight = 1; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_2D_ARRAY): + arrayLayers = faceDepth; + faceDepth = 1; + break; + case (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY): + arrayLayers = faceDepth; + faceDepth = 1; + break; + default: + break; + } + + uint32_t destWidth = faceWidth * properties.blockWidth; + uint32_t destHeight = faceHeight * properties.blockHeight; + uint32_t destDepth = faceDepth * properties.blockDepth; + + const auto valueSize = properties.stride; // data->valueSize(); + + uint32_t data_mipLevels = static_cast(data->properties.mipLevels); + + auto mipmapData = data->getMipmapLayout(); + if (mipmapData) + { + const auto& mipmap0 = mipmapData->at(0); + destWidth = mipmap0.x; + destHeight = mipmap0.y; + destDepth = mipmap0.z; + + if (mipmapData->size() > 1) + { + data_mipLevels = static_cast(mipmapData->size()); + } + } + + bool useDataMipmaps = mipLevels > 1 && data_mipLevels > 1; + bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; + + if (useDataMipmaps) mipLevels = std::min(mipLevels, data_mipLevels); + + // vsg::info("vsg::transferImageData() data = ", data, ", data->properties.mipLevels = ", int(data->properties.mipLevels), ", data_mipLevels = ", data_mipLevels, " mipLevels = ", mipLevels, ", mipmapData = ", mipmapData, ", generateMipmaps = ", generateMipmaps); + + if (generateMipmaps) + { + VkFormatProperties props; + vkGetPhysicalDeviceFormatProperties(*(device->getPhysicalDevice()), properties.format, &props); + const bool isBlitPossible = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) > 0; + + if (!isBlitPossible) + { + generateMipmaps = false; + } + } + + // transfer the data. + VkImageMemoryBarrier preCopyBarrier = {}; + preCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + preCopyBarrier.srcAccessMask = 0; + preCopyBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + preCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; + preCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + preCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + preCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + preCopyBarrier.image = vk_image; + preCopyBarrier.subresourceRange.aspectMask = aspectMask; + preCopyBarrier.subresourceRange.baseArrayLayer = 0; + preCopyBarrier.subresourceRange.layerCount = arrayLayers; + preCopyBarrier.subresourceRange.levelCount = mipLevels; + preCopyBarrier.subresourceRange.baseMipLevel = 0; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &preCopyBarrier); + + std::vector regions; + + if (useDataMipmaps) + { + if (mipmapData) + { + regions.resize(mipLevels * arrayLayers); + + auto mipmapItr = mipmapData->begin(); + for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) + { + const auto& mipmap = (*mipmapItr++); + + for (uint32_t face = 0; face < arrayLayers; ++face) + { + auto& region = regions[mipLevel * arrayLayers + face]; + region.bufferOffset = stagingBufferOffset + mipmap.w; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = aspectMask; + region.imageSubresource.mipLevel = mipLevel; + region.imageSubresource.baseArrayLayer = face; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {mipmap.x, mipmap.y, mipmap.z}; + } + } + } + else + { + regions.resize(mipLevels * arrayLayers); + + size_t offset = 0u; + uint32_t mipWidth = destWidth; + uint32_t mipHeight = destHeight; + uint32_t mipDepth = destDepth; + + for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) + { + const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); + + for (uint32_t face = 0; face < arrayLayers; ++face) + { + auto& region = regions[mipLevel * arrayLayers + face]; + region.bufferOffset = stagingBufferOffset + offset; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = aspectMask; + region.imageSubresource.mipLevel = mipLevel; + region.imageSubresource.baseArrayLayer = face; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {mipWidth, mipHeight, mipDepth}; + + offset += faceSize; + } + + if (mipWidth > 1) mipWidth /= 2; + if (mipHeight > 1) mipHeight /= 2; + if (mipDepth > 1) mipDepth /= 2; + if (faceWidth > 1) faceWidth /= 2; + if (faceHeight > 1) faceHeight /= 2; + if (faceDepth > 1) faceDepth /= 2; + } + } + } + else + { + regions.resize(arrayLayers); + + const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); + for (auto face = 0u; face < arrayLayers; face++) + { + auto& region = regions[face]; + region.bufferOffset = stagingBufferOffset + face * faceSize; + region.bufferRowLength = 0; + region.bufferImageHeight = 0; + region.imageSubresource.aspectMask = aspectMask; + region.imageSubresource.mipLevel = 0; + region.imageSubresource.baseArrayLayer = face; + region.imageSubresource.layerCount = 1; + region.imageOffset = {0, 0, 0}; + region.imageExtent = {destWidth, destHeight, destDepth}; + } + } + + vkCmdCopyBufferToImage(commandBuffer, stagingBuffer->vk(device->deviceID), vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + static_cast(regions.size()), regions.data()); + + if (generateMipmaps) + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.image = vk_image; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = aspectMask; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = arrayLayers; + barrier.subresourceRange.levelCount = 1; + + int32_t mipWidth = destWidth; + int32_t mipHeight = destHeight; + int32_t mipDepth = destDepth; + + for (uint32_t i = 1; i < mipLevels; ++i) + { + barrier.subresourceRange.baseMipLevel = i - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + int32_t nextWidth = (mipWidth > 1) ? (mipWidth) / 2 : 1; + int32_t nextHeight = (mipHeight > 1) ? (mipHeight) / 2 : 1; + int32_t nextDepth = (mipDepth > 1) ? (mipDepth) / 2 : 1; + + VkImageBlit blit; + blit.srcOffsets[0] = {0, 0, 0}; + blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; + blit.srcSubresource.aspectMask = aspectMask; + blit.srcSubresource.mipLevel = i - 1; + blit.srcSubresource.baseArrayLayer = 0; + blit.srcSubresource.layerCount = arrayLayers; + blit.dstOffsets[0] = {0, 0, 0}; + blit.dstOffsets[1] = {nextWidth, nextHeight, nextDepth}; + blit.dstSubresource.aspectMask = aspectMask; + blit.dstSubresource.mipLevel = i; + blit.dstSubresource.baseArrayLayer = 0; + blit.dstSubresource.layerCount = arrayLayers; + + vkCmdBlitImage(commandBuffer, + vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 1, &blit, + VK_FILTER_LINEAR); + + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barrier.newLayout = targetImageLayout; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + + mipWidth = nextWidth; + mipHeight = nextHeight; + mipDepth = nextDepth; + } + + barrier.subresourceRange.baseMipLevel = mipLevels - 1; + barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barrier.newLayout = targetImageLayout; + barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &barrier); + } + else + { + VkImageMemoryBarrier postCopyBarrier = {}; + postCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + postCopyBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + postCopyBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + postCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + postCopyBarrier.newLayout = targetImageLayout; + postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + postCopyBarrier.image = vk_image; + postCopyBarrier.subresourceRange.aspectMask = aspectMask; + postCopyBarrier.subresourceRange.baseArrayLayer = 0; + postCopyBarrier.subresourceRange.layerCount = arrayLayers; + postCopyBarrier.subresourceRange.levelCount = mipLevels; + postCopyBarrier.subresourceRange.baseMipLevel = 0; + + vkCmdPipelineBarrier(commandBuffer, + VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, + 0, nullptr, + 0, nullptr, + 1, &postCopyBarrier); + } +} diff --git a/src/vsg/app/WindowTraits.cpp b/src/vsg/app/WindowTraits.cpp index 1f3c63639a..bc8f1f1bbc 100644 --- a/src/vsg/app/WindowTraits.cpp +++ b/src/vsg/app/WindowTraits.cpp @@ -55,11 +55,10 @@ WindowTraits::WindowTraits(CommandLine& arguments) arguments.read("--display", display); arguments.read("--samples", samples); - auto setDevicePref = [&](const VkPhysicalDeviceType typeIn) - { - auto it = std::find(deviceTypePreferences.begin(), deviceTypePreferences.end(), typeIn); - if (it != deviceTypePreferences.end()) deviceTypePreferences.erase(it); - deviceTypePreferences.insert(deviceTypePreferences.begin(), typeIn); + auto setDevicePref = [&](const VkPhysicalDeviceType typeIn) { + auto it = std::find(deviceTypePreferences.begin(), deviceTypePreferences.end(), typeIn); + if (it != deviceTypePreferences.end()) deviceTypePreferences.erase(it); + deviceTypePreferences.insert(deviceTypePreferences.begin(), typeIn); }; if (arguments.read("--prefer-integrated")) setDevicePref(VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU); if (arguments.read("--prefer-discrete")) setDevicePref(VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU); diff --git a/src/vsg/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index 1556194d26..06b7c1883f 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -10,10 +10,11 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +#include #include #include #include -#include +#include using namespace vsg; @@ -37,7 +38,6 @@ CopyAndReleaseImage::CopyData::CopyData(ref_ptr src, ref_ptrdata->width(); height = source->data->height(); depth = source->data->depth(); - mipmapOffsets = source->data->computeMipmapOffsets(); } } @@ -165,7 +165,7 @@ void CopyAndReleaseImage::_copyDirectly(ref_ptr data, ref_ptr d void CopyAndReleaseImage::CopyData::record(CommandBuffer& commandBuffer) const { - transferImageData(destination->imageView, destination->imageLayout, layout, width, height, depth, mipLevels, mipmapOffsets, source->buffer, source->offset, commandBuffer.vk(), commandBuffer.getDevice()); + transferImageData(destination->imageView, destination->imageLayout, layout, width, height, depth, mipLevels, source->buffer, source->offset, commandBuffer.vk(), commandBuffer.getDevice()); } void CopyAndReleaseImage::record(CommandBuffer& commandBuffer) const diff --git a/src/vsg/core/ConstVisitor.cpp b/src/vsg/core/ConstVisitor.cpp index 4b72f37c51..42850c65e2 100644 --- a/src/vsg/core/ConstVisitor.cpp +++ b/src/vsg/core/ConstVisitor.cpp @@ -37,6 +37,11 @@ void ConstVisitor::apply(const Data& value) apply(static_cast(value)); } +void ConstVisitor::apply(const MipmapLayout& value) +{ + apply(static_cast(value)); +} + //////////////////////////////////////////////////////////////////////////////// // // Values diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 715344f922..cab03faaae 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -11,7 +11,9 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include +#include #include +#include #include #include @@ -28,7 +30,7 @@ Data::Properties& Data::Properties::operator=(const Properties& rhs) format = rhs.format; if (rhs.stride != 0) stride = rhs.stride; - maxNumMipmaps = rhs.maxNumMipmaps; + mipLevels = rhs.mipLevels; blockWidth = rhs.blockWidth; blockHeight = rhs.blockHeight; blockDepth = rhs.blockDepth; @@ -78,15 +80,15 @@ void Data::read(Input& input) if (input.version_greater_equal(0, 6, 1)) { - input.read("properties", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); + input.read("properties", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); } else if (input.version_greater_equal(0, 5, 7)) { - input.read("Layout", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); + input.read("Layout", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); } else { - input.read("Layout", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType); + input.read("Layout", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType); properties.dataVariance = STATIC_DATA; } @@ -100,61 +102,103 @@ void Data::write(Output& output) const uint32_t format = properties.format; if (output.version_greater_equal(0, 6, 1)) { - output.write("properties", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); + output.write("properties", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); } else if (output.version_greater_equal(0, 5, 7)) { - output.write("Layout", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); + output.write("Layout", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType, properties.dataVariance); } else { - output.write("Layout", format, properties.stride, properties.maxNumMipmaps, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType); + output.write("Layout", format, properties.stride, properties.mipLevels, properties.blockWidth, properties.blockHeight, properties.blockDepth, properties.origin, properties.imageViewType); } } -Data::MipmapOffsets Data::computeMipmapOffsets() const +void Data::_copy(const Data& rhs) { - if (properties.maxNumMipmaps <= 1) return {}; + properties = rhs.properties; + if (rhs.getAuxiliary()) + { + getOrCreateAuxiliary()->userObjects = rhs.getAuxiliary()->userObjects; + } + else if (getAuxiliary()) + { + getAuxiliary()->userObjects.clear(); + } +} - uint32_t numMipmaps = properties.maxNumMipmaps; +void Data::_clear() +{ + if (getAuxiliary()) getAuxiliary()->clear(); +} - MipmapOffsets offsets; +void Data::setMipmapLayout(MipmapLayout* mipmapLayout) +{ + if (mipmapLayout) + setObject("mipmapLayout", ref_ptr(mipmapLayout)); + else if (getAuxiliary()) + removeObject("mipmapLayout"); +} - std::size_t w = width(); - std::size_t h = height(); - std::size_t d = depth(); +const MipmapLayout* Data::getMipmapLayout() const +{ + return getObject("mipmapLayout"); +} - std::size_t lastPosition = 0; - offsets.push_back(lastPosition); - while (numMipmaps > 1 && (w > 1 || h > 1 || d > 1)) - { - lastPosition += (w * h * d); - offsets.push_back(lastPosition); +std::size_t Data::computeValueCountIncludingMipmaps() const +{ + std::size_t count = 0; - --numMipmaps; - if (w > 1) w /= 2; - if (h > 1) h /= 2; - if (d > 1) d /= 2; + if (auto mipmapLayout = getMipmapLayout()) + { + for (const auto& mipmap : *mipmapLayout) + { + // round to block size + std::size_t w = (mipmap.x + properties.blockWidth - 1) / properties.blockWidth; + std::size_t h = (mipmap.y + properties.blockHeight - 1) / properties.blockHeight; + std::size_t d = (mipmap.z + properties.blockDepth - 1) / properties.blockDepth; + + count += w * h * d; + } + } + else + { + std::size_t x = width() * properties.blockWidth; + std::size_t y = height() * properties.blockHeight; + std::size_t z = depth() * properties.blockDepth; + + auto mipLevels = std::max(properties.mipLevels, uint8_t(1)); + for (uint8_t level = 0; level < mipLevels; ++level) + { + // round to block size + std::size_t w = (x + properties.blockWidth - 1) / properties.blockWidth; + std::size_t h = (y + properties.blockHeight - 1) / properties.blockHeight; + std::size_t d = (z + properties.blockDepth - 1) / properties.blockDepth; + + count += w * h * d; + + if (x > 1) x = x / 2; + if (y > 1) y = y / 2; + if (z > 1) z = z / 2; + } } - return offsets; + return count; } -std::size_t Data::computeValueCountIncludingMipmaps(std::size_t w, std::size_t h, std::size_t d, uint32_t numMipmaps) +std::tuple Data::pixelExtents() const { - if (numMipmaps <= 1) return w * h * d; + uint32_t w = width() * properties.blockWidth; + uint32_t h = height() * properties.blockHeight; + uint32_t d = depth() * properties.blockDepth; - std::size_t lastPosition = (w * h * d); - while (numMipmaps > 1 && (w > 1 || h > 1 || d > 1)) + if (auto mipmapLayout = getMipmapLayout()) { - --numMipmaps; - - if (w > 1) w /= 2; - if (h > 1) h /= 2; - if (d > 1) d /= 2; - - lastPosition += (w * h * d); + auto mipmap = mipmapLayout->at(0); + w = mipmap.x; + h = mipmap.y; + d = mipmap.z; } - return lastPosition; + return {w, h, d}; } diff --git a/src/vsg/core/MipmapLayout.cpp b/src/vsg/core/MipmapLayout.cpp new file mode 100644 index 0000000000..cbfbfefe09 --- /dev/null +++ b/src/vsg/core/MipmapLayout.cpp @@ -0,0 +1,44 @@ +/* + +Copyright(c) 2018 Robert Osfield + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +#include +#include +#include + +using namespace vsg; + +MipmapLayout::MipmapLayout() +{ +} + +MipmapLayout::MipmapLayout(std::size_t size) : + mipmaps(size) +{ +} + +MipmapLayout::~MipmapLayout() +{ +} + +void MipmapLayout::read(Input& input) +{ + Object::read(input); + + input.readValues("mipmaps", mipmaps); +} + +void MipmapLayout::write(Output& output) const +{ + Object::write(output); + + output.writeValues("mipmaps", mipmaps); +} diff --git a/src/vsg/core/Visitor.cpp b/src/vsg/core/Visitor.cpp index 377757159c..c6b8f06dd8 100644 --- a/src/vsg/core/Visitor.cpp +++ b/src/vsg/core/Visitor.cpp @@ -37,6 +37,11 @@ void Visitor::apply(Data& value) apply(static_cast(value)); } +void Visitor::apply(MipmapLayout& value) +{ + apply(static_cast(value)); +} + //////////////////////////////////////////////////////////////////////////////// // // Values diff --git a/src/vsg/io/JSONParser.cpp b/src/vsg/io/JSONParser.cpp index de908624f4..dee3ee2872 100644 --- a/src/vsg/io/JSONParser.cpp +++ b/src/vsg/io/JSONParser.cpp @@ -204,10 +204,6 @@ bool JSONParser::read_uri(std::string& value, ref_ptr& object) auto comma = buffer.find(',', semicolon + 1); - std::string encoding = buffer.substr(semicolon + 1, comma - semicolon - 1); - - // value = buffer.substr(comma+1, end_of_value - comma -1); - value = memeType; object = vsg::stringValue::create(buffer.substr(comma + 1, end_of_value - comma - 1)); diff --git a/src/vsg/io/ObjectFactory.cpp b/src/vsg/io/ObjectFactory.cpp index ecca256913..0f261bbf06 100644 --- a/src/vsg/io/ObjectFactory.cpp +++ b/src/vsg/io/ObjectFactory.cpp @@ -29,6 +29,7 @@ ObjectFactory::ObjectFactory() add(); add(); add(); + add(); // values add(); @@ -353,5 +354,6 @@ vsg::ref_ptr ObjectFactory::create(const std::string& className) } warn("ObjectFactory::create(", className, ") failed to find means to create object."); + return vsg::ref_ptr(); } diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index e2b5a41b8f..42417d61e5 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -38,12 +38,9 @@ Image::Image(ref_ptr in_data) : if (data) { auto properties = data->properties; - auto mipmapOffsets = data->computeMipmapOffsets(); auto dimensions = data->dimensions(); - uint32_t width = data->width() * properties.blockWidth; - uint32_t height = data->height() * properties.blockHeight; - uint32_t depth = data->depth() * properties.blockDepth; + auto [width, height, depth] = data->pixelExtents(); switch (properties.imageViewType) { @@ -92,9 +89,11 @@ Image::Image(ref_ptr in_data) : } format = properties.format; - mipLevels = static_cast(mipmapOffsets.size()); + mipLevels = std::max(1u, static_cast(data->properties.mipLevels)); extent = VkExtent3D{width, height, depth}; + // vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); + // remap RGB to RGBA if (format >= VK_FORMAT_R8G8B8_UNORM && format <= VK_FORMAT_B8G8R8_SRGB) format = static_cast(format + 14); @@ -198,6 +197,8 @@ void Image::compile(Device* device) info.pQueueFamilyIndices = queueFamilyIndices.data(); info.initialLayout = initialLayout; + // vsg::info("Image::compile(), data = ",data, ", mipLevels = ", mipLevels, ", arrayLayers = ", arrayLayers, ", extent = {", extent.width, ", ", extent.height, ", ", extent.depth, "}"); + vd.device = device; vd.requiresDataCopy = data.valid(); diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 06e86f67b8..144edc9f94 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -101,22 +101,53 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) } else if (format == VK_FORMAT_D16_UNORM_S8_UINT) { + traits.packed = true; traits.numBitsPerComponent = 24; traits.numComponents = 1; traits.size = 3; } else if (format == VK_FORMAT_D24_UNORM_S8_UINT) { + traits.packed = true; traits.numBitsPerComponent = 32; traits.numComponents = 1; traits.size = 4; } else if (format == VK_FORMAT_D32_SFLOAT_S8_UINT) { + traits.packed = true; traits.numBitsPerComponent = 40; traits.numComponents = 1; traits.size = 5; } + else if (VK_FORMAT_A8B8G8R8_UNORM_PACK32 <= format && format <= VK_FORMAT_A8B8G8R8_SRGB_PACK32) + { + traits.packed = true; + traits.numBitsPerComponent = 8; + traits.numComponents = 4; + traits.size = 4; + } + else if (VK_FORMAT_A2R10G10B10_UNORM_PACK32 <= format && format <= VK_FORMAT_A2B10G10R10_SINT_PACK32) + { + traits.packed = true; + traits.numBitsPerComponent = 32; // Perhaps should be 10, except alpha is 2, will treat as one packed components + traits.numComponents = 1; + traits.size = 4; + } + else if (VK_FORMAT_B10G11R11_UFLOAT_PACK32 <= format && format <= VK_FORMAT_E5B9G9R9_UFLOAT_PACK32) + { + traits.packed = true; + traits.numBitsPerComponent = 32; // Perhaps should be 10, except R is 11, will treat as one packed components + traits.numComponents = 1; + traits.size = 4; + } + else if (format == VK_FORMAT_X8_D24_UNORM_PACK32) + { + traits.packed = true; + traits.numBitsPerComponent = 32; + traits.numComponents = 1; + traits.size = 4; + } else if (VK_FORMAT_BC1_RGB_UNORM_BLOCK <= format && format <= VK_FORMAT_BC1_RGBA_SRGB_BLOCK) { traits.packed = true; @@ -177,9 +208,118 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) traits.numComponents = 1; traits.size = 16; } + else if ((VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK <= format && format <= VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK) || + (VK_FORMAT_EAC_R11_UNORM_BLOCK <= format && format <= VK_FORMAT_EAC_R11_SNORM_BLOCK)) + { + traits.packed = true; + traits.blockWidth = 4; + traits.blockHeight = 4; + traits.blockDepth = 1; + traits.numBitsPerComponent = 64; + traits.numComponents = 1; + traits.size = 8; + } + else if ((VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK <= format && format <= VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK) || + (VK_FORMAT_EAC_R11G11_UNORM_BLOCK <= format && format <= VK_FORMAT_EAC_R11G11_SNORM_BLOCK)) + { + traits.packed = true; + traits.blockWidth = 4; + traits.blockHeight = 4; + traits.blockDepth = 1; + traits.numBitsPerComponent = 128; + traits.numComponents = 1; + traits.size = 16; + } + else if (VK_FORMAT_ASTC_4x4_UNORM_BLOCK <= format && format <= VK_FORMAT_ASTC_12x12_SRGB_BLOCK) + { + traits.packed = true; + traits.blockDepth = 1; + traits.numBitsPerComponent = 128; + traits.numComponents = 1; + traits.size = 16; + + switch (format) + { + case (VK_FORMAT_ASTC_4x4_UNORM_BLOCK): + case (VK_FORMAT_ASTC_4x4_SRGB_BLOCK): + traits.blockWidth = 4; + traits.blockHeight = 4; + break; + case (VK_FORMAT_ASTC_5x4_UNORM_BLOCK): + case (VK_FORMAT_ASTC_5x4_SRGB_BLOCK): + traits.blockWidth = 5; + traits.blockHeight = 4; + break; + case (VK_FORMAT_ASTC_5x5_UNORM_BLOCK): + case (VK_FORMAT_ASTC_5x5_SRGB_BLOCK): + traits.blockWidth = 5; + traits.blockHeight = 5; + break; + case (VK_FORMAT_ASTC_6x5_UNORM_BLOCK): + case (VK_FORMAT_ASTC_6x5_SRGB_BLOCK): + traits.blockWidth = 6; + traits.blockHeight = 5; + break; + case (VK_FORMAT_ASTC_6x6_UNORM_BLOCK): + case (VK_FORMAT_ASTC_6x6_SRGB_BLOCK): + traits.blockWidth = 6; + traits.blockHeight = 6; + break; + case (VK_FORMAT_ASTC_8x5_UNORM_BLOCK): + case (VK_FORMAT_ASTC_8x5_SRGB_BLOCK): + traits.blockWidth = 8; + traits.blockHeight = 5; + break; + case (VK_FORMAT_ASTC_8x6_UNORM_BLOCK): + case (VK_FORMAT_ASTC_8x6_SRGB_BLOCK): + traits.blockWidth = 8; + traits.blockHeight = 6; + break; + case (VK_FORMAT_ASTC_8x8_UNORM_BLOCK): + case (VK_FORMAT_ASTC_8x8_SRGB_BLOCK): + traits.blockWidth = 8; + traits.blockHeight = 8; + break; + case (VK_FORMAT_ASTC_10x5_UNORM_BLOCK): + case (VK_FORMAT_ASTC_10x5_SRGB_BLOCK): + traits.blockWidth = 10; + traits.blockHeight = 5; + break; + case (VK_FORMAT_ASTC_10x6_UNORM_BLOCK): + case (VK_FORMAT_ASTC_10x6_SRGB_BLOCK): + traits.blockWidth = 10; + traits.blockHeight = 6; + break; + case (VK_FORMAT_ASTC_10x8_UNORM_BLOCK): + case (VK_FORMAT_ASTC_10x8_SRGB_BLOCK): + traits.blockWidth = 10; + traits.blockHeight = 8; + break; + case (VK_FORMAT_ASTC_10x10_UNORM_BLOCK): + case (VK_FORMAT_ASTC_10x10_SRGB_BLOCK): + traits.blockWidth = 10; + traits.blockHeight = 10; + break; + case (VK_FORMAT_ASTC_12x10_UNORM_BLOCK): + case (VK_FORMAT_ASTC_12x10_SRGB_BLOCK): + traits.blockWidth = 12; + traits.blockHeight = 10; + break; + case (VK_FORMAT_ASTC_12x12_UNORM_BLOCK): + case (VK_FORMAT_ASTC_12x12_SRGB_BLOCK): + traits.blockWidth = 12; + traits.blockHeight = 12; + break; + default: + info("getFormatTraits(", format, ") not handled."); + traits.blockWidth = 4; + traits.blockHeight = 4; + break; + } + } else { - info("getFormatTraits(", format, ") unhandled."); + info("getFormatTraits(", format, ") not handled."); } return traits; @@ -191,7 +331,8 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) if (sampler) { // clamp the mipLevels so that it's no larger than what the data dimensions support - uint32_t maxDimension = std::max({data->width(), data->height(), data->depth()}); + auto [width, height, depth] = data->pixelExtents(); + uint32_t maxDimension = std::max({width, height, depth}); if (sampler->maxLod == VK_LOD_CLAMP_NONE) { while ((1u << mipLevels) <= maxDimension) @@ -207,6 +348,31 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) --mipLevels; } } + + bool generateMipmaps = (mipLevels > 1) && (data->properties.mipLevels <= 1); + if (generateMipmaps) + { + // check that the data isn't compressed. + const auto& properties = data->properties; + if (properties.blockWidth > 1 || properties.blockHeight > 1 || properties.blockDepth > 1) + { + if (sampler->maxLod != 0.0f && sampler->maxLod != VK_LOD_CLAMP_NONE) + { + warn("ImageInfo::computeNumMipMapLevels() cannot enable generated mipmaps for vsg::Image, but Sampler::maxLod is not zero or VK_LOD_CLAMP_NONE, sampler->maxLod = ", sampler->maxLod); + } + + mipLevels = 1; + } + } + else + { + if (data->properties.mipLevels < mipLevels) + { + mipLevels = std::max(1u, static_cast(data->properties.mipLevels)); + } + } + + // vsg::info("vsg::computeNumMipMapLevels(data = ", data, ", sampler->maxLod = ", sampler->maxLod, ", data->properties.mipLevels = ", int(data->properties.mipLevels), ", mipLevels = ", mipLevels); } //mipLevels = 1; // disable mipmapping @@ -241,30 +407,10 @@ void ImageInfo::computeNumMipMapLevels() { if (imageView && imageView->image && imageView->image->data) { - auto image = imageView->image; - auto data = image->data; - auto mipLevels = vsg::computeNumMipMapLevels(data, sampler); - - const auto& mipmapOffsets = image->data->computeMipmapOffsets(); - bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); - - if (generateMipmaps) - { - // check that the data isn't compressed. - const auto& properties = data->properties; - if (properties.blockWidth > 1 || properties.blockHeight > 1 || properties.blockDepth > 1) - { - if (sampler->maxLod != 0.0f && sampler->maxLod != VK_LOD_CLAMP_NONE) - { - warn("ImageInfo::computeNumMipMapLevels() cannot enable generated mipmaps for vsg::Image, but Sampler::maxLod is not zero or VK_LOD_CLAMP_NONE, sampler->maxLod = ", sampler->maxLod); - } - - mipLevels = 1; - } - } - - image->mipLevels = mipLevels; - + const auto& image = imageView->image; + const auto& data = image->data; + image->mipLevels = vsg::computeNumMipMapLevels(data, sampler); + bool generateMipmaps = (image->mipLevels > 1) && (data->properties.mipLevels <= 1); if (generateMipmaps) image->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } } diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index 0375293b7e..e8d8a722ea 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -198,247 +198,3 @@ ref_ptr vsg::createImageView(Device* device, ref_ptr image, Vk return imageView; } - -void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, const Data::MipmapOffsets& mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device) -{ - ref_ptr textureImage(imageView->image); - auto aspectMask = imageView->subresourceRange.aspectMask; - - uint32_t faceWidth = width; - uint32_t faceHeight = height; - uint32_t faceDepth = depth; - uint32_t arrayLayers = 1; - - //switch(properties.imageViewType) - switch (imageView->viewType) - { - case (VK_IMAGE_VIEW_TYPE_CUBE): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_1D_ARRAY): - arrayLayers = faceHeight * faceDepth; - faceHeight = 1; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_2D_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - case (VK_IMAGE_VIEW_TYPE_CUBE_ARRAY): - arrayLayers = faceDepth; - faceDepth = 1; - break; - default: - break; - } - - uint32_t destWidth = faceWidth * properties.blockWidth; - uint32_t destHeight = faceHeight * properties.blockHeight; - uint32_t destDepth = faceDepth * properties.blockDepth; - - const auto valueSize = properties.stride; // data->valueSize(); - - bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); - bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); - - auto vk_textureImage = textureImage->vk(device->deviceID); - - if (generateMipmaps) - { - VkFormatProperties props; - vkGetPhysicalDeviceFormatProperties(*(device->getPhysicalDevice()), properties.format, &props); - const bool isBlitPossible = (props.optimalTilingFeatures & VK_FORMAT_FEATURE_BLIT_DST_BIT) > 0; - - if (!isBlitPossible) - { - generateMipmaps = false; - } - } - - // transfer the data. - VkImageMemoryBarrier preCopyBarrier = {}; - preCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - preCopyBarrier.srcAccessMask = 0; - preCopyBarrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - preCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - preCopyBarrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - preCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - preCopyBarrier.image = vk_textureImage; - preCopyBarrier.subresourceRange.aspectMask = aspectMask; - preCopyBarrier.subresourceRange.baseArrayLayer = 0; - preCopyBarrier.subresourceRange.layerCount = arrayLayers; - preCopyBarrier.subresourceRange.levelCount = mipLevels; - preCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &preCopyBarrier); - - std::vector regions; - - if (useDataMipmaps) - { - size_t offset = 0u; - regions.resize(mipLevels * arrayLayers); - - uint32_t mipWidth = destWidth; - uint32_t mipHeight = destHeight; - uint32_t mipDepth = destDepth; - - for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) - { - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - - for (uint32_t face = 0; face < arrayLayers; ++face) - { - auto& region = regions[mipLevel * arrayLayers + face]; - region.bufferOffset = stagingBufferOffset + offset; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = mipLevel; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {mipWidth, mipHeight, mipDepth}; - - offset += faceSize; - } - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - if (faceWidth > 1) faceWidth /= 2; - if (faceHeight > 1) faceHeight /= 2; - if (faceDepth > 1) faceDepth /= 2; - } - } - else - { - regions.resize(arrayLayers); - - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); - for (auto face = 0u; face < arrayLayers; face++) - { - auto& region = regions[face]; - region.bufferOffset = stagingBufferOffset + face * faceSize; - region.bufferRowLength = 0; - region.bufferImageHeight = 0; - region.imageSubresource.aspectMask = aspectMask; - region.imageSubresource.mipLevel = 0; - region.imageSubresource.baseArrayLayer = face; - region.imageSubresource.layerCount = 1; - region.imageOffset = {0, 0, 0}; - region.imageExtent = {destWidth, destHeight, destDepth}; - } - } - - vkCmdCopyBufferToImage(commandBuffer, stagingBuffer->vk(device->deviceID), vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - static_cast(regions.size()), regions.data()); - - if (generateMipmaps) - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.image = vk_textureImage; - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = aspectMask; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = arrayLayers; - barrier.subresourceRange.levelCount = 1; - - int32_t mipWidth = destWidth; - int32_t mipHeight = destHeight; - int32_t mipDepth = destDepth; - - for (uint32_t i = 1; i < mipLevels; ++i) - { - barrier.subresourceRange.baseMipLevel = i - 1; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - VkImageBlit blit; - blit.srcOffsets[0] = {0, 0, 0}; - blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; - blit.srcSubresource.aspectMask = aspectMask; - blit.srcSubresource.mipLevel = i - 1; - blit.srcSubresource.baseArrayLayer = 0; - blit.srcSubresource.layerCount = arrayLayers; - blit.dstOffsets[0] = {0, 0, 0}; - blit.dstOffsets[1] = {mipWidth > 1 ? mipWidth / 2 : 1, mipHeight > 1 ? mipHeight / 2 : 1, mipDepth > 1 ? mipDepth / 2 : 1}; - blit.dstSubresource.aspectMask = aspectMask; - blit.dstSubresource.mipLevel = i; - blit.dstSubresource.baseArrayLayer = 0; - blit.dstSubresource.layerCount = arrayLayers; - - vkCmdBlitImage(commandBuffer, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, - 1, &blit, - VK_FILTER_LINEAR); - - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; - } - - barrier.subresourceRange.baseMipLevel = mipLevels - 1; - barrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier.newLayout = targetImageLayout; - barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &barrier); - } - else - { - VkImageMemoryBarrier postCopyBarrier = {}; - postCopyBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - postCopyBarrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - postCopyBarrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - postCopyBarrier.oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - postCopyBarrier.newLayout = targetImageLayout; - postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.image = vk_textureImage; - postCopyBarrier.subresourceRange.aspectMask = aspectMask; - postCopyBarrier.subresourceRange.baseArrayLayer = 0; - postCopyBarrier.subresourceRange.layerCount = arrayLayers; - postCopyBarrier.subresourceRange.levelCount = mipLevels; - postCopyBarrier.subresourceRange.baseMipLevel = 0; - - vkCmdPipelineBarrier(commandBuffer, - VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, - 0, nullptr, - 0, nullptr, - 1, &postCopyBarrier); - } -} diff --git a/src/vsg/state/ShaderModule.cpp b/src/vsg/state/ShaderModule.cpp index 9de2c7bbd6..7ddb9e8965 100644 --- a/src/vsg/state/ShaderModule.cpp +++ b/src/vsg/state/ShaderModule.cpp @@ -26,7 +26,7 @@ ShaderCompileSettings::ShaderCompileSettings() { } -ShaderCompileSettings::ShaderCompileSettings(const ShaderCompileSettings& rhs, const CopyOp& copyop): +ShaderCompileSettings::ShaderCompileSettings(const ShaderCompileSettings& rhs, const CopyOp& copyop) : Inherit(rhs, copyop), vulkanVersion(rhs.vulkanVersion), clientInputVersion(rhs.clientInputVersion), @@ -111,7 +111,7 @@ ShaderModule::ShaderModule() { } -ShaderModule::ShaderModule(const ShaderModule& rhs, const CopyOp& copyop): +ShaderModule::ShaderModule(const ShaderModule& rhs, const CopyOp& copyop) : Inherit(rhs, copyop), source(rhs.source), hints(copyop(rhs.hints)), diff --git a/src/vsg/state/ShaderStage.cpp b/src/vsg/state/ShaderStage.cpp index 81e342258f..7876f054e6 100644 --- a/src/vsg/state/ShaderStage.cpp +++ b/src/vsg/state/ShaderStage.cpp @@ -21,7 +21,7 @@ ShaderStage::ShaderStage() { } -ShaderStage::ShaderStage(const ShaderStage& rhs, const CopyOp& copyop): +ShaderStage::ShaderStage(const ShaderStage& rhs, const CopyOp& copyop) : Inherit(rhs, copyop), mask(rhs.mask), flags(rhs.flags), diff --git a/src/vsg/utils/Builder.cpp b/src/vsg/utils/Builder.cpp index 2f699b655a..59eaf5fbec 100644 --- a/src/vsg/utils/Builder.cpp +++ b/src/vsg/utils/Builder.cpp @@ -65,6 +65,8 @@ ref_ptr Builder::createStateGroup(const StateInfo& stateInfo) sampler->addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; sampler->addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + sampler->maxLod = static_cast(stateInfo.image->properties.mipLevels); + if (sharedObjects) sharedObjects->share(sampler); graphicsPipelineConfig->assignTexture("diffuseMap", stateInfo.image, sampler); diff --git a/src/vsg/vk/State.cpp b/src/vsg/vk/State.cpp index 11ddd3d8eb..86f4c622f9 100644 --- a/src/vsg/vk/State.cpp +++ b/src/vsg/vk/State.cpp @@ -74,7 +74,7 @@ void State::popView(const View& view) if ((viewportStateHint & DYNAMIC_VIEWPORTSTATE) && view.camera && view.camera->viewportState) popView(view.camera->viewportState); } -void State::inherit(State& state) +void State::inherit(const State& state) { reserve(state.maxSlots);