Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[FIXED] valueCount for array mipmaps read from vsg::Data #955

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion include/vsg/commands/CopyAndReleaseImage.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
};
Expand Down
7 changes: 5 additions & 2 deletions include/vsg/core/Data.h
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,11 @@ namespace vsg
uint32_t stride() const { return properties.stride ? properties.stride : static_cast<uint32_t>(valueSize()); }

using MipmapOffsets = std::vector<size_t>;
MipmapOffsets computeMipmapOffsets() const;
static size_t computeValueCountIncludingMipmaps(size_t w, size_t h, size_t d, uint32_t maxNumMipmaps);
// Note, computeMipmapOffsets will naively interpret the data dimensions as the image dimensions
// and return incorrect values for layered images.
MipmapOffsets computeMipmapOffsets() const; // deprecated
static size_t computeValueCountIncludingMipmaps(size_t w, size_t h, size_t d, uint32_t maxNumMipmaps); // deprecated
static size_t computeValueCountIncludingMipmaps(size_t w, size_t h, size_t d, uint32_t maxNumMipmaps, uint32_t arrayLayers);

/// increment the ModifiedCount to signify the data has been modified
void dirty() { ++_modifiedCount; }
Expand Down
14 changes: 13 additions & 1 deletion include/vsg/state/ImageInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,18 @@ namespace vsg
extern VSG_DECLSPEC FormatTraits getFormatTraits(VkFormat format, bool default_one = true);

/// return the number of mip map levels specified by Data/Sampler.
extern VSG_DECLSPEC uint32_t computeNumMipMapLevels(const Data* data, const Sampler* sampler);
extern VSG_DECLSPEC uint32_t computeNumMipMapLevels(const Data* data, const Sampler* sampler); // deprecated
extern VSG_DECLSPEC uint32_t computeNumMipMapLevels(uint32_t w, uint32_t h, uint32_t d, const Sampler* sampler);
/// return the size of a full mipmap chain for dimensions.
/// equivalent to: log2(max(w,h,d))+1
/// See Vulkan spec 12.3.2 "Image Miplevel Sizing"
extern VSG_DECLSPEC uint32_t computeNumMipMapLevels(uint32_t w, uint32_t h, uint32_t d);

/// return the number of mipLevels that can be read from vsg::Data for this vsg::Image.
extern VSG_DECLSPEC uint32_t computeNumMipMapLevels(const vsg::Data::Properties& properties, const Image* image);

/// return the number of Data values required for Image including mipmaps
/// Note, Data::valueCount() doesn't support layers correctly
extern VSG_DECLSPEC size_t computeValueCount(const vsg::Data::Properties& properties, const Image* image);

} // namespace vsg
2 changes: 1 addition & 1 deletion include/vsg/state/ImageView.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,6 @@ namespace vsg
extern VSG_DECLSPEC ref_ptr<ImageView> createImageView(Device* device, ref_ptr<Image> image, VkImageAspectFlags aspectFlags);

/// convenience function that uploads staging buffer data to device including mipmaps.
extern VSG_DECLSPEC void transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, const Data::MipmapOffsets& mipmapOffsets, ref_ptr<Buffer> stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device);
extern VSG_DECLSPEC void transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetImageLayout, const Data::Properties& properties, uint32_t width, uint32_t height, uint32_t depth, ref_ptr<Buffer> stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer vk_commandBuffer, vsg::Device* device);

} // namespace vsg
25 changes: 13 additions & 12 deletions src/vsg/app/TransferTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ void TransferTask::assign(const ImageInfoList& imageInfoList)

VkFormat targetFormat = imageInfo->imageView->format;
auto targetTraits = getFormatTraits(targetFormat);
VkDeviceSize imageTotalSize = targetTraits.size * data->valueCount();
auto valueCount = vsg::computeValueCount(data->properties, imageInfo->imageView->image);
VkDeviceSize imageTotalSize = targetTraits.size * valueCount;

VkDeviceSize endOfEntry = offset + imageTotalSize;
offset = (/*alignment == 1 ||*/ (endOfEntry % alignment) == 0) ? endOfEntry : ((endOfEntry / alignment) + 1) * alignment;
Expand Down Expand Up @@ -254,21 +255,22 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f
auto width = data->width();
auto height = data->height();
auto depth = data->depth();
auto mipmapOffsets = data->computeMipmapOffsets();
uint32_t mipLevels = vsg::computeNumMipMapLevels(data, imageInfo.sampler);

auto source_offset = offset;

log(level, "ImageInfo needs copying ", data, ", mipLevels = ", mipLevels);
log(level, "ImageInfo needs copying ", data, ", image->mipLevels = ", imageInfo.imageView->image->mipLevels);

