From 85615032d17ca3ab5e03ac1e05e148c8c1423a43 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 15 Oct 2025 12:19:46 +0100 Subject: [PATCH 01/25] Experiments with passing mipmap data via vsg::uivec4Array. --- src/vsg/core/Data.cpp | 15 +++++- src/vsg/state/Image.cpp | 4 ++ src/vsg/state/ImageInfo.cpp | 2 +- src/vsg/state/ImageView.cpp | 96 ++++++++++++++++++++++++++----------- src/vsg/utils/Builder.cpp | 5 ++ 5 files changed, 92 insertions(+), 30 deletions(-) diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 715344f922..2e5b29d952 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -12,6 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include +#include #include #include @@ -116,10 +117,20 @@ Data::MipmapOffsets Data::computeMipmapOffsets() const { if (properties.maxNumMipmaps <= 1) return {}; - uint32_t numMipmaps = properties.maxNumMipmaps; - MipmapOffsets offsets; + auto mipmapData = getObject("mipmapData"); + if (mipmapData) + { + for(auto& mipmap : *mipmapData) + { + offsets.push_back(mipmap.w); + } + return offsets; + } + + uint32_t numMipmaps = properties.maxNumMipmaps; + std::size_t w = width(); std::size_t h = height(); std::size_t d = depth(); diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index e2b5a41b8f..32eda65e11 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -95,6 +95,8 @@ Image::Image(ref_ptr in_data) : mipLevels = static_cast(mipmapOffsets.size()); 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 +200,8 @@ void Image::compile(Device* device) info.pQueueFamilyIndices = queueFamilyIndices.data(); info.initialLayout = initialLayout; + vsg::info("Image::compile(), mipLevels = ", mipLevels); + vd.device = device; vd.requiresDataCopy = data.valid(); diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 06e86f67b8..00e6cb7db4 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -191,7 +191,7 @@ 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()}); + uint32_t maxDimension = std::max({data->width() * data->properties.blockWidth, data->height() * data->properties.blockHeight, data->depth() * data->properties.blockDepth}); if (sampler->maxLod == VK_LOD_CLAMP_NONE) { while ((1u << mipLevels) <= maxDimension) diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index 0375293b7e..4448b7ec65 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -240,7 +240,21 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm const auto valueSize = properties.stride; // data->valueSize(); bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); - bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); + + ref_ptr mipmapData; + if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); + if (mipmapData) + { + mipLevels = mipmapData->size(); + useDataMipmaps = true; + } + + vsg::info("transferImageData() mipmapData = ", mipmapData, ", mipLevels = ", mipLevels); + + bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; + + vsg::info(" useDataMipmaps = ", useDataMipmaps); + vsg::info(" generateMipmaps = ", generateMipmaps); auto vk_textureImage = textureImage->vk(device->deviceID); @@ -282,39 +296,67 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 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) + if (mipmapData) { - const size_t faceSize = static_cast(faceWidth * faceHeight * faceDepth * valueSize); + auto mipmapItr = mipmapData->begin(); - for (uint32_t face = 0; face < arrayLayers; ++face) + for (uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) { - 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; + for (uint32_t face = 0; face < arrayLayers; ++face) + { + const auto& mipmap = (*mipmapItr++); + + 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}; + + vsg::info(" mipmap = ", mipmap); + } } + } + else + { + size_t offset = 0u; + uint32_t mipWidth = destWidth; + uint32_t mipHeight = destHeight; + uint32_t mipDepth = destDepth; - 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; + 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 diff --git a/src/vsg/utils/Builder.cpp b/src/vsg/utils/Builder.cpp index 16ca2b3c65..4cee203ab4 100644 --- a/src/vsg/utils/Builder.cpp +++ b/src/vsg/utils/Builder.cpp @@ -73,6 +73,11 @@ 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.maxNumMipmaps); + + vsg::info("Builder stateInfo.image = ", stateInfo.image, ", width = ", stateInfo.image->width(), ", height = ", stateInfo.image->height(), + ", maxNumMipmaps = ", int(stateInfo.image->properties.maxNumMipmaps)); + if (sharedObjects) sharedObjects->share(sampler); graphicsPipelineConfig->assignTexture("diffuseMap", stateInfo.image, sampler); From 1b868aef3c9919e84ef9dd54520b56e5619501fa Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 30 Oct 2025 13:58:50 +0000 Subject: [PATCH 02/25] Added support for ASTC. --- src/vsg/state/ImageInfo.cpp | 89 ++++++++++++++++++++++++++++++++++++- 1 file changed, 88 insertions(+), 1 deletion(-) diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 00e6cb7db4..d6021a78a0 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -177,9 +177,96 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) 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; From a29d4f52708cf3613a461ecbde9c716401e9ef37 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 15 Oct 2025 17:40:44 +0100 Subject: [PATCH 03/25] Bumped VulkanSDK version number to fix automated build --- .github/workflows/ci.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ee0512e6df..d858edc506 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,12 +10,12 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - vulkan-version: [1.3.250.1] + vulkan-version: [1.3.268.0] build-shared: [OFF] include: - build-shared: ON os: windows-latest - vulkan-version: 1.3.250.1 + vulkan-version: 1.3.268.0 continue-on-error: ${{ matrix.vulkan-version == 'latest' }} steps: From ab38cbdca60ffe805d47c320e4bba64dab2b33a5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 31 Oct 2025 18:22:39 +0000 Subject: [PATCH 04/25] Added additional format support --- src/vsg/state/ImageInfo.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index d6021a78a0..3743fc0bea 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -177,6 +177,26 @@ 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) + { + 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) + { + 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; From 87a3a8714440747bf3cff2914dd5a1557f060c7b Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 5 Nov 2025 12:33:45 +0000 Subject: [PATCH 05/25] Implemented support for more formats. --- src/vsg/state/ImageInfo.cpp | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 3743fc0bea..f68c4b4e16 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; From d5f3e98c8917aa024d90fb5af6278756ece22549 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Thu, 6 Nov 2025 13:22:25 +0000 Subject: [PATCH 06/25] Queitened debug messages and added support for VK_FORMAT_EAC* formats --- src/vsg/state/Image.cpp | 4 ++-- src/vsg/state/ImageInfo.cpp | 6 ++++-- src/vsg/state/ImageView.cpp | 5 +++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 32eda65e11..a5b98ed656 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -95,7 +95,7 @@ Image::Image(ref_ptr in_data) : mipLevels = static_cast(mipmapOffsets.size()); extent = VkExtent3D{width, height, depth}; - vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); + // vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); // remap RGB to RGBA if (format >= VK_FORMAT_R8G8B8_UNORM && format <= VK_FORMAT_B8G8R8_SRGB) @@ -200,7 +200,7 @@ void Image::compile(Device* device) info.pQueueFamilyIndices = queueFamilyIndices.data(); info.initialLayout = initialLayout; - vsg::info("Image::compile(), mipLevels = ", mipLevels); + // vsg::info("Image::compile(), mipLevels = ", mipLevels); vd.device = device; diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index f68c4b4e16..59440b79aa 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -208,7 +208,8 @@ 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) + 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; @@ -218,7 +219,8 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) traits.numComponents = 1; traits.size = 8; } - else if (VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK <= format && format <= VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK) + 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; diff --git a/src/vsg/state/ImageView.cpp b/src/vsg/state/ImageView.cpp index 4448b7ec65..53193e96c0 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -249,12 +249,13 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm useDataMipmaps = true; } - vsg::info("transferImageData() mipmapData = ", mipmapData, ", mipLevels = ", mipLevels); - bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; +#if 0 + vsg::info("transferImageData() mipmapData = ", mipmapData, ", mipLevels = ", mipLevels); vsg::info(" useDataMipmaps = ", useDataMipmaps); vsg::info(" generateMipmaps = ", generateMipmaps); +#endif auto vk_textureImage = textureImage->vk(device->deviceID); From f5cb83e594dcffe9b5324d00cd22c5631f5bf8e1 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Fri, 14 Nov 2025 18:50:58 +0000 Subject: [PATCH 07/25] Refactored how mipmaps are managed. --- include/vsg/core/Array.h | 10 +++---- include/vsg/core/Array2D.h | 13 +++++---- include/vsg/core/Array3D.h | 15 +++++----- include/vsg/core/Data.h | 2 +- src/vsg/app/TransferTask.cpp | 3 +- src/vsg/core/Data.cpp | 46 ++++++++++++++++++++--------- src/vsg/state/Image.cpp | 2 +- src/vsg/state/ImageInfo.cpp | 56 ++++++++++++++++++++---------------- src/vsg/state/ImageView.cpp | 39 +++++++++++++------------ 9 files changed, 108 insertions(+), 78 deletions(-) diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index ebc3209a14..b6618120c4 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -165,7 +165,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,9 +184,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); @@ -209,7 +209,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.maxNumMipmaps <= 1) ? _size : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index 999b423e32..df60e21083 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -144,7 +144,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,10 +164,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); @@ -190,7 +191,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.maxNumMipmaps <= 1) ? (static_cast(_width) * static_cast(_height)) : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 033bf9d84c..bdb32eb8f4 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -150,7 +150,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,11 +171,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); @@ -198,7 +199,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.maxNumMipmaps <= 1) ? (static_cast(_width) * _height * _depth) : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index d785490fb3..5eb83e2385 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -191,7 +191,7 @@ namespace vsg 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; } diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 45fd522188..66560cbc5f 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -267,7 +267,8 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Transfer 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; diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 2e5b29d952..59c314902a 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -137,35 +137,53 @@ Data::MipmapOffsets Data::computeMipmapOffsets() const std::size_t lastPosition = 0; offsets.push_back(lastPosition); - while (numMipmaps > 1 && (w > 1 || h > 1 || d > 1)) + while (numMipmaps > 1) { lastPosition += (w * h * d); offsets.push_back(lastPosition); --numMipmaps; - if (w > 1) w /= 2; - if (h > 1) h /= 2; - if (d > 1) d /= 2; + if (w > 1) w = (w+1)/2; + if (h > 1) h = (h+1)/2; + if (d > 1) d = (d+1)/2; } return offsets; } -std::size_t Data::computeValueCountIncludingMipmaps(std::size_t w, std::size_t h, std::size_t d, uint32_t numMipmaps) +std::size_t Data::computeValueCountIncludingMipmaps() const { - if (numMipmaps <= 1) return w * h * d; + std::size_t count = 0; - std::size_t lastPosition = (w * h * d); - while (numMipmaps > 1 && (w > 1 || h > 1 || d > 1)) + auto mipmapData = getObject("mipmapData"); + if (mipmapData) { - --numMipmaps; + for(auto& mipmap : *mipmapData) + { + 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 w = width(); + std::size_t h = height(); + std::size_t d = depth(); - if (w > 1) w /= 2; - if (h > 1) h /= 2; - if (d > 1) d /= 2; + count = w*h*d; - lastPosition += (w * h * d); + for(uint8_t level = 1; level < properties.maxNumMipmaps; ++level) + { + if (w > 1) w = w/2; + if (h > 1) h = h/2; + if (d > 1) d = d/2; + + count += w*h*d; + } } - return lastPosition; + return count; } diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index a5b98ed656..9d79e12c98 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -200,7 +200,7 @@ void Image::compile(Device* device) info.pQueueFamilyIndices = queueFamilyIndices.data(); info.initialLayout = initialLayout; - // vsg::info("Image::compile(), mipLevels = ", mipLevels); + // vsg::info("Image::compile(), data = ",data, ", mipLevels = ", mipLevels, ", arrayLayers = ", arrayLayers, ", extent = {", extent.width, ", ", extent.height, ", ", extent.depth, "}"); vd.device = device; diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 59440b79aa..11bfd14813 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -347,6 +347,33 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) --mipLevels; } } + + const auto& mipmapOffsets = 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; + } + } + else + { + if (mipmapOffsets.size() < mipLevels) + { + mipLevels = mipmapOffsets.size(); + } + } + // vsg::info("computeNumMipMapLevels(", sampler->maxLod, ", data->mipmapOffsets.size() = ", mipmapOffsets.size(), ", mipLevels = ", mipLevels); + } //mipLevels = 1; // disable mipmapping @@ -381,30 +408,11 @@ 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; - + auto& image = imageView->image; + auto& data = image->data; + image->mipLevels = vsg::computeNumMipMapLevels(data, sampler); + const auto& mipmapOffsets = data->computeMipmapOffsets(); + bool generateMipmaps = (image->mipLevels > 1) && (mipmapOffsets.size() <= 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 53193e96c0..50257bd850 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -245,18 +245,16 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); if (mipmapData) { - mipLevels = mipmapData->size(); - useDataMipmaps = true; + auto& mipmap0 = mipmapData->at(0); + destWidth = mipmap0.x; + destHeight = mipmap0.y; + destDepth = mipmap0.z; + + useDataMipmaps = mipmapData->size() > 1; } bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; -#if 0 - vsg::info("transferImageData() mipmapData = ", mipmapData, ", mipLevels = ", mipLevels); - vsg::info(" useDataMipmaps = ", useDataMipmaps); - vsg::info(" generateMipmaps = ", generateMipmaps); -#endif - auto vk_textureImage = textureImage->vk(device->deviceID); if (generateMipmaps) @@ -297,18 +295,17 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm if (useDataMipmaps) { - regions.resize(mipLevels * arrayLayers); - if (mipmapData) { - auto mipmapItr = mipmapData->begin(); + 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) { - const auto& mipmap = (*mipmapItr++); - auto& region = regions[mipLevel * arrayLayers + face]; region.bufferOffset = stagingBufferOffset + mipmap.w; region.bufferRowLength = 0; @@ -319,13 +316,13 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm region.imageSubresource.layerCount = 1; region.imageOffset = {0, 0, 0}; region.imageExtent = {mipmap.x, mipmap.y, mipmap.z}; - - vsg::info(" mipmap = ", mipmap); } } } else { + regions.resize(mipLevels * arrayLayers); + size_t offset = 0u; uint32_t mipWidth = destWidth; uint32_t mipHeight = destHeight; @@ -413,6 +410,10 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 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}; @@ -421,7 +422,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 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.dstOffsets[1] = {nextWidth, nextHeight, nextDepth}; blit.dstSubresource.aspectMask = aspectMask; blit.dstSubresource.mipLevel = i; blit.dstSubresource.baseArrayLayer = 0; @@ -444,9 +445,9 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 0, nullptr, 1, &barrier); - if (mipWidth > 1) mipWidth /= 2; - if (mipHeight > 1) mipHeight /= 2; - if (mipDepth > 1) mipDepth /= 2; + mipWidth = nextWidth; + mipHeight = nextHeight; + mipDepth = nextDepth; } barrier.subresourceRange.baseMipLevel = mipLevels - 1; From 042e2372cd49606fe09982b59e4685e72444801e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 15 Nov 2025 10:52:36 +0000 Subject: [PATCH 08/25] Moved transferImageData(..) function from ImageView header/source file into TransferTask header/source file. --- include/vsg/app/TransferTask.h | 3 + src/vsg/app/TransferTask.cpp | 292 +++++++++++++++++++++++ src/vsg/commands/CopyAndReleaseImage.cpp | 2 +- 3 files changed, 296 insertions(+), 1 deletion(-) diff --git a/include/vsg/app/TransferTask.h b/include/vsg/app/TransferTask.h index 4308f9c852..2a19e66e84 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, const Data::MipmapOffsets& mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device); + } // namespace vsg diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 66560cbc5f..0f3a50e821 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -559,3 +559,295 @@ 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, 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); + + ref_ptr mipmapData; + if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); + if (mipmapData) + { + auto& mipmap0 = mipmapData->at(0); + destWidth = mipmap0.x; + destHeight = mipmap0.y; + destDepth = mipmap0.z; + + useDataMipmaps = mipmapData->size() > 1; + } + + bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; + + 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) + { + 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_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); + + 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_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); + + 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_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/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index 1556194d26..aba3799c0f 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -13,7 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include +#include using namespace vsg; From bf6b42208c7597b0ff5e3408a250e103c8fbba38 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sat, 15 Nov 2025 11:30:05 +0000 Subject: [PATCH 09/25] Removed no longer required mipmap API --- include/vsg/app/TransferTask.h | 2 +- include/vsg/commands/CopyAndReleaseImage.h | 1 - include/vsg/core/Data.h | 2 - include/vsg/state/ImageView.h | 3 - src/vsg/app/TransferTask.cpp | 13 +- src/vsg/commands/CopyAndReleaseImage.cpp | 3 +- src/vsg/core/Data.cpp | 38 --- src/vsg/state/Image.cpp | 3 +- src/vsg/state/ImageInfo.cpp | 10 +- src/vsg/state/ImageView.cpp | 288 --------------------- 10 files changed, 16 insertions(+), 347 deletions(-) diff --git a/include/vsg/app/TransferTask.h b/include/vsg/app/TransferTask.h index 2a19e66e84..b098bbb0b6 100644 --- a/include/vsg/app/TransferTask.h +++ b/include/vsg/app/TransferTask.h @@ -119,6 +119,6 @@ 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, const Data::MipmapOffsets& mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device); + 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/Data.h b/include/vsg/core/Data.h index 5eb83e2385..0335aa4fc6 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -189,8 +189,6 @@ namespace vsg uint32_t stride() const { return properties.stride ? properties.stride : static_cast(valueSize()); } - using MipmapOffsets = std::vector; - MipmapOffsets computeMipmapOffsets() const; size_t computeValueCountIncludingMipmaps() const; /// increment the ModifiedCount to signify the data has been modified 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/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 0f3a50e821..708f227d8b 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -266,7 +266,6 @@ 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 = imageInfo.imageView->image->mipLevels; @@ -334,7 +333,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) @@ -564,7 +563,7 @@ TransferTask::TransferResult TransferTask::_transferData(DataToCopy& dataToCopy) // // 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, const Data::MipmapOffsets& mipmapOffsets, ref_ptr stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device) +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) { ref_ptr textureImage(imageView->image); auto aspectMask = imageView->subresourceRange.aspectMask; @@ -604,7 +603,8 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm const auto valueSize = properties.stride; // data->valueSize(); - bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1); + mipLevels = std::min(mipLevels, static_cast(imageView->image->data->properties.maxNumMipmaps)); + bool useDataMipmaps = false; ref_ptr mipmapData; if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); @@ -616,6 +616,11 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm destDepth = mipmap0.z; useDataMipmaps = mipmapData->size() > 1; + mipLevels = std::min(mipLevels, static_cast(mipmapData->size())); + } + else if (imageView->image->data->properties.maxNumMipmaps > 1) + { + useDataMipmaps = true; } bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; diff --git a/src/vsg/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index aba3799c0f..089036fffc 100644 --- a/src/vsg/commands/CopyAndReleaseImage.cpp +++ b/src/vsg/commands/CopyAndReleaseImage.cpp @@ -37,7 +37,6 @@ CopyAndReleaseImage::CopyData::CopyData(ref_ptr src, ref_ptrdata->width(); height = source->data->height(); depth = source->data->depth(); - mipmapOffsets = source->data->computeMipmapOffsets(); } } @@ -165,7 +164,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/Data.cpp b/src/vsg/core/Data.cpp index 59c314902a..82311fbf76 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -113,44 +113,6 @@ void Data::write(Output& output) const } } -Data::MipmapOffsets Data::computeMipmapOffsets() const -{ - if (properties.maxNumMipmaps <= 1) return {}; - - MipmapOffsets offsets; - - auto mipmapData = getObject("mipmapData"); - if (mipmapData) - { - for(auto& mipmap : *mipmapData) - { - offsets.push_back(mipmap.w); - } - return offsets; - } - - uint32_t numMipmaps = properties.maxNumMipmaps; - - std::size_t w = width(); - std::size_t h = height(); - std::size_t d = depth(); - - std::size_t lastPosition = 0; - offsets.push_back(lastPosition); - while (numMipmaps > 1) - { - lastPosition += (w * h * d); - offsets.push_back(lastPosition); - - --numMipmaps; - if (w > 1) w = (w+1)/2; - if (h > 1) h = (h+1)/2; - if (d > 1) d = (d+1)/2; - } - - return offsets; -} - std::size_t Data::computeValueCountIncludingMipmaps() const { std::size_t count = 0; diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 9d79e12c98..6bbb20c58a 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -38,7 +38,6 @@ 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; @@ -92,7 +91,7 @@ Image::Image(ref_ptr in_data) : } format = properties.format; - mipLevels = static_cast(mipmapOffsets.size()); + mipLevels = data->properties.maxNumMipmaps; extent = VkExtent3D{width, height, depth}; // vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 11bfd14813..d54efd97b8 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -348,8 +348,7 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) } } - const auto& mipmapOffsets = data->computeMipmapOffsets(); - bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1); + bool generateMipmaps = (mipLevels > 1) && (data->properties.maxNumMipmaps <= 1); if (generateMipmaps) { @@ -367,9 +366,9 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) } else { - if (mipmapOffsets.size() < mipLevels) + if (data->properties.maxNumMipmaps < mipLevels) { - mipLevels = mipmapOffsets.size(); + mipLevels = data->properties.maxNumMipmaps; } } // vsg::info("computeNumMipMapLevels(", sampler->maxLod, ", data->mipmapOffsets.size() = ", mipmapOffsets.size(), ", mipLevels = ", mipLevels); @@ -411,8 +410,7 @@ void ImageInfo::computeNumMipMapLevels() auto& image = imageView->image; auto& data = image->data; image->mipLevels = vsg::computeNumMipMapLevels(data, sampler); - const auto& mipmapOffsets = data->computeMipmapOffsets(); - bool generateMipmaps = (image->mipLevels > 1) && (mipmapOffsets.size() <= 1); + bool generateMipmaps = (image->mipLevels > 1) && (data->properties.maxNumMipmaps <= 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 50257bd850..e8d8a722ea 100644 --- a/src/vsg/state/ImageView.cpp +++ b/src/vsg/state/ImageView.cpp @@ -198,291 +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); - - ref_ptr mipmapData; - if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); - if (mipmapData) - { - auto& mipmap0 = mipmapData->at(0); - destWidth = mipmap0.x; - destHeight = mipmap0.y; - destDepth = mipmap0.z; - - useDataMipmaps = mipmapData->size() > 1; - } - - bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; - - 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) - { - 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_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); - - 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_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); - - 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_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); - } -} From 8d41978fe13a606a89516b4be84af2cce79273ca Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 16 Nov 2025 11:53:55 +0000 Subject: [PATCH 10/25] Added include to fix Windows build --- src/vsg/commands/CopyAndReleaseImage.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/vsg/commands/CopyAndReleaseImage.cpp b/src/vsg/commands/CopyAndReleaseImage.cpp index 089036fffc..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; From fa87f80fb759b4773d1f397606107798fe047408 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 16 Nov 2025 12:22:55 +0000 Subject: [PATCH 11/25] Improved handling of vsg::Data mipmap data. --- src/vsg/app/TransferTask.cpp | 43 +++++++++++++++++++++--------------- src/vsg/state/Image.cpp | 2 +- 2 files changed, 26 insertions(+), 19 deletions(-) diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 708f227d8b..25b7083368 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -565,7 +565,13 @@ TransferTask::TransferResult TransferTask::_transferData(DataToCopy& dataToCopy) // 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) { - ref_ptr textureImage(imageView->image); + 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; @@ -603,11 +609,9 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm const auto valueSize = properties.stride; // data->valueSize(); - mipLevels = std::min(mipLevels, static_cast(imageView->image->data->properties.maxNumMipmaps)); - bool useDataMipmaps = false; + uint32_t data_mipLevels = static_cast(data->properties.maxNumMipmaps); - ref_ptr mipmapData; - if (imageView->image && imageView->image->data) mipmapData = imageView->image->data->getObject("mipmapData"); + auto mipmapData = data->getObject("mipmapData"); if (mipmapData) { auto& mipmap0 = mipmapData->at(0); @@ -615,17 +619,18 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm destHeight = mipmap0.y; destDepth = mipmap0.z; - useDataMipmaps = mipmapData->size() > 1; - mipLevels = std::min(mipLevels, static_cast(mipmapData->size())); - } - else if (imageView->image->data->properties.maxNumMipmaps > 1) - { - useDataMipmaps = true; + if (mipmapData->size() > 1) + { + data_mipLevels = static_cast(mipmapData->size()); + } } + bool useDataMipmaps = mipLevels > 1 && data_mipLevels > 1; bool generateMipmaps = (mipLevels > 1) && !useDataMipmaps; - auto vk_textureImage = textureImage->vk(device->deviceID); + if (useDataMipmaps) mipLevels = std::min(mipLevels, data_mipLevels); + + // vsg::info("vsg::transferImageData() data = ", data, ", data->properties.maxNumMipmaps = ", int(data->properties.maxNumMipmaps), ", data_mipLevels = ", data_mipLevels, " mipLevels = ", mipLevels, ", mipmapData = ", mipmapData, ", generateMipmaps = ", generateMipmaps); if (generateMipmaps) { @@ -648,7 +653,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 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.image = vk_image; preCopyBarrier.subresourceRange.aspectMask = aspectMask; preCopyBarrier.subresourceRange.baseArrayLayer = 0; preCopyBarrier.subresourceRange.layerCount = arrayLayers; @@ -747,14 +752,14 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm } } - vkCmdCopyBufferToImage(commandBuffer, stagingBuffer->vk(device->deviceID), vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + 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_textureImage; + barrier.image = vk_image; barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; barrier.subresourceRange.aspectMask = aspectMask; @@ -784,6 +789,8 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm int32_t nextHeight = (mipHeight > 1) ? (mipHeight)/2 : 1; int32_t nextDepth = (mipDepth > 1) ? (mipDepth)/2 : 1; + vsg::info("blitting level = ", i, ", { ", mipWidth, ", ", mipHeight, ", ", mipDepth, "} -> {", nextWidth, ", ", nextHeight, ", ", nextDepth, "}"); + VkImageBlit blit; blit.srcOffsets[0] = {0, 0, 0}; blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; @@ -799,8 +806,8 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm blit.dstSubresource.layerCount = arrayLayers; vkCmdBlitImage(commandBuffer, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, - vk_textureImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, + vk_image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, + vk_image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &blit, VK_FILTER_LINEAR); @@ -842,7 +849,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm postCopyBarrier.newLayout = targetImageLayout; postCopyBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; postCopyBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - postCopyBarrier.image = vk_textureImage; + postCopyBarrier.image = vk_image; postCopyBarrier.subresourceRange.aspectMask = aspectMask; postCopyBarrier.subresourceRange.baseArrayLayer = 0; postCopyBarrier.subresourceRange.layerCount = arrayLayers; diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 6bbb20c58a..20176c84a6 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -91,7 +91,7 @@ Image::Image(ref_ptr in_data) : } format = properties.format; - mipLevels = data->properties.maxNumMipmaps; + mipLevels = std::max(1u, static_cast(data->properties.maxNumMipmaps)); extent = VkExtent3D{width, height, depth}; // vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); From 856cd2ab84e659e20443a8363469eb59f8f113b2 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Sun, 16 Nov 2025 12:41:50 +0000 Subject: [PATCH 12/25] Renamed Properties.maxNumMipMaps to Properties.mipLevels to be consistent with Vulkan naming. --- include/vsg/core/Array.h | 2 +- include/vsg/core/Array2D.h | 2 +- include/vsg/core/Array3D.h | 2 +- include/vsg/core/Data.h | 2 +- src/vsg/app/TransferTask.cpp | 6 ++---- src/vsg/core/Data.cpp | 16 ++++++++-------- src/vsg/state/Image.cpp | 2 +- src/vsg/state/ImageInfo.cpp | 8 ++++---- src/vsg/utils/Builder.cpp | 4 ++-- 9 files changed, 21 insertions(+), 23 deletions(-) diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index b6618120c4..b50b8ad8f5 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -209,7 +209,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? _size : computeValueCountIncludingMipmaps(); } + size_t size() const { return (properties.mipLevels <= 1) ? _size : computeValueCountIncludingMipmaps(); } bool available() const { return _data != nullptr; } bool empty() const { return _data == nullptr; } diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index df60e21083..e191920a07 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -191,7 +191,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast(_width) * static_cast(_height)) : computeValueCountIncludingMipmaps(); } + 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; } diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index bdb32eb8f4..5482cec004 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -199,7 +199,7 @@ namespace vsg output.writeEndOfLine(); } - size_t size() const { return (properties.maxNumMipmaps <= 1) ? (static_cast(_width) * _height * _depth) : computeValueCountIncludingMipmaps(); } + 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; } diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index 0335aa4fc6..b3023f8569 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -121,7 +121,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; diff --git a/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 25b7083368..9c1fb3048d 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -609,7 +609,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm const auto valueSize = properties.stride; // data->valueSize(); - uint32_t data_mipLevels = static_cast(data->properties.maxNumMipmaps); + uint32_t data_mipLevels = static_cast(data->properties.mipLevels); auto mipmapData = data->getObject("mipmapData"); if (mipmapData) @@ -630,7 +630,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm if (useDataMipmaps) mipLevels = std::min(mipLevels, data_mipLevels); - // vsg::info("vsg::transferImageData() data = ", data, ", data->properties.maxNumMipmaps = ", int(data->properties.maxNumMipmaps), ", data_mipLevels = ", data_mipLevels, " mipLevels = ", mipLevels, ", mipmapData = ", mipmapData, ", generateMipmaps = ", generateMipmaps); + // 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) { @@ -789,8 +789,6 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm int32_t nextHeight = (mipHeight > 1) ? (mipHeight)/2 : 1; int32_t nextDepth = (mipDepth > 1) ? (mipDepth)/2 : 1; - vsg::info("blitting level = ", i, ", { ", mipWidth, ", ", mipHeight, ", ", mipDepth, "} -> {", nextWidth, ", ", nextHeight, ", ", nextDepth, "}"); - VkImageBlit blit; blit.srcOffsets[0] = {0, 0, 0}; blit.srcOffsets[1] = {mipWidth, mipHeight, mipDepth}; diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 82311fbf76..3cfc04b7c5 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -29,7 +29,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; @@ -79,15 +79,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; } @@ -101,15 +101,15 @@ 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); } } @@ -137,7 +137,7 @@ std::size_t Data::computeValueCountIncludingMipmaps() const count = w*h*d; - for(uint8_t level = 1; level < properties.maxNumMipmaps; ++level) + for(uint8_t level = 1; level < properties.mipLevels; ++level) { if (w > 1) w = w/2; if (h > 1) h = h/2; diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 20176c84a6..9e1499ed2d 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -91,7 +91,7 @@ Image::Image(ref_ptr in_data) : } format = properties.format; - mipLevels = std::max(1u, static_cast(data->properties.maxNumMipmaps)); + mipLevels = std::max(1u, static_cast(data->properties.mipLevels)); extent = VkExtent3D{width, height, depth}; // vsg::info("Image::Image(", data, ") mpipLevels = ", mipLevels); diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index d54efd97b8..13d0852580 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -348,7 +348,7 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) } } - bool generateMipmaps = (mipLevels > 1) && (data->properties.maxNumMipmaps <= 1); + bool generateMipmaps = (mipLevels > 1) && (data->properties.mipLevels <= 1); if (generateMipmaps) { @@ -366,9 +366,9 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) } else { - if (data->properties.maxNumMipmaps < mipLevels) + if (data->properties.mipLevels < mipLevels) { - mipLevels = data->properties.maxNumMipmaps; + mipLevels = data->properties.mipLevels; } } // vsg::info("computeNumMipMapLevels(", sampler->maxLod, ", data->mipmapOffsets.size() = ", mipmapOffsets.size(), ", mipLevels = ", mipLevels); @@ -410,7 +410,7 @@ void ImageInfo::computeNumMipMapLevels() auto& image = imageView->image; auto& data = image->data; image->mipLevels = vsg::computeNumMipMapLevels(data, sampler); - bool generateMipmaps = (image->mipLevels > 1) && (data->properties.maxNumMipmaps <= 1); + bool generateMipmaps = (image->mipLevels > 1) && (data->properties.mipLevels <= 1); if (generateMipmaps) image->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT; } } diff --git a/src/vsg/utils/Builder.cpp b/src/vsg/utils/Builder.cpp index 7d7bc13cb7..e4f0ec3ded 100644 --- a/src/vsg/utils/Builder.cpp +++ b/src/vsg/utils/Builder.cpp @@ -65,10 +65,10 @@ 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.maxNumMipmaps); + sampler->maxLod = static_cast(stateInfo.image->properties.mipLevels); vsg::info("Builder stateInfo.image = ", stateInfo.image, ", width = ", stateInfo.image->width(), ", height = ", stateInfo.image->height(), - ", maxNumMipmaps = ", int(stateInfo.image->properties.maxNumMipmaps)); + ", mipLevels = ", int(stateInfo.image->properties.mipLevels)); if (sharedObjects) sharedObjects->share(sampler); From 0e5576ff67ff192d5c85c87aecbe9ad22fde8c5e Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 17 Nov 2025 19:08:50 +0000 Subject: [PATCH 13/25] Created dedicated MipmapDetails class to hold the mipmap layout --- include/vsg/core/Array.h | 28 ++++++++++++----- include/vsg/core/Array2D.h | 27 +++++++++++----- include/vsg/core/Array3D.h | 26 +++++++++++----- include/vsg/core/Data.h | 16 ++++++++++ include/vsg/core/MipmapDetails.h | 52 +++++++++++++++++++++++++++++++ include/vsg/core/Value.h | 7 +++++ src/vsg/CMakeLists.txt | 1 + src/vsg/app/TransferTask.cpp | 3 +- src/vsg/core/Data.cpp | 53 ++++++++++++++++++++++++++++++-- src/vsg/core/MipmapDetails.cpp | 27 ++++++++++++++++ src/vsg/state/ArrayState.cpp | 1 + src/vsg/state/Image.cpp | 4 +-- src/vsg/state/ImageInfo.cpp | 3 +- 13 files changed, 217 insertions(+), 31 deletions(-) create mode 100644 include/vsg/core/MipmapDetails.h create mode 100644 src/vsg/core/MipmapDetails.cpp diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index b50b8ad8f5..12a86a1c75 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -12,6 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +#include #include #include @@ -31,7 +32,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - template class Array : public Data { @@ -63,10 +63,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 = {}, MipmapDetails* mipmapDetails = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), - _size(numElements) { dirty(); } + _size(numElements) + { + setMipmapDetails(mipmapDetails); + dirty(); + } Array(uint32_t numElements, const value_type& value, Properties in_properties = {}) : Data(in_properties, sizeof(value_type)), @@ -77,12 +81,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 = {}, MipmapDetails* mipmapDetails = nullptr) : Data(), _data(nullptr), _size(0) { - assign(data, offset, stride, numElements, in_properties); + assign(data, offset, stride, numElements, in_properties, mipmapDetails); } explicit Array(std::initializer_list l) : @@ -229,7 +233,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _size = rhs._size; if (_size != 0) @@ -239,12 +244,13 @@ namespace vsg for (const auto& v : rhs) *(dest_v++) = v; } + dirty(); return *this; } - void assign(uint32_t numElements, value_type* data, Properties in_properties = {}) + void assign(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -254,10 +260,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapDetails(mipmapDetails); + 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 = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -275,6 +283,8 @@ namespace vsg _size = 0; } + setMipmapDetails(mipmapDetails); + dirty(); } @@ -365,6 +375,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + removeMipmapDetails(); } private: diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index e191920a07..a7030263d0 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -12,8 +12,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +#include #include - #include #include #include @@ -68,11 +68,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 = {}, MipmapDetails* mipmapDetails = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), _width(width), - _height(height) { dirty(); } + _height(height) + { + setMipmapDetails(mipmapDetails); + dirty(); + } Array2D(uint32_t width, uint32_t height, const value_type& value, Properties in_properties = {}) : Data(in_properties, sizeof(value_type)), @@ -88,13 +92,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 = {}, MipmapDetails* mipmapDetails = nullptr) : Data(), _data(nullptr), _width(0), _height(0) { - assign(data, offset, stride, width, height, in_properties); + assign(data, offset, stride, width, height, in_properties, mipmapDetails); } template @@ -212,7 +216,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _width = rhs._width; _height = rhs._height; @@ -228,7 +233,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 = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -239,10 +244,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapDetails(mipmapDetails); + 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 = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -262,6 +269,8 @@ namespace vsg _height = 0; } + setMipmapDetails(mipmapDetails); + dirty(); } @@ -361,6 +370,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + removeMipmapDetails(); } private: diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 5482cec004..9a638e831d 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -12,6 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +#include #include #include @@ -70,12 +71,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 = {}, MipmapDetails* mipmapDetails = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), _width(width), _height(height), - _depth(depth) { dirty(); } + _depth(depth) + { + setMipmapDetails(mipmapDetails); + 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 +97,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 = {}, MipmapDetails* mipmapDetails = 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, mipmapDetails); } template @@ -221,7 +226,8 @@ namespace vsg clear(); - properties = rhs.properties; + _copy(rhs); + _width = rhs._width; _height = rhs._height; _depth = rhs._depth; @@ -238,7 +244,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 = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -250,10 +256,12 @@ namespace vsg _data = data; _storage = nullptr; + setMipmapDetails(mipmapDetails); + 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 = {}, MipmapDetails* mipmapDetails = nullptr) { _delete(); @@ -275,6 +283,8 @@ namespace vsg _depth = 0; } + setMipmapDetails(mipmapDetails); + dirty(); } @@ -376,6 +386,8 @@ namespace vsg else if (properties.allocatorType != 0) vsg::deallocate(_data); } + + removeMipmapDetails(); } private: diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index b3023f8569..f7114d08a0 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 MipmapDetails + class MipmapDetails; + /// 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 MipmapDetails; + /// 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 @@ -185,6 +190,9 @@ 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()); } @@ -209,9 +217,17 @@ namespace vsg /// return true if Data's ModifiedCount is different from the specified ModifiedCount bool differentModifiedCount(const ModifiedCount& mc) const { return _modifiedCount != mc; } + void setMipmapDetails(MipmapDetails* mipmapData); + + const MipmapDetails* getMipmapDetails() const; + + void removeMipmapDetails(); + protected: virtual ~Data() {} + void _copy(const Data& rhs); + ModifiedCount _modifiedCount; #if 1 diff --git a/include/vsg/core/MipmapDetails.h b/include/vsg/core/MipmapDetails.h new file mode 100644 index 0000000000..3b236b80a7 --- /dev/null +++ b/include/vsg/core/MipmapDetails.h @@ -0,0 +1,52 @@ +#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 MipmapDetails : public Inherit + { + public: + + MipmapDetails() {} + + MipmapDetails(std::size_t size) : mipmaps(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, 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; + }; + VSG_type_name(vsg::MipmapDetails); + +} // namespace vsg diff --git a/include/vsg/core/Value.h b/include/vsg/core/Value.h index c813bd456c..71440ad6ac 100644 --- a/include/vsg/core/Value.h +++ b/include/vsg/core/Value.h @@ -12,6 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ +#include #include #include @@ -142,6 +143,12 @@ namespace vsg Value& operator=(const Value& rhs) { _value = rhs._value; + + if (getAuxiliary()) + { + getOrCreateAuxiliary()->userObjects = getAuxiliary()->userObjects; + } + return *this; } Value& operator=(const value_type& rhs) diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 26e87199aa..7677e25f02 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/MipmapDetails.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 9c1fb3048d..373a3bf511 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 @@ -611,7 +612,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm uint32_t data_mipLevels = static_cast(data->properties.mipLevels); - auto mipmapData = data->getObject("mipmapData"); + auto mipmapData = data->getMipmapDetails(); if (mipmapData) { auto& mipmap0 = mipmapData->at(0); diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 3cfc04b7c5..5bb5fd045c 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -13,6 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include #include @@ -117,10 +118,10 @@ std::size_t Data::computeValueCountIncludingMipmaps() const { std::size_t count = 0; - auto mipmapData = getObject("mipmapData"); - if (mipmapData) + auto mipmapDetails = getObject("mipmapDetails"); + if (mipmapDetails) { - for(auto& mipmap : *mipmapData) + for(auto& mipmap : *mipmapDetails) { std::size_t w = (mipmap.x+properties.blockWidth-1)/properties.blockWidth; std::size_t h = (mipmap.y+properties.blockHeight-1)/properties.blockHeight; @@ -149,3 +150,49 @@ std::size_t Data::computeValueCountIncludingMipmaps() const return count; } + +void Data::_copy(const Data& rhs) +{ + properties = rhs.properties; + if (rhs.getAuxiliary()) + { + getOrCreateAuxiliary()->userObjects = rhs.getAuxiliary()->userObjects; + } + else if (getAuxiliary()) + { + getAuxiliary()->userObjects.clear(); + } +} + +void Data::setMipmapDetails(MipmapDetails* mipmapDetails) +{ + if (mipmapDetails) setObject("mipmapDetails", ref_ptr(mipmapDetails)); + else if (getAuxiliary()) removeObject("mipmapDetails"); +} + +const MipmapDetails* Data::getMipmapDetails() const +{ + return getObject("mipmapDetails"); +} + +void Data::removeMipmapDetails() +{ + if (getAuxiliary()) removeObject("mipmapDetails"); +} + +std::tuple Data::pixelExtents() const +{ + uint32_t w = width() * properties.blockWidth; + uint32_t h = height() * properties.blockHeight; + uint32_t d = depth() * properties.blockDepth; + + if (auto mipmapDetails = getMipmapDetails()) + { + auto mipmap = mipmapDetails->at(0); + w = mipmap.x; + h = mipmap.y; + d = mipmap.z; + } + + return {w, h, d}; +} diff --git a/src/vsg/core/MipmapDetails.cpp b/src/vsg/core/MipmapDetails.cpp new file mode 100644 index 0000000000..6982b9d6d2 --- /dev/null +++ b/src/vsg/core/MipmapDetails.cpp @@ -0,0 +1,27 @@ +/* + +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; + +void MipmapDetails::read(Input& input) +{ + Object::read(input); +} + +void MipmapDetails::write(Output& output) const +{ + Object::write(output); +} diff --git a/src/vsg/state/ArrayState.cpp b/src/vsg/state/ArrayState.cpp index 1a08fe9dba..f5856f3735 100644 --- a/src/vsg/state/ArrayState.cpp +++ b/src/vsg/state/ArrayState.cpp @@ -27,6 +27,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace vsg; diff --git a/src/vsg/state/Image.cpp b/src/vsg/state/Image.cpp index 9e1499ed2d..42417d61e5 100644 --- a/src/vsg/state/Image.cpp +++ b/src/vsg/state/Image.cpp @@ -40,9 +40,7 @@ Image::Image(ref_ptr in_data) : auto properties = data->properties; 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) { diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 13d0852580..eb38bff8a4 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -331,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->properties.blockWidth, data->height() * data->properties.blockHeight, data->depth() * data->properties.blockDepth}); + 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) From f3280bc046b698744202002b2f0a022efe091a23 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Mon, 17 Nov 2025 19:30:54 +0000 Subject: [PATCH 14/25] Renamed MipmapDetails to MipmapLayout to better reflect it's role. --- include/vsg/all.h | 1 + include/vsg/core/Array.h | 18 ++++++------- include/vsg/core/Array2D.h | 18 ++++++------- include/vsg/core/Array3D.h | 18 ++++++------- include/vsg/core/Data.h | 12 ++++----- .../core/{MipmapDetails.h => MipmapLayout.h} | 8 +++--- src/vsg/CMakeLists.txt | 2 +- src/vsg/app/TransferTask.cpp | 4 +-- src/vsg/core/Data.cpp | 26 +++++++++---------- .../{MipmapDetails.cpp => MipmapLayout.cpp} | 6 ++--- src/vsg/io/ObjectFactory.cpp | 1 + 11 files changed, 58 insertions(+), 56 deletions(-) rename include/vsg/core/{MipmapDetails.h => MipmapLayout.h} (90%) rename src/vsg/core/{MipmapDetails.cpp => MipmapLayout.cpp} (91%) 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/core/Array.h b/include/vsg/core/Array.h index 12a86a1c75..f31649edf1 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -63,12 +63,12 @@ namespace vsg _data(_allocate(numElements)), _size(numElements) { dirty(); } - Array(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) : + Array(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) : Data(in_properties, sizeof(value_type)), _data(data), _size(numElements) { - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -81,12 +81,12 @@ namespace vsg dirty(); } - Array(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) : + 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, mipmapDetails); + assign(data, offset, stride, numElements, in_properties, mipmapLayout); } explicit Array(std::initializer_list l) : @@ -250,7 +250,7 @@ namespace vsg return *this; } - void assign(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) + void assign(uint32_t numElements, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -260,12 +260,12 @@ namespace vsg _data = data; _storage = nullptr; - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } - void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) + void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t numElements, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -283,7 +283,7 @@ namespace vsg _size = 0; } - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -376,7 +376,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapDetails(); + removeMipmapLayout(); } private: diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index a7030263d0..aa14454b7d 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -68,13 +68,13 @@ namespace vsg dirty(); } - Array2D(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) : + 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) { - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -92,13 +92,13 @@ namespace vsg } } - Array2D(ref_ptr data, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) : + 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, mipmapDetails); + assign(data, offset, stride, width, height, in_properties, mipmapLayout); } template @@ -233,7 +233,7 @@ namespace vsg return *this; } - void assign(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) + void assign(uint32_t width, uint32_t height, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -244,12 +244,12 @@ namespace vsg _data = data; _storage = nullptr; - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } - void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) + void assign(ref_ptr storage, uint32_t offset, uint32_t stride, uint32_t width, uint32_t height, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -269,7 +269,7 @@ namespace vsg _height = 0; } - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -371,7 +371,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapDetails(); + removeMipmapLayout(); } private: diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 9a638e831d..2e2297d728 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -71,14 +71,14 @@ namespace vsg dirty(); } - Array3D(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) : + 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) { - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -97,14 +97,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 = {}, MipmapDetails* mipmapDetails = nullptr) : + 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, mipmapDetails); + assign(data, offset, stride, width, height, depth, in_properties, mipmapLayout); } template @@ -244,7 +244,7 @@ namespace vsg return *this; } - void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}, MipmapDetails* mipmapDetails = nullptr) + void assign(uint32_t width, uint32_t height, uint32_t depth, value_type* data, Properties in_properties = {}, MipmapLayout* mipmapLayout = nullptr) { _delete(); @@ -256,12 +256,12 @@ namespace vsg _data = data; _storage = nullptr; - setMipmapDetails(mipmapDetails); + 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 = {}, MipmapDetails* mipmapDetails = nullptr) + 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(); @@ -283,7 +283,7 @@ namespace vsg _depth = 0; } - setMipmapDetails(mipmapDetails); + setMipmapLayout(mipmapLayout); dirty(); } @@ -387,7 +387,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapDetails(); + removeMipmapLayout(); } private: diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index f7114d08a0..da5e7c6e75 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -24,8 +24,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - // forward declaer MipmapDetails - class MipmapDetails; + // forward declaer MipmapLayout + class MipmapLayout; /// ModifiedCount provides a count value to keep track of modifications to data. struct ModifiedCount @@ -107,7 +107,7 @@ namespace vsg value_type* operator->() { return reinterpret_cast(ptr); } }; - class MipmapDetails; + 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. @@ -217,11 +217,11 @@ namespace vsg /// return true if Data's ModifiedCount is different from the specified ModifiedCount bool differentModifiedCount(const ModifiedCount& mc) const { return _modifiedCount != mc; } - void setMipmapDetails(MipmapDetails* mipmapData); + void setMipmapLayout(MipmapLayout* mipmapData); - const MipmapDetails* getMipmapDetails() const; + const MipmapLayout* getMipmapLayout() const; - void removeMipmapDetails(); + void removeMipmapLayout(); protected: virtual ~Data() {} diff --git a/include/vsg/core/MipmapDetails.h b/include/vsg/core/MipmapLayout.h similarity index 90% rename from include/vsg/core/MipmapDetails.h rename to include/vsg/core/MipmapLayout.h index 3b236b80a7..51e948d580 100644 --- a/include/vsg/core/MipmapDetails.h +++ b/include/vsg/core/MipmapLayout.h @@ -20,13 +20,13 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI namespace vsg { - class VSG_DECLSPEC MipmapDetails : public Inherit + class VSG_DECLSPEC MipmapLayout : public Inherit { public: - MipmapDetails() {} + MipmapLayout() {} - MipmapDetails(std::size_t size) : mipmaps(size) {} + MipmapLayout(std::size_t size) : mipmaps(size) {} using Mipmaps = std::vector; @@ -47,6 +47,6 @@ namespace vsg void read(Input& input) override; void write(Output& output) const override; }; - VSG_type_name(vsg::MipmapDetails); + VSG_type_name(vsg::MipmapLayout); } // namespace vsg diff --git a/src/vsg/CMakeLists.txt b/src/vsg/CMakeLists.txt index 7677e25f02..34ad025dde 100644 --- a/src/vsg/CMakeLists.txt +++ b/src/vsg/CMakeLists.txt @@ -10,7 +10,7 @@ endif() # set up the source files explicitly. set(SOURCES - core/MipmapDetails.cpp + 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 373a3bf511..f18b08bdf8 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -12,7 +12,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include -#include +#include #include #include #include @@ -612,7 +612,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm uint32_t data_mipLevels = static_cast(data->properties.mipLevels); - auto mipmapData = data->getMipmapDetails(); + auto mipmapData = data->getMipmapLayout(); if (mipmapData) { auto& mipmap0 = mipmapData->at(0); diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 5bb5fd045c..c0428fcf92 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -13,7 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include +#include #include #include @@ -118,10 +118,10 @@ std::size_t Data::computeValueCountIncludingMipmaps() const { std::size_t count = 0; - auto mipmapDetails = getObject("mipmapDetails"); - if (mipmapDetails) + auto mipmapLayout = getObject("mipmapLayout"); + if (mipmapLayout) { - for(auto& mipmap : *mipmapDetails) + for(auto& mipmap : *mipmapLayout) { std::size_t w = (mipmap.x+properties.blockWidth-1)/properties.blockWidth; std::size_t h = (mipmap.y+properties.blockHeight-1)/properties.blockHeight; @@ -164,20 +164,20 @@ void Data::_copy(const Data& rhs) } } -void Data::setMipmapDetails(MipmapDetails* mipmapDetails) +void Data::setMipmapLayout(MipmapLayout* mipmapLayout) { - if (mipmapDetails) setObject("mipmapDetails", ref_ptr(mipmapDetails)); - else if (getAuxiliary()) removeObject("mipmapDetails"); + if (mipmapLayout) setObject("mipmapLayout", ref_ptr(mipmapLayout)); + else if (getAuxiliary()) removeObject("mipmapLayout"); } -const MipmapDetails* Data::getMipmapDetails() const +const MipmapLayout* Data::getMipmapLayout() const { - return getObject("mipmapDetails"); + return getObject("mipmapLayout"); } -void Data::removeMipmapDetails() +void Data::removeMipmapLayout() { - if (getAuxiliary()) removeObject("mipmapDetails"); + if (getAuxiliary()) removeObject("mipmapLayout"); } std::tuple Data::pixelExtents() const @@ -186,9 +186,9 @@ std::tuple Data::pixelExtents() const uint32_t h = height() * properties.blockHeight; uint32_t d = depth() * properties.blockDepth; - if (auto mipmapDetails = getMipmapDetails()) + if (auto mipmapLayout = getMipmapLayout()) { - auto mipmap = mipmapDetails->at(0); + auto mipmap = mipmapLayout->at(0); w = mipmap.x; h = mipmap.y; d = mipmap.z; diff --git a/src/vsg/core/MipmapDetails.cpp b/src/vsg/core/MipmapLayout.cpp similarity index 91% rename from src/vsg/core/MipmapDetails.cpp rename to src/vsg/core/MipmapLayout.cpp index 6982b9d6d2..ea834366d6 100644 --- a/src/vsg/core/MipmapDetails.cpp +++ b/src/vsg/core/MipmapLayout.cpp @@ -10,18 +10,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include +#include #include #include using namespace vsg; -void MipmapDetails::read(Input& input) +void MipmapLayout::read(Input& input) { Object::read(input); } -void MipmapDetails::write(Output& output) const +void MipmapLayout::write(Output& output) const { Object::write(output); } diff --git a/src/vsg/io/ObjectFactory.cpp b/src/vsg/io/ObjectFactory.cpp index ecca256913..de69abe5cd 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(); From dc421a7b64321c70f6874fc888c83b91fa16324f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 18 Nov 2025 13:22:08 +0000 Subject: [PATCH 15/25] Refined the MipmapLayout implementation. --- include/vsg/core/MipmapLayout.h | 9 ++-- src/vsg/core/Data.cpp | 78 +++++++++++++++++---------------- src/vsg/core/MipmapLayout.cpp | 17 +++++++ src/vsg/io/ObjectFactory.cpp | 1 + src/vsg/state/ArrayState.cpp | 1 - 5 files changed, 65 insertions(+), 41 deletions(-) diff --git a/include/vsg/core/MipmapLayout.h b/include/vsg/core/MipmapLayout.h index 51e948d580..6ee1349971 100644 --- a/include/vsg/core/MipmapLayout.h +++ b/include/vsg/core/MipmapLayout.h @@ -24,9 +24,9 @@ namespace vsg { public: - MipmapLayout() {} + MipmapLayout(); - MipmapLayout(std::size_t size) : mipmaps(size) {} + explicit MipmapLayout(std::size_t size); using Mipmaps = std::vector; @@ -36,7 +36,7 @@ namespace vsg 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, vsg::uivec4 value) { mipmaps[i] = value; } + void set(size_t i, const vsg::uivec4& value) { mipmaps[i] = value; } Mipmaps::iterator begin() { return mipmaps.begin(); } Mipmaps::iterator end() { return mipmaps.end(); } @@ -46,6 +46,9 @@ namespace vsg void read(Input& input) override; void write(Output& output) const override; + + protected: + virtual ~MipmapLayout(); }; VSG_type_name(vsg::MipmapLayout); diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index c0428fcf92..0ff5d7c604 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -114,42 +114,6 @@ void Data::write(Output& output) const } } -std::size_t Data::computeValueCountIncludingMipmaps() const -{ - std::size_t count = 0; - - auto mipmapLayout = getObject("mipmapLayout"); - if (mipmapLayout) - { - for(auto& mipmap : *mipmapLayout) - { - 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 w = width(); - std::size_t h = height(); - std::size_t d = depth(); - - count = w*h*d; - - for(uint8_t level = 1; level < properties.mipLevels; ++level) - { - if (w > 1) w = w/2; - if (h > 1) h = h/2; - if (d > 1) d = d/2; - - count += w*h*d; - } - } - - return count; -} void Data::_copy(const Data& rhs) { @@ -167,7 +131,7 @@ void Data::_copy(const Data& rhs) void Data::setMipmapLayout(MipmapLayout* mipmapLayout) { if (mipmapLayout) setObject("mipmapLayout", ref_ptr(mipmapLayout)); - else if (getAuxiliary()) removeObject("mipmapLayout"); + else removeMipmapLayout(); } const MipmapLayout* Data::getMipmapLayout() const @@ -180,6 +144,46 @@ void Data::removeMipmapLayout() if (getAuxiliary()) removeObject("mipmapLayout"); } +std::size_t Data::computeValueCountIncludingMipmaps() const +{ + std::size_t count = 0; + + if (auto mipmapLayout = getMipmapLayout()) + { + for(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; + + for(uint8_t level = 0; level < properties.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 count; +} + std::tuple Data::pixelExtents() const { uint32_t w = width() * properties.blockWidth; diff --git a/src/vsg/core/MipmapLayout.cpp b/src/vsg/core/MipmapLayout.cpp index ea834366d6..6ec5783e35 100644 --- a/src/vsg/core/MipmapLayout.cpp +++ b/src/vsg/core/MipmapLayout.cpp @@ -16,12 +16,29 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI using namespace vsg; +MipmapLayout::MipmapLayout() +{ +} + +MipmapLayout::MipmapLayout(std::size_t size) : + mipmaps(size) +{ +} + +MipmapLayout::~MipmapLayout() +{ +} + void MipmapLayout::read(Input& input) { Object::read(input); + + input.read("mipmaps", mipmaps); } void MipmapLayout::write(Output& output) const { Object::write(output); + + output.write("mipmaps", mipmaps); } diff --git a/src/vsg/io/ObjectFactory.cpp b/src/vsg/io/ObjectFactory.cpp index de69abe5cd..0f261bbf06 100644 --- a/src/vsg/io/ObjectFactory.cpp +++ b/src/vsg/io/ObjectFactory.cpp @@ -354,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/ArrayState.cpp b/src/vsg/state/ArrayState.cpp index f5856f3735..1a08fe9dba 100644 --- a/src/vsg/state/ArrayState.cpp +++ b/src/vsg/state/ArrayState.cpp @@ -27,7 +27,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include using namespace vsg; From 45a813758b183d0a0d16844b81967ec4f31b69cb Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 18 Nov 2025 15:47:54 +0000 Subject: [PATCH 16/25] Fixed reading/writing of mipmaps --- include/vsg/core/Array.h | 1 - include/vsg/core/Array2D.h | 1 - include/vsg/core/Array3D.h | 1 - include/vsg/core/Value.h | 5 +---- src/vsg/core/Data.cpp | 6 ++++-- src/vsg/core/MipmapLayout.cpp | 4 ++-- 6 files changed, 7 insertions(+), 11 deletions(-) diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index f31649edf1..cca9cdcc92 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -12,7 +12,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include #include #include diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index aa14454b7d..a479875449 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -12,7 +12,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include #include #include #include diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 2e2297d728..5747c044d6 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -12,7 +12,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include #include #include diff --git a/include/vsg/core/Value.h b/include/vsg/core/Value.h index 71440ad6ac..de9481981e 100644 --- a/include/vsg/core/Value.h +++ b/include/vsg/core/Value.h @@ -144,10 +144,7 @@ namespace vsg { _value = rhs._value; - if (getAuxiliary()) - { - getOrCreateAuxiliary()->userObjects = getAuxiliary()->userObjects; - } + _copy(rhs); return *this; } diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 0ff5d7c604..e1c010c85c 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -16,6 +16,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include using namespace vsg; @@ -166,14 +167,15 @@ std::size_t Data::computeValueCountIncludingMipmaps() const std::size_t y = height() * properties.blockHeight; std::size_t z = depth() * properties.blockDepth; - for(uint8_t level = 0; level < properties.mipLevels; ++level) + 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; + count += w*h*d; if (x > 1) x = x/2; if (y > 1) y = y/2; diff --git a/src/vsg/core/MipmapLayout.cpp b/src/vsg/core/MipmapLayout.cpp index 6ec5783e35..cbfbfefe09 100644 --- a/src/vsg/core/MipmapLayout.cpp +++ b/src/vsg/core/MipmapLayout.cpp @@ -33,12 +33,12 @@ void MipmapLayout::read(Input& input) { Object::read(input); - input.read("mipmaps", mipmaps); + input.readValues("mipmaps", mipmaps); } void MipmapLayout::write(Output& output) const { Object::write(output); - output.write("mipmaps", mipmaps); + output.writeValues("mipmaps", mipmaps); } From 1787f5594a8aee6d5389f64484f31dc9589fa615 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 18 Nov 2025 16:35:27 +0000 Subject: [PATCH 17/25] Added MipmapLayout to Visitor and ConstVisitor --- include/vsg/core/ConstVisitor.h | 2 ++ include/vsg/core/Visitor.h | 2 ++ src/vsg/core/ConstVisitor.cpp | 5 +++++ src/vsg/core/Visitor.cpp | 5 +++++ 4 files changed, 14 insertions(+) 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/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/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/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 From cade7d452beb34e53c30b3d0b033d254dc0787b2 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 18 Nov 2025 17:58:52 +0000 Subject: [PATCH 18/25] Ran clang-format. --- include/vsg/app/RecordTraversal.h | 1 - include/vsg/core/Array.h | 2 - include/vsg/core/Array2D.h | 1 - include/vsg/core/Array3D.h | 1 - include/vsg/core/MipmapLayout.h | 1 - include/vsg/state/ShaderModule.h | 1 - src/vsg/app/TransferTask.cpp | 6 +- src/vsg/app/WindowTraits.cpp | 9 +- src/vsg/core/Data.cpp | 37 +++---- src/vsg/state/ImageInfo.cpp | 159 +++++++++++++++--------------- src/vsg/state/ShaderModule.cpp | 4 +- src/vsg/state/ShaderStage.cpp | 2 +- 12 files changed, 108 insertions(+), 116 deletions(-) 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/core/Array.h b/include/vsg/core/Array.h index cca9cdcc92..4d30475986 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -187,7 +187,6 @@ namespace vsg _data = _allocate(new_total_size); } - if (_data) input.read(new_total_size, _data); dirty(); @@ -243,7 +242,6 @@ namespace vsg for (const auto& v : rhs) *(dest_v++) = v; } - dirty(); return *this; diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index a479875449..44fca1cb4e 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -167,7 +167,6 @@ namespace vsg _data = _allocate(new_size); } - if (_data) input.read(new_size, _data); dirty(); diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 5747c044d6..79b914ec39 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -175,7 +175,6 @@ namespace vsg _data = _allocate(new_size); } - if (_data) input.read(new_size, _data); dirty(); diff --git a/include/vsg/core/MipmapLayout.h b/include/vsg/core/MipmapLayout.h index 6ee1349971..968114255f 100644 --- a/include/vsg/core/MipmapLayout.h +++ b/include/vsg/core/MipmapLayout.h @@ -23,7 +23,6 @@ namespace vsg class VSG_DECLSPEC MipmapLayout : public Inherit { public: - MipmapLayout(); explicit MipmapLayout(std::size_t size); 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/src/vsg/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index f18b08bdf8..3633e78b82 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -786,9 +786,9 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm 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; + 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}; 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/core/Data.cpp b/src/vsg/core/Data.cpp index e1c010c85c..aa9c39f1fe 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -11,12 +11,12 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include -#include #include +#include #include #include -#include #include +#include using namespace vsg; @@ -115,7 +115,6 @@ void Data::write(Output& output) const } } - void Data::_copy(const Data& rhs) { properties = rhs.properties; @@ -131,8 +130,10 @@ void Data::_copy(const Data& rhs) void Data::setMipmapLayout(MipmapLayout* mipmapLayout) { - if (mipmapLayout) setObject("mipmapLayout", ref_ptr(mipmapLayout)); - else removeMipmapLayout(); + if (mipmapLayout) + setObject("mipmapLayout", ref_ptr(mipmapLayout)); + else + removeMipmapLayout(); } const MipmapLayout* Data::getMipmapLayout() const @@ -151,14 +152,14 @@ std::size_t Data::computeValueCountIncludingMipmaps() const if (auto mipmapLayout = getMipmapLayout()) { - for(auto& mipmap : *mipmapLayout) + for (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; + 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; + count += w * h * d; } } else @@ -168,18 +169,18 @@ std::size_t Data::computeValueCountIncludingMipmaps() const std::size_t z = depth() * properties.blockDepth; auto mipLevels = std::max(properties.mipLevels, uint8_t(1)); - for(uint8_t level = 0; level < mipLevels; ++level) + 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; + 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; + count += w * h * d; - if (x > 1) x = x/2; - if (y > 1) y = y/2; - if (z > 1) z = z/2; + if (x > 1) x = x / 2; + if (y > 1) y = y / 2; + if (z > 1) z = z / 2; } } diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index eb38bff8a4..a87d76aca4 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -209,7 +209,7 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) 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)) + (VK_FORMAT_EAC_R11_UNORM_BLOCK <= format && format <= VK_FORMAT_EAC_R11_SNORM_BLOCK)) { traits.packed = true; traits.blockWidth = 4; @@ -238,83 +238,83 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one) traits.numComponents = 1; traits.size = 16; - switch(format) + 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; + 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 @@ -350,7 +350,6 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) } bool generateMipmaps = (mipLevels > 1) && (data->properties.mipLevels <= 1); - if (generateMipmaps) { // check that the data isn't compressed. @@ -369,11 +368,11 @@ uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler) { if (data->properties.mipLevels < mipLevels) { - mipLevels = data->properties.mipLevels; + mipLevels = std::max(1u, static_cast(data->properties.mipLevels)); } } - // vsg::info("computeNumMipMapLevels(", sampler->maxLod, ", data->mipmapOffsets.size() = ", mipmapOffsets.size(), ", mipLevels = ", mipLevels); + // vsg::info("vsg::computeNumMipMapLevels(data = ", data, ", sampler->maxLod = ", sampler->maxLod, ", data->properties.mipLevels = ", int(data->properties.mipLevels), ", mipLevels = ", mipLevels); } //mipLevels = 1; // disable mipmapping 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), From 663f5068f20e823a04b0b80895c119e4a5a6b970 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 09:09:16 +0000 Subject: [PATCH 19/25] cppcheck fixes --- include/vsg/vk/State.h | 2 +- src/vsg/app/TransferTask.cpp | 2 +- src/vsg/core/Data.cpp | 2 +- src/vsg/io/JSONParser.cpp | 4 ---- src/vsg/state/ImageInfo.cpp | 2 +- src/vsg/vk/State.cpp | 2 +- 6 files changed, 5 insertions(+), 9 deletions(-) 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/app/TransferTask.cpp b/src/vsg/app/TransferTask.cpp index 3633e78b82..a0805b7735 100644 --- a/src/vsg/app/TransferTask.cpp +++ b/src/vsg/app/TransferTask.cpp @@ -615,7 +615,7 @@ void vsg::transferImageData(ref_ptr imageView, VkImageLayout targetIm auto mipmapData = data->getMipmapLayout(); if (mipmapData) { - auto& mipmap0 = mipmapData->at(0); + const auto& mipmap0 = mipmapData->at(0); destWidth = mipmap0.x; destHeight = mipmap0.y; destDepth = mipmap0.z; diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index aa9c39f1fe..91682544ef 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -152,7 +152,7 @@ std::size_t Data::computeValueCountIncludingMipmaps() const if (auto mipmapLayout = getMipmapLayout()) { - for (auto& mipmap : *mipmapLayout) + for (const auto& mipmap : *mipmapLayout) { // round to block size std::size_t w = (mipmap.x + properties.blockWidth - 1) / properties.blockWidth; 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/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index a87d76aca4..2859ed950a 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -408,7 +408,7 @@ void ImageInfo::computeNumMipMapLevels() if (imageView && imageView->image && imageView->image->data) { auto& image = imageView->image; - auto& data = image->data; + 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/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); From 58d3fa73f6ef2c68e3bf098681226cc3d68e765f Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 09:11:31 +0000 Subject: [PATCH 20/25] Bumped version for vsg::Data mipmap changes --- CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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) From 68ecba1dca664a3202396b5bfb171c5cef3e8664 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 09:45:41 +0000 Subject: [PATCH 21/25] Refactored the clean up of MipmapLayout etc. --- include/vsg/core/Array.h | 2 +- include/vsg/core/Array2D.h | 2 +- include/vsg/core/Array3D.h | 2 +- include/vsg/core/Auxiliary.h | 13 ++++++++++--- include/vsg/core/Data.h | 5 +++-- src/vsg/core/Data.cpp | 13 ++++++------- 6 files changed, 22 insertions(+), 15 deletions(-) diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index 4d30475986..f83433c00a 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -373,7 +373,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapLayout(); + Data::_delete(); } private: diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index 44fca1cb4e..6cdfd48d3c 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -369,7 +369,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapLayout(); + Data::_delete(); } private: diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index 79b914ec39..ddf8f57059 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -385,7 +385,7 @@ namespace vsg vsg::deallocate(_data); } - removeMipmapLayout(); + Data::_delete(); } private: diff --git a/include/vsg/core/Auxiliary.h b/include/vsg/core/Auxiliary.h index 01cc86408f..91b3d295ee 100644 --- a/include/vsg/core/Auxiliary.h +++ b/include/vsg/core/Auxiliary.h @@ -39,6 +39,12 @@ 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 +82,11 @@ namespace vsg return {}; } - using ObjectMap = std::map>; + void clear() + { + userObjects.clear(); + } - /// container for all user objects - ObjectMap userObjects; protected: explicit Auxiliary(Object* object); diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index da5e7c6e75..25ce0d9af7 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -217,16 +217,17 @@ 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; - void removeMipmapLayout(); - protected: virtual ~Data() {} void _copy(const Data& rhs); + void _delete(); ModifiedCount _modifiedCount; diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index 91682544ef..f874b141f3 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -128,12 +128,16 @@ void Data::_copy(const Data& rhs) } } +void Data::_delete() +{ + if (getAuxiliary()) getAuxiliary()->clear(); +} + void Data::setMipmapLayout(MipmapLayout* mipmapLayout) { if (mipmapLayout) setObject("mipmapLayout", ref_ptr(mipmapLayout)); - else - removeMipmapLayout(); + else if (getAuxiliary()) removeObject("mipmapLayout"); } const MipmapLayout* Data::getMipmapLayout() const @@ -141,11 +145,6 @@ const MipmapLayout* Data::getMipmapLayout() const return getObject("mipmapLayout"); } -void Data::removeMipmapLayout() -{ - if (getAuxiliary()) removeObject("mipmapLayout"); -} - std::size_t Data::computeValueCountIncludingMipmaps() const { std::size_t count = 0; From bb05babc5a3fda8b886340b90844028bc8a1bc61 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 10:05:30 +0000 Subject: [PATCH 22/25] Refactored how Auxiliary is cleared by Data subclasses --- include/vsg/core/Array.h | 2 +- include/vsg/core/Array2D.h | 2 +- include/vsg/core/Array3D.h | 2 +- include/vsg/core/Data.h | 2 +- src/vsg/core/Data.cpp | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/include/vsg/core/Array.h b/include/vsg/core/Array.h index f83433c00a..5d6420760a 100644 --- a/include/vsg/core/Array.h +++ b/include/vsg/core/Array.h @@ -373,7 +373,7 @@ namespace vsg vsg::deallocate(_data); } - Data::_delete(); + _clear(); } private: diff --git a/include/vsg/core/Array2D.h b/include/vsg/core/Array2D.h index 6cdfd48d3c..ee19e4405c 100644 --- a/include/vsg/core/Array2D.h +++ b/include/vsg/core/Array2D.h @@ -369,7 +369,7 @@ namespace vsg vsg::deallocate(_data); } - Data::_delete(); + _clear(); } private: diff --git a/include/vsg/core/Array3D.h b/include/vsg/core/Array3D.h index ddf8f57059..08efd30c15 100644 --- a/include/vsg/core/Array3D.h +++ b/include/vsg/core/Array3D.h @@ -385,7 +385,7 @@ namespace vsg vsg::deallocate(_data); } - Data::_delete(); + _clear(); } private: diff --git a/include/vsg/core/Data.h b/include/vsg/core/Data.h index 25ce0d9af7..aa3dc6db7c 100644 --- a/include/vsg/core/Data.h +++ b/include/vsg/core/Data.h @@ -227,7 +227,7 @@ namespace vsg virtual ~Data() {} void _copy(const Data& rhs); - void _delete(); + void _clear(); ModifiedCount _modifiedCount; diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index f874b141f3..adbd62aad0 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -128,7 +128,7 @@ void Data::_copy(const Data& rhs) } } -void Data::_delete() +void Data::_clear() { if (getAuxiliary()) getAuxiliary()->clear(); } From 4f331a310ee280bcbe3ac7d3c1400f4f493056a5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 12:44:36 +0000 Subject: [PATCH 23/25] Cleaned up includes and indentation --- include/vsg/core/Value.h | 1 - src/vsg/core/Data.cpp | 6 +++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/include/vsg/core/Value.h b/include/vsg/core/Value.h index de9481981e..5a6e3c24a6 100644 --- a/include/vsg/core/Value.h +++ b/include/vsg/core/Value.h @@ -12,7 +12,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ -#include #include #include diff --git a/src/vsg/core/Data.cpp b/src/vsg/core/Data.cpp index adbd62aad0..cab03faaae 100644 --- a/src/vsg/core/Data.cpp +++ b/src/vsg/core/Data.cpp @@ -11,11 +11,10 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI */ #include -#include +#include #include #include #include -#include #include using namespace vsg; @@ -137,7 +136,8 @@ void Data::setMipmapLayout(MipmapLayout* mipmapLayout) { if (mipmapLayout) setObject("mipmapLayout", ref_ptr(mipmapLayout)); - else if (getAuxiliary()) removeObject("mipmapLayout"); + else if (getAuxiliary()) + removeObject("mipmapLayout"); } const MipmapLayout* Data::getMipmapLayout() const From 8760deff37316b6453cf1577721da6d147af39d8 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 12:44:56 +0000 Subject: [PATCH 24/25] Ran clang-format --- include/vsg/core/Auxiliary.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/vsg/core/Auxiliary.h b/include/vsg/core/Auxiliary.h index 91b3d295ee..e57cdbbfbf 100644 --- a/include/vsg/core/Auxiliary.h +++ b/include/vsg/core/Auxiliary.h @@ -44,7 +44,6 @@ namespace vsg /// container for all user objects ObjectMap userObjects; - void setObject(const std::string& key, ref_ptr object) { userObjects[key] = object; @@ -87,7 +86,6 @@ namespace vsg userObjects.clear(); } - protected: explicit Auxiliary(Object* object); From 57f3ac524982cd7eb7d0013db29bc6cc24a2a030 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Wed, 19 Nov 2025 13:47:56 +0000 Subject: [PATCH 25/25] Fixed cppcheck issue and removed debug output --- src/vsg/state/ImageInfo.cpp | 2 +- src/vsg/utils/Builder.cpp | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/vsg/state/ImageInfo.cpp b/src/vsg/state/ImageInfo.cpp index 2859ed950a..144edc9f94 100644 --- a/src/vsg/state/ImageInfo.cpp +++ b/src/vsg/state/ImageInfo.cpp @@ -407,7 +407,7 @@ void ImageInfo::computeNumMipMapLevels() { if (imageView && imageView->image && imageView->image->data) { - auto& image = imageView->image; + 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); diff --git a/src/vsg/utils/Builder.cpp b/src/vsg/utils/Builder.cpp index e4f0ec3ded..59eaf5fbec 100644 --- a/src/vsg/utils/Builder.cpp +++ b/src/vsg/utils/Builder.cpp @@ -67,9 +67,6 @@ ref_ptr Builder::createStateGroup(const StateInfo& stateInfo) sampler->maxLod = static_cast(stateInfo.image->properties.mipLevels); - vsg::info("Builder stateInfo.image = ", stateInfo.image, ", width = ", stateInfo.image->width(), ", height = ", stateInfo.image->height(), - ", mipLevels = ", int(stateInfo.image->properties.mipLevels)); - if (sharedObjects) sharedObjects->share(sampler); graphicsPipelineConfig->assignTexture("diffuseMap", stateInfo.image, sampler);