// copy data.
VkFormat sourceFormat = data->properties.format;
VkFormat targetFormat = imageInfo.imageView->format;
//auto dataSize = data->dataSize();
auto valueCount = vsg::computeValueCount(data->properties, imageInfo.imageView->image);
auto dataSize = valueCount * data->properties.stride;
if (sourceFormat == targetFormat)
{
log(level, " sourceFormat and targetFormat compatible.");
std::memcpy(ptr, data->dataPointer(), data->dataSize());
offset += data->dataSize();
std::memcpy(ptr, data->dataPointer(), dataSize);
offset += dataSize;
}
else
{
Expand All @@ -277,17 +279,17 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f
if (sourceTraits.size == targetTraits.size)
{
log(level, " sourceTraits.size and targetTraits.size compatible.");
std::memcpy(ptr, data->dataPointer(), data->dataSize());
offset += data->dataSize();
std::memcpy(ptr, data->dataPointer(), dataSize);
offset += dataSize;
}
else
{
VkDeviceSize imageTotalSize = targetTraits.size * data->valueCount();
VkDeviceSize imageTotalSize = targetTraits.size * valueCount;

properties.format = targetFormat;
properties.stride = targetTraits.size;

log(level, " sourceTraits.size and targetTraits.size not compatible. dataSize() = ", data->dataSize(), ", imageTotalSize = ", imageTotalSize);
log(level, " sourceTraits.size and targetTraits.size not compatible. dataSize = ", dataSize, ", imageTotalSize = ", imageTotalSize);

// set up a vec4 worth of default values for the type
const uint8_t* default_ptr = targetTraits.defaultValue;
Expand All @@ -302,7 +304,6 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f

value_type* dest_ptr = reinterpret_cast<value_type*>(ptr);

size_t valueCount = data->valueCount();
for (size_t i = 0; i < valueCount; ++i)
{
uint32_t s = 0;
Expand All @@ -321,7 +322,7 @@ void TransferTask::_transferImageInfo(VkCommandBuffer vk_commandBuffer, Frame& f
}

// 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, imageStagingBuffer, source_offset, vk_commandBuffer, device);
}

VkResult TransferTask::transferDynamicData()
Expand Down
17 changes: 10 additions & 7 deletions src/vsg/commands/CopyAndReleaseImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ CopyAndReleaseImage::CopyData::CopyData(ref_ptr<BufferInfo> src, ref_ptr<ImageIn
width = source->data->width();
height = source->data->height();
depth = source->data->depth();
mipmapOffsets = source->data->computeMipmapOffsets();
}
}

Expand All @@ -50,7 +49,8 @@ void CopyAndReleaseImage::add(const CopyData& cd)

void CopyAndReleaseImage::add(ref_ptr<BufferInfo> src, ref_ptr<ImageInfo> dest)
{
add(CopyData(src, dest, vsg::computeNumMipMapLevels(src->data, dest->sampler)));
uint32_t dataMipLevels = computeNumMipMapLevels(src->data->properties, dest->imageView->image);
add(CopyData(src, dest, dataMipLevels));
}

void CopyAndReleaseImage::add(ref_ptr<BufferInfo> src, ref_ptr<ImageInfo> dest, uint32_t numMipMapLevels)
Expand All @@ -60,7 +60,8 @@ void CopyAndReleaseImage::add(ref_ptr<BufferInfo> src, ref_ptr<ImageInfo> dest,

void CopyAndReleaseImage::copy(ref_ptr<Data> data, ref_ptr<ImageInfo> dest)
{
copy(data, dest, vsg::computeNumMipMapLevels(data, dest->sampler));
uint32_t dataMipLevels = computeNumMipMapLevels(data->properties, dest->imageView->image);
copy(data, dest, dataMipLevels);
}

void CopyAndReleaseImage::copy(ref_ptr<Data> data, ref_ptr<ImageInfo> dest, uint32_t numMipMapLevels)
Expand Down Expand Up @@ -90,7 +91,9 @@ void CopyAndReleaseImage::copy(ref_ptr<Data> data, ref_ptr<ImageInfo> dest, uint
{
VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;

VkDeviceSize imageTotalSize = targetTraits.size * data->valueCount();
//VkDeviceSize imageTotalSize = targetTraits.size * data->valueCount();
size_t valueCount = vsg::computeValueCount(data->properties, dest->imageView->image);
VkDeviceSize imageTotalSize = targetTraits.size * valueCount;
VkDeviceSize alignment = std::max(VkDeviceSize(4), VkDeviceSize(targetTraits.size));

auto stagingBufferInfo = stagingMemoryBufferPools->reserveBuffer(imageTotalSize, alignment, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VK_SHARING_MODE_EXCLUSIVE, memoryPropertyFlags);
Expand Down Expand Up @@ -121,7 +124,6 @@ void CopyAndReleaseImage::copy(ref_ptr<Data> data, ref_ptr<ImageInfo> dest, uint
imageStagingMemory->map(imageStagingBuffer->getMemoryOffset(deviceID) + stagingBufferInfo->offset, imageTotalSize, 0, &buffer_data);
value_type* dest_ptr = reinterpret_cast<value_type*>(buffer_data);

size_t valueCount = data->valueCount();
for (size_t i = 0; i < valueCount; ++i)
{
uint32_t s = 0;
Expand All @@ -145,7 +147,8 @@ void CopyAndReleaseImage::copy(ref_ptr<Data> data, ref_ptr<ImageInfo> dest, uint

void CopyAndReleaseImage::_copyDirectly(ref_ptr<Data> data, ref_ptr<ImageInfo> dest, uint32_t numMipMapLevels)
{
VkDeviceSize imageTotalSize = data->dataSize();
size_t valueCount = vsg::computeValueCount(data->properties, dest->imageView->image);
VkDeviceSize imageTotalSize = data->properties.stride * valueCount;
VkDeviceSize alignment = std::max(VkDeviceSize(4), VkDeviceSize(data->valueSize()));

VkMemoryPropertyFlags memoryPropertyFlags = VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT;
Expand All @@ -166,7 +169,7 @@ void CopyAndReleaseImage::_copyDirectly(ref_ptr<Data> data, ref_ptr<ImageInfo> 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, source->buffer, source->offset, commandBuffer.vk(), commandBuffer.getDevice());
}

void CopyAndReleaseImage::record(CommandBuffer& commandBuffer) const
Expand Down
11 changes: 8 additions & 3 deletions src/vsg/core/Data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,9 +143,14 @@ Data::MipmapOffsets Data::computeMipmapOffsets() const

std::size_t Data::computeValueCountIncludingMipmaps(std::size_t w, std::size_t h, std::size_t d, uint32_t numMipmaps)
{
if (numMipmaps <= 1) return w * h * d;
return computeValueCountIncludingMipmaps(w, h, d, numMipmaps, 1);
}

std::size_t Data::computeValueCountIncludingMipmaps(std::size_t w, std::size_t h, std::size_t d, uint32_t numMipmaps, uint32_t arrayLayers)
{
if (numMipmaps <= 1) return w * h * d * arrayLayers;

std::size_t lastPosition = (w * h * d);
std::size_t lastPosition = (w * h * d * arrayLayers);
while (numMipmaps > 1 && (w > 1 || h > 1 || d > 1))
{
--numMipmaps;
Expand All @@ -154,7 +159,7 @@ std::size_t Data::computeValueCountIncludingMipmaps(std::size_t w, std::size_t h
if (h > 1) h /= 2;
if (d > 1) d /= 2;

lastPosition += (w * h * d);
lastPosition += (w * h * d * arrayLayers);
}

return lastPosition;
Expand Down
2 changes: 1 addition & 1 deletion src/vsg/state/DescriptorImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ void DescriptorImage::compile(Context& context)
if (imageView.image && imageView.image->syncModifiedCount(context.deviceID))
{
auto& image = *imageView.image;
context.copy(image.data, imageInfo, image.mipLevels);
context.copy(image.data, imageInfo);
}
}
}
Expand Down
76 changes: 58 additions & 18 deletions src/vsg/state/ImageInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,26 +93,19 @@ FormatTraits vsg::getFormatTraits(VkFormat format, bool default_one)
}

uint32_t vsg::computeNumMipMapLevels(const Data* data, const Sampler* sampler)
{
return computeNumMipMapLevels(data->width(), data->height(), data->depth(), sampler);
}

uint32_t vsg::computeNumMipMapLevels(uint32_t w, uint32_t h, uint32_t d, const Sampler* sampler)
{
uint32_t mipLevels = 1;
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()});
if (sampler->maxLod == VK_LOD_CLAMP_NONE)
{
while ((1u << mipLevels) <= maxDimension)
{
++mipLevels;
}
}
else if (static_cast<uint32_t>(sampler->maxLod) > 1)
mipLevels = vsg::computeNumMipMapLevels(w, h, d);
if (sampler->maxLod != VK_LOD_CLAMP_NONE)
{
mipLevels = static_cast<uint32_t>(sampler->maxLod);
while ((1u << (mipLevels - 1)) > maxDimension)
{
--mipLevels;
}
mipLevels = std::max(1u, std::min(static_cast<uint32_t>(sampler->maxLod), mipLevels));
}
}

Expand Down Expand Up @@ -150,10 +143,17 @@ void ImageInfo::computeNumMipMapLevels()
{
auto image = imageView->image;
auto data = image->data;
auto mipLevels = vsg::computeNumMipMapLevels(data, sampler);
uint32_t mipLevels = vsg::computeNumMipMapLevels(image->extent.width / data->properties.blockWidth, image->extent.height / data->properties.blockHeight, image->extent.depth / data->properties.blockDepth, sampler);

const auto& mipmapOffsets = image->data->computeMipmapOffsets();
bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1);
bool generateMipmaps = false;
if (data->properties.maxNumMipmaps <= 1 && mipLevels > 1)
{
generateMipmaps = true;
}
else
{
mipLevels = vsg::computeNumMipMapLevels(data->properties, image);
}

if (generateMipmaps)
{
Expand All @@ -167,6 +167,7 @@ void ImageInfo::computeNumMipMapLevels()
}

mipLevels = 1;
generateMipmaps = false;
}
}

Expand All @@ -175,3 +176,42 @@ void ImageInfo::computeNumMipMapLevels()
if (generateMipmaps) image->usage |= VK_IMAGE_USAGE_TRANSFER_SRC_BIT;
}
}

uint32_t vsg::computeNumMipMapLevels(uint32_t w, uint32_t h, uint32_t d)
{
// clamp the mipLevels so that it's no larger than what the data dimensions support
uint32_t maxDimension = std::max({w, h, d});
uint32_t mipLevels = 1;
while ((1u << mipLevels) <= maxDimension)
{
++mipLevels;
}
return mipLevels;
}

uint32_t vsg::computeNumMipMapLevels(const vsg::Data::Properties& properties, const Image* image)
{
// get the dimensions, usually equivalent to Data::width/height/depth() except for layered images
uint32_t w = image->extent.width / properties.blockWidth;
uint32_t h = image->extent.height / properties.blockHeight;
uint32_t d = image->extent.depth / properties.blockDepth;
// clamp the mipLevels so that it's no larger than what the data dimensions support
uint32_t mipLevels = vsg::computeNumMipMapLevels(w, h, d);

// clamp the mipLevels so that it's no larger than specified by vsg::Data
mipLevels = std::min(std::max(1u, static_cast<uint32_t>(properties.maxNumMipmaps)), mipLevels);

// clamp the mipLevels so that it's no larger than the mipLevels vsg::Image was compiled with
if (image->mipLevels > 0)
mipLevels = std::min(image->mipLevels, mipLevels);
return mipLevels;
}

size_t vsg::computeValueCount(const vsg::Data::Properties& properties, const vsg::Image* image)
{
uint32_t w = image->extent.width / properties.blockWidth;
uint32_t h = image->extent.height / properties.blockHeight;
uint32_t d = image->extent.depth / properties.blockDepth;
uint32_t mipLevels = vsg::computeNumMipMapLevels(properties, image);
return Data::computeValueCountIncludingMipmaps(w, h, d, mipLevels, image->arrayLayers);
}
7 changes: 4 additions & 3 deletions src/vsg/state/ImageView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ ref_ptr<ImageView> vsg::createImageView(Device* device, ref_ptr<Image> image, Vk
return imageView;
}

void vsg::transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetImageLayout, Data::Properties properties, uint32_t width, uint32_t height, uint32_t depth, uint32_t mipLevels, const Data::MipmapOffsets& mipmapOffsets, ref_ptr<Buffer> stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device)
void vsg::transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetImageLayout, const Data::Properties& properties, uint32_t width, uint32_t height, uint32_t depth, ref_ptr<Buffer> stagingBuffer, VkDeviceSize stagingBufferOffset, VkCommandBuffer commandBuffer, vsg::Device* device)
{
ref_ptr<Image> textureImage(imageView->image);
auto aspectMask = imageView->subresourceRange.aspectMask;
Expand Down Expand Up @@ -240,8 +240,9 @@ void vsg::transferImageData(ref_ptr<ImageView> imageView, VkImageLayout targetIm

const auto valueSize = properties.stride; // data->valueSize();

bool useDataMipmaps = (mipLevels > 1) && (mipmapOffsets.size() > 1);
bool generateMipmaps = (mipLevels > 1) && (mipmapOffsets.size() <= 1);
uint32_t mipLevels = imageView->image->mipLevels;
bool useDataMipmaps = (mipLevels > 1) && (properties.maxNumMipmaps > 1);
bool generateMipmaps = (mipLevels > 1) && (properties.maxNumMipmaps <= 1);

auto vk_textureImage = textureImage->vk(device->deviceID);

Expand Down
Loading