Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 1 | // Copyright 2018 The SwiftShader Authors. All Rights Reserved. |
| 2 | // |
| 3 | // Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | // you may not use this file except in compliance with the License. |
| 5 | // You may obtain a copy of the License at |
| 6 | // |
| 7 | // http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | // |
| 9 | // Unless required by applicable law or agreed to in writing, software |
| 10 | // distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | // See the License for the specific language governing permissions and |
| 13 | // limitations under the License. |
| 14 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 15 | #include "VkImage.hpp" |
Nicolas Capens | a4347a9 | 2020-03-01 08:29:25 -0500 | [diff] [blame] | 16 | |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 17 | #include "VkBuffer.hpp" |
Alexis Hetu | 0da99f5 | 2019-02-27 12:54:52 -0500 | [diff] [blame] | 18 | #include "VkDevice.hpp" |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 19 | #include "VkDeviceMemory.hpp" |
Nicolas Capens | 51b2800 | 2020-01-30 16:41:00 -0500 | [diff] [blame] | 20 | #include "Device/ASTC_Decoder.hpp" |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 21 | #include "Device/BC_Decoder.hpp" |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 22 | #include "Device/Blitter.hpp" |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 23 | #include "Device/ETC_Decoder.hpp" |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 24 | |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 25 | #ifdef __ANDROID__ |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 26 | # include "System/GrallocAndroid.hpp" |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 27 | #endif |
| 28 | |
Nicolas Capens | a4347a9 | 2020-03-01 08:29:25 -0500 | [diff] [blame] | 29 | #include <cstring> |
| 30 | |
Nicolas Capens | 157ba26 | 2019-12-10 17:49:14 -0500 | [diff] [blame] | 31 | namespace { |
| 32 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 33 | ETC_Decoder::InputType GetInputType(const vk::Format &format) |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 34 | { |
Nicolas Capens | 157ba26 | 2019-12-10 17:49:14 -0500 | [diff] [blame] | 35 | switch(format) |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 36 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 37 | case VK_FORMAT_EAC_R11_UNORM_BLOCK: |
| 38 | return ETC_Decoder::ETC_R_UNSIGNED; |
| 39 | case VK_FORMAT_EAC_R11_SNORM_BLOCK: |
| 40 | return ETC_Decoder::ETC_R_SIGNED; |
| 41 | case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: |
| 42 | return ETC_Decoder::ETC_RG_UNSIGNED; |
| 43 | case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: |
| 44 | return ETC_Decoder::ETC_RG_SIGNED; |
| 45 | case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
| 46 | case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
| 47 | return ETC_Decoder::ETC_RGB; |
| 48 | case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
| 49 | case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
| 50 | return ETC_Decoder::ETC_RGB_PUNCHTHROUGH_ALPHA; |
| 51 | case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: |
| 52 | case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: |
| 53 | return ETC_Decoder::ETC_RGBA; |
| 54 | default: |
Nicolas Capens | 865f889 | 2020-01-21 14:27:10 -0500 | [diff] [blame] | 55 | UNSUPPORTED("format: %d", int(format)); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 56 | return ETC_Decoder::ETC_RGBA; |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 57 | } |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 58 | } |
| 59 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 60 | int GetBCn(const vk::Format &format) |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 61 | { |
| 62 | switch(format) |
| 63 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 64 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: |
| 65 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: |
| 66 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: |
| 67 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: |
| 68 | return 1; |
| 69 | case VK_FORMAT_BC2_UNORM_BLOCK: |
| 70 | case VK_FORMAT_BC2_SRGB_BLOCK: |
| 71 | return 2; |
| 72 | case VK_FORMAT_BC3_UNORM_BLOCK: |
| 73 | case VK_FORMAT_BC3_SRGB_BLOCK: |
| 74 | return 3; |
| 75 | case VK_FORMAT_BC4_UNORM_BLOCK: |
| 76 | case VK_FORMAT_BC4_SNORM_BLOCK: |
| 77 | return 4; |
| 78 | case VK_FORMAT_BC5_UNORM_BLOCK: |
| 79 | case VK_FORMAT_BC5_SNORM_BLOCK: |
| 80 | return 5; |
Ben Clayton | 5751f9e | 2020-03-11 10:41:32 +0000 | [diff] [blame] | 81 | case VK_FORMAT_BC6H_UFLOAT_BLOCK: |
| 82 | case VK_FORMAT_BC6H_SFLOAT_BLOCK: |
| 83 | return 6; |
| 84 | case VK_FORMAT_BC7_UNORM_BLOCK: |
| 85 | case VK_FORMAT_BC7_SRGB_BLOCK: |
| 86 | return 7; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 87 | default: |
Nicolas Capens | 865f889 | 2020-01-21 14:27:10 -0500 | [diff] [blame] | 88 | UNSUPPORTED("format: %d", int(format)); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 89 | return 0; |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 90 | } |
| 91 | } |
| 92 | |
| 93 | // Returns true for BC1 if we have an RGB format, false for RGBA |
Sean Risser | c101f74 | 2020-06-04 15:00:15 -0400 | [diff] [blame] | 94 | // Returns true for BC4, BC5, BC6H if we have an unsigned format, false for signed |
| 95 | // Ignored by BC2, BC3, and BC7 |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 96 | bool GetNoAlphaOrUnsigned(const vk::Format &format) |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 97 | { |
| 98 | switch(format) |
| 99 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 100 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: |
| 101 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: |
| 102 | case VK_FORMAT_BC4_UNORM_BLOCK: |
| 103 | case VK_FORMAT_BC5_UNORM_BLOCK: |
Sean Risser | c101f74 | 2020-06-04 15:00:15 -0400 | [diff] [blame] | 104 | case VK_FORMAT_BC6H_UFLOAT_BLOCK: |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 105 | return true; |
| 106 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: |
| 107 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: |
| 108 | case VK_FORMAT_BC2_UNORM_BLOCK: |
| 109 | case VK_FORMAT_BC2_SRGB_BLOCK: |
| 110 | case VK_FORMAT_BC3_UNORM_BLOCK: |
| 111 | case VK_FORMAT_BC3_SRGB_BLOCK: |
| 112 | case VK_FORMAT_BC4_SNORM_BLOCK: |
| 113 | case VK_FORMAT_BC5_SNORM_BLOCK: |
Ben Clayton | 5751f9e | 2020-03-11 10:41:32 +0000 | [diff] [blame] | 114 | case VK_FORMAT_BC6H_SFLOAT_BLOCK: |
| 115 | case VK_FORMAT_BC7_SRGB_BLOCK: |
| 116 | case VK_FORMAT_BC7_UNORM_BLOCK: |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 117 | return false; |
| 118 | default: |
Nicolas Capens | 865f889 | 2020-01-21 14:27:10 -0500 | [diff] [blame] | 119 | UNSUPPORTED("format: %d", int(format)); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 120 | return false; |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 121 | } |
| 122 | } |
| 123 | |
Nicolas Capens | 157ba26 | 2019-12-10 17:49:14 -0500 | [diff] [blame] | 124 | } // anonymous namespace |
| 125 | |
| 126 | namespace vk { |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 127 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 128 | Image::Image(const VkImageCreateInfo *pCreateInfo, void *mem, Device *device) |
| 129 | : device(device) |
| 130 | , flags(pCreateInfo->flags) |
| 131 | , imageType(pCreateInfo->imageType) |
| 132 | , format(pCreateInfo->format) |
| 133 | , extent(pCreateInfo->extent) |
| 134 | , mipLevels(pCreateInfo->mipLevels) |
| 135 | , arrayLayers(pCreateInfo->arrayLayers) |
| 136 | , samples(pCreateInfo->samples) |
| 137 | , tiling(pCreateInfo->tiling) |
| 138 | , usage(pCreateInfo->usage) |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 139 | { |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 140 | if(format.isCompressed()) |
| 141 | { |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 142 | VkImageCreateInfo compressedImageCreateInfo = *pCreateInfo; |
| 143 | compressedImageCreateInfo.format = format.getDecompressedFormat(); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 144 | decompressedImage = new(mem) Image(&compressedImageCreateInfo, nullptr, device); |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 145 | } |
David 'Digit' Turner | 359bc80 | 2019-08-14 17:46:07 +0200 | [diff] [blame] | 146 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 147 | const auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext); |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 148 | for(; nextInfo != nullptr; nextInfo = nextInfo->pNext) |
David 'Digit' Turner | 359bc80 | 2019-08-14 17:46:07 +0200 | [diff] [blame] | 149 | { |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 150 | if(nextInfo->sType == VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO) |
David 'Digit' Turner | 359bc80 | 2019-08-14 17:46:07 +0200 | [diff] [blame] | 151 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 152 | const auto *externalInfo = reinterpret_cast<const VkExternalMemoryImageCreateInfo *>(nextInfo); |
David 'Digit' Turner | 359bc80 | 2019-08-14 17:46:07 +0200 | [diff] [blame] | 153 | supportedExternalMemoryHandleTypes = externalInfo->handleTypes; |
| 154 | } |
| 155 | } |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 156 | } |
| 157 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 158 | void Image::destroy(const VkAllocationCallbacks *pAllocator) |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 159 | { |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 160 | if(decompressedImage) |
| 161 | { |
| 162 | vk::deallocate(decompressedImage, pAllocator); |
| 163 | } |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 164 | } |
| 165 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 166 | size_t Image::ComputeRequiredAllocationSize(const VkImageCreateInfo *pCreateInfo) |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 167 | { |
Nicolas Capens | 0c73680 | 2019-05-27 12:53:31 -0400 | [diff] [blame] | 168 | return Format(pCreateInfo->format).isCompressed() ? sizeof(Image) : 0; |
Alexis Hetu | f62f375 | 2018-11-15 14:51:15 -0500 | [diff] [blame] | 169 | } |
| 170 | |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 171 | const VkMemoryRequirements Image::getMemoryRequirements() const |
| 172 | { |
| 173 | VkMemoryRequirements memoryRequirements; |
| 174 | memoryRequirements.alignment = vk::REQUIRED_MEMORY_ALIGNMENT; |
| 175 | memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT; |
Nicolas Capens | cfe11c7 | 2019-05-16 09:58:26 -0400 | [diff] [blame] | 176 | memoryRequirements.size = getStorageSize(format.getAspects()) + |
| 177 | (decompressedImage ? decompressedImage->getStorageSize(decompressedImage->format.getAspects()) : 0); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 178 | return memoryRequirements; |
| 179 | } |
| 180 | |
Alexis Hetu | 0774188 | 2020-04-01 16:49:03 -0400 | [diff] [blame] | 181 | size_t Image::getSizeInBytes(const VkImageSubresourceRange &subresourceRange) const |
| 182 | { |
| 183 | size_t size = 0; |
| 184 | uint32_t lastLayer = getLastLayerIndex(subresourceRange); |
| 185 | uint32_t lastMipLevel = getLastMipLevel(subresourceRange); |
| 186 | uint32_t layerCount = lastLayer - subresourceRange.baseArrayLayer + 1; |
| 187 | uint32_t mipLevelCount = lastMipLevel - subresourceRange.baseMipLevel + 1; |
| 188 | |
| 189 | auto aspect = static_cast<VkImageAspectFlagBits>(subresourceRange.aspectMask); |
| 190 | |
| 191 | if(layerCount > 1) |
| 192 | { |
| 193 | if(mipLevelCount < mipLevels) // Compute size for all layers except the last one, then add relevant mip level sizes only for last layer |
| 194 | { |
| 195 | size = (layerCount - 1) * getLayerSize(aspect); |
| 196 | for(uint32_t mipLevel = subresourceRange.baseMipLevel; mipLevel <= lastMipLevel; ++mipLevel) |
| 197 | { |
| 198 | size += getMultiSampledLevelSize(aspect, mipLevel); |
| 199 | } |
| 200 | } |
| 201 | else // All mip levels used, compute full layer sizes |
| 202 | { |
| 203 | size = layerCount * getLayerSize(aspect); |
| 204 | } |
| 205 | } |
| 206 | else // Single layer, add all mip levels in the subresource range |
| 207 | { |
| 208 | for(uint32_t mipLevel = subresourceRange.baseMipLevel; mipLevel <= lastMipLevel; ++mipLevel) |
| 209 | { |
| 210 | size += getMultiSampledLevelSize(aspect, mipLevel); |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | return size; |
| 215 | } |
| 216 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 217 | bool Image::canBindToMemory(DeviceMemory *pDeviceMemory) const |
David 'Digit' Turner | 359bc80 | 2019-08-14 17:46:07 +0200 | [diff] [blame] | 218 | { |
| 219 | return pDeviceMemory->checkExternalMemoryHandleType(supportedExternalMemoryHandleTypes); |
| 220 | } |
| 221 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 222 | void Image::bind(DeviceMemory *pDeviceMemory, VkDeviceSize pMemoryOffset) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 223 | { |
Alexis Hetu | 7d96f51 | 2019-06-13 18:23:56 -0400 | [diff] [blame] | 224 | deviceMemory = pDeviceMemory; |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 225 | memoryOffset = pMemoryOffset; |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 226 | if(decompressedImage) |
| 227 | { |
| 228 | decompressedImage->deviceMemory = deviceMemory; |
Nicolas Capens | cfe11c7 | 2019-05-16 09:58:26 -0400 | [diff] [blame] | 229 | decompressedImage->memoryOffset = memoryOffset + getStorageSize(format.getAspects()); |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 230 | } |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 231 | } |
| 232 | |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 233 | #ifdef __ANDROID__ |
| 234 | VkResult Image::prepareForExternalUseANDROID() const |
| 235 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 236 | void *nativeBuffer = nullptr; |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 237 | VkExtent3D extent = getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0); |
| 238 | |
Jason Macnak | 1de497c | 2020-04-08 11:31:50 -0700 | [diff] [blame] | 239 | buffer_handle_t importedBufferHandle = nullptr; |
| 240 | if(GrallocModule::getInstance()->import(backingMemory.nativeHandle, &importedBufferHandle) != 0) |
| 241 | { |
| 242 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 243 | } |
| 244 | if(!importedBufferHandle) |
| 245 | { |
| 246 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 247 | } |
| 248 | |
| 249 | if(GrallocModule::getInstance()->lock(importedBufferHandle, GRALLOC_USAGE_SW_WRITE_OFTEN, 0, 0, extent.width, extent.height, &nativeBuffer) != 0) |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 250 | { |
| 251 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 252 | } |
| 253 | |
| 254 | if(!nativeBuffer) |
| 255 | { |
| 256 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 257 | } |
| 258 | |
| 259 | int imageRowBytes = rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, 0); |
| 260 | int bufferRowBytes = backingMemory.stride * getFormat().bytes(); |
| 261 | ASSERT(imageRowBytes <= bufferRowBytes); |
| 262 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 263 | uint8_t *srcBuffer = static_cast<uint8_t *>(deviceMemory->getOffsetPointer(0)); |
| 264 | uint8_t *dstBuffer = static_cast<uint8_t *>(nativeBuffer); |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 265 | for(uint32_t i = 0; i < extent.height; i++) |
| 266 | { |
| 267 | memcpy(dstBuffer + (i * bufferRowBytes), srcBuffer + (i * imageRowBytes), imageRowBytes); |
| 268 | } |
| 269 | |
Jason Macnak | 1de497c | 2020-04-08 11:31:50 -0700 | [diff] [blame] | 270 | if(GrallocModule::getInstance()->unlock(importedBufferHandle) != 0) |
| 271 | { |
| 272 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 273 | } |
| 274 | |
| 275 | if(GrallocModule::getInstance()->release(importedBufferHandle) != 0) |
Alexis Hetu | 5244595 | 2019-10-31 17:51:07 -0400 | [diff] [blame] | 276 | { |
| 277 | return VK_ERROR_OUT_OF_DATE_KHR; |
| 278 | } |
| 279 | |
| 280 | return VK_SUCCESS; |
| 281 | } |
| 282 | |
| 283 | VkDeviceMemory Image::getExternalMemory() const |
| 284 | { |
| 285 | return backingMemory.externalMemory ? *deviceMemory : VkDeviceMemory{ VK_NULL_HANDLE }; |
| 286 | } |
| 287 | #endif |
| 288 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 289 | void Image::getSubresourceLayout(const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) const |
Alexis Hetu | 6ab37b0 | 2019-01-24 17:02:45 -0500 | [diff] [blame] | 290 | { |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 291 | // By spec, aspectMask has a single bit set. |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 292 | if(!((pSubresource->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) || |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 293 | (pSubresource->aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) || |
| 294 | (pSubresource->aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) || |
| 295 | (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) || |
| 296 | (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) || |
| 297 | (pSubresource->aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT))) |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 298 | { |
Nicolas Capens | 7e01e4e | 2019-05-18 08:19:07 -0400 | [diff] [blame] | 299 | UNSUPPORTED("aspectMask %X", pSubresource->aspectMask); |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 300 | } |
Nicolas Capens | 7e01e4e | 2019-05-18 08:19:07 -0400 | [diff] [blame] | 301 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 302 | auto aspect = static_cast<VkImageAspectFlagBits>(pSubresource->aspectMask); |
| 303 | pLayout->offset = getMemoryOffset(aspect, pSubresource->mipLevel, pSubresource->arrayLayer); |
Alexis Hetu | 54ec759 | 2019-03-20 14:37:16 -0400 | [diff] [blame] | 304 | pLayout->size = getMultiSampledLevelSize(aspect, pSubresource->mipLevel); |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 305 | pLayout->rowPitch = rowPitchBytes(aspect, pSubresource->mipLevel); |
| 306 | pLayout->depthPitch = slicePitchBytes(aspect, pSubresource->mipLevel); |
| 307 | pLayout->arrayPitch = getLayerSize(aspect); |
Alexis Hetu | 6ab37b0 | 2019-01-24 17:02:45 -0500 | [diff] [blame] | 308 | } |
| 309 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 310 | void Image::copyTo(Image *dstImage, const VkImageCopy ®ion) const |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 311 | { |
| 312 | // Image copy does not perform any conversion, it simply copies memory from |
| 313 | // an image to another image that has the same number of bytes per pixel. |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 314 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 315 | if(!((region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) || |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 316 | (region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) || |
| 317 | (region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) || |
| 318 | (region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) || |
| 319 | (region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) || |
| 320 | (region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT))) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 321 | { |
Alexis Hetu | a384afc | 2019-12-12 15:12:30 -0500 | [diff] [blame] | 322 | UNSUPPORTED("srcSubresource.aspectMask %X", region.srcSubresource.aspectMask); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 323 | } |
| 324 | |
Nicolas Capens | 81bc9d9 | 2019-12-16 15:05:57 -0500 | [diff] [blame] | 325 | if(!((region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) || |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 326 | (region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_DEPTH_BIT) || |
| 327 | (region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_STENCIL_BIT) || |
| 328 | (region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_0_BIT) || |
| 329 | (region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_1_BIT) || |
| 330 | (region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_PLANE_2_BIT))) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 331 | { |
Alexis Hetu | a384afc | 2019-12-12 15:12:30 -0500 | [diff] [blame] | 332 | UNSUPPORTED("dstSubresource.aspectMask %X", region.dstSubresource.aspectMask); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 333 | } |
| 334 | |
Alexis Hetu | a384afc | 2019-12-12 15:12:30 -0500 | [diff] [blame] | 335 | VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask); |
| 336 | VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask); |
Chris Forbes | 4ac42db | 2019-05-08 07:40:24 -0700 | [diff] [blame] | 337 | |
| 338 | Format srcFormat = getFormat(srcAspect); |
Alexis Hetu | 63ae924 | 2019-06-06 13:52:15 -0400 | [diff] [blame] | 339 | Format dstFormat = dstImage->getFormat(dstAspect); |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 340 | int bytesPerBlock = srcFormat.bytesPerBlock(); |
| 341 | ASSERT(bytesPerBlock == dstFormat.bytesPerBlock()); |
Nicolas Capens | 2aace0d | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 342 | ASSERT(samples == dstImage->samples); |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 343 | |
Alexis Hetu | a384afc | 2019-12-12 15:12:30 -0500 | [diff] [blame] | 344 | VkExtent3D srcExtent = getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel); |
| 345 | VkExtent3D dstExtent = dstImage->getMipLevelExtent(dstAspect, region.dstSubresource.mipLevel); |
| 346 | VkExtent3D copyExtent = imageExtentInBlocks(region.extent, srcAspect); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 347 | |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 348 | VkImageType srcImageType = imageType; |
| 349 | VkImageType dstImageType = dstImage->getImageType(); |
| 350 | bool one3D = (srcImageType == VK_IMAGE_TYPE_3D) != (dstImageType == VK_IMAGE_TYPE_3D); |
| 351 | bool both3D = (srcImageType == VK_IMAGE_TYPE_3D) && (dstImageType == VK_IMAGE_TYPE_3D); |
| 352 | |
| 353 | // Texel layout pitches, using the VkSubresourceLayout nomenclature. |
| 354 | int srcRowPitch = rowPitchBytes(srcAspect, region.srcSubresource.mipLevel); |
| 355 | int srcDepthPitch = slicePitchBytes(srcAspect, region.srcSubresource.mipLevel); |
| 356 | int dstRowPitch = dstImage->rowPitchBytes(dstAspect, region.dstSubresource.mipLevel); |
| 357 | int dstDepthPitch = dstImage->slicePitchBytes(dstAspect, region.dstSubresource.mipLevel); |
| 358 | VkDeviceSize srcArrayPitch = getLayerSize(srcAspect); |
| 359 | VkDeviceSize dstArrayPitch = dstImage->getLayerSize(dstAspect); |
| 360 | |
| 361 | // These are the pitches used when iterating over the layers that are being copied by the |
| 362 | // vkCmdCopyImage command. They can differ from the above array piches because the spec states that: |
| 363 | // "If one image is VK_IMAGE_TYPE_3D and the other image is VK_IMAGE_TYPE_2D with multiple |
| 364 | // layers, then each slice is copied to or from a different layer." |
| 365 | VkDeviceSize srcLayerPitch = (srcImageType == VK_IMAGE_TYPE_3D) ? srcDepthPitch : srcArrayPitch; |
| 366 | VkDeviceSize dstLayerPitch = (dstImageType == VK_IMAGE_TYPE_3D) ? dstDepthPitch : dstArrayPitch; |
| 367 | |
| 368 | // If one image is 3D, extent.depth must match the layer count. If both images are 2D, |
| 369 | // depth is 1 but the source and destination subresource layer count must match. |
| 370 | uint32_t layerCount = one3D ? copyExtent.depth : region.srcSubresource.layerCount; |
| 371 | |
| 372 | // Copies between 2D and 3D images are treated as layers, so only use depth as the slice count when |
| 373 | // both images are 3D. |
Nicolas Capens | 2aace0d | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 374 | // Multisample images are currently implemented similar to 3D images by storing one sample per slice. |
| 375 | // TODO(b/160600347): Store samples consecutively. |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 376 | uint32_t sliceCount = both3D ? copyExtent.depth : samples; |
Nicolas Capens | 2aace0d | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 377 | |
| 378 | bool isSingleSlice = (sliceCount == 1); |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 379 | bool isSingleRow = (copyExtent.height == 1) && isSingleSlice; |
| 380 | // In order to copy multiple rows using a single memcpy call, we |
| 381 | // have to make sure that we need to copy the entire row and that |
| 382 | // both source and destination rows have the same size in bytes |
| 383 | bool isEntireRow = (region.extent.width == srcExtent.width) && |
| 384 | (region.extent.width == dstExtent.width) && |
| 385 | // For non-compressed formats, blockWidth is 1. For compressed |
| 386 | // formats, rowPitchBytes returns the number of bytes for a row of |
| 387 | // blocks, so we have to divide by the block height, which means: |
| 388 | // srcRowPitchBytes / srcBlockWidth == dstRowPitchBytes / dstBlockWidth |
| 389 | // And, to avoid potential non exact integer division, for example if a |
| 390 | // block has 16 bytes and represents 5 rows, we change the equation to: |
| 391 | // srcRowPitchBytes * dstBlockWidth == dstRowPitchBytes * srcBlockWidth |
| 392 | ((srcRowPitch * dstFormat.blockWidth()) == |
| 393 | (dstRowPitch * srcFormat.blockWidth())); |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 394 | // In order to copy multiple slices using a single memcpy call, we |
| 395 | // have to make sure that we need to copy the entire slice and that |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 396 | // both source and destination slices have the same size in bytes |
| 397 | bool isEntireSlice = isEntireRow && |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 398 | (copyExtent.height == srcExtent.height) && |
| 399 | (copyExtent.height == dstExtent.height) && |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 400 | (srcDepthPitch == dstDepthPitch); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 401 | |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 402 | const uint8_t *srcLayer = static_cast<const uint8_t *>(getTexelPointer(region.srcOffset, { region.srcSubresource.aspectMask, region.srcSubresource.mipLevel, region.srcSubresource.baseArrayLayer })); |
| 403 | uint8_t *dstLayer = static_cast<uint8_t *>(dstImage->getTexelPointer(region.dstOffset, { region.dstSubresource.aspectMask, region.dstSubresource.mipLevel, region.dstSubresource.baseArrayLayer })); |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 404 | |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 405 | for(uint32_t layer = 0; layer < layerCount; layer++) |
| 406 | { |
| 407 | if(isSingleRow) // Copy one row |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 408 | { |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 409 | size_t copySize = copyExtent.width * bytesPerBlock; |
| 410 | ASSERT((srcLayer + copySize) < end()); |
| 411 | ASSERT((dstLayer + copySize) < dstImage->end()); |
| 412 | memcpy(dstLayer, srcLayer, copySize); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 413 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 414 | else if(isEntireRow && isSingleSlice) // Copy one slice |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 415 | { |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 416 | size_t copySize = copyExtent.height * srcRowPitch; |
| 417 | ASSERT((srcLayer + copySize) < end()); |
| 418 | ASSERT((dstLayer + copySize) < dstImage->end()); |
| 419 | memcpy(dstLayer, srcLayer, copySize); |
| 420 | } |
| 421 | else if(isEntireSlice) // Copy multiple slices |
| 422 | { |
| 423 | size_t copySize = sliceCount * srcDepthPitch; |
| 424 | ASSERT((srcLayer + copySize) < end()); |
| 425 | ASSERT((dstLayer + copySize) < dstImage->end()); |
| 426 | memcpy(dstLayer, srcLayer, copySize); |
| 427 | } |
| 428 | else if(isEntireRow) // Copy slice by slice |
| 429 | { |
| 430 | size_t sliceSize = copyExtent.height * srcRowPitch; |
| 431 | const uint8_t *srcSlice = srcLayer; |
| 432 | uint8_t *dstSlice = dstLayer; |
| 433 | |
| 434 | for(uint32_t z = 0; z < sliceCount; z++) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 435 | { |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 436 | ASSERT((srcSlice + sliceSize) < end()); |
| 437 | ASSERT((dstSlice + sliceSize) < dstImage->end()); |
| 438 | |
| 439 | memcpy(dstSlice, srcSlice, sliceSize); |
| 440 | |
| 441 | dstSlice += dstDepthPitch; |
| 442 | srcSlice += srcDepthPitch; |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 443 | } |
| 444 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 445 | else // Copy row by row |
| 446 | { |
| 447 | size_t rowSize = copyExtent.width * bytesPerBlock; |
| 448 | const uint8_t *srcSlice = srcLayer; |
| 449 | uint8_t *dstSlice = dstLayer; |
| 450 | |
| 451 | for(uint32_t z = 0; z < sliceCount; z++) |
| 452 | { |
| 453 | const uint8_t *srcRow = srcSlice; |
| 454 | uint8_t *dstRow = dstSlice; |
| 455 | |
| 456 | for(uint32_t y = 0; y < copyExtent.height; y++) |
| 457 | { |
| 458 | ASSERT((srcRow + rowSize) < end()); |
| 459 | ASSERT((dstRow + rowSize) < dstImage->end()); |
| 460 | |
| 461 | memcpy(dstRow, srcRow, rowSize); |
| 462 | |
| 463 | srcRow += srcRowPitch; |
| 464 | dstRow += dstRowPitch; |
| 465 | } |
| 466 | |
| 467 | srcSlice += srcDepthPitch; |
| 468 | dstSlice += dstDepthPitch; |
| 469 | } |
| 470 | } |
| 471 | |
| 472 | srcLayer += srcLayerPitch; |
| 473 | dstLayer += dstLayerPitch; |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 474 | } |
Alexis Hetu | a384afc | 2019-12-12 15:12:30 -0500 | [diff] [blame] | 475 | |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 476 | dstImage->contentsChanged({ region.dstSubresource.aspectMask, region.dstSubresource.mipLevel, 1, |
| 477 | region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount }); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 478 | } |
| 479 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 480 | void Image::copy(Buffer *buffer, const VkBufferImageCopy ®ion, bool bufferIsSource) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 481 | { |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 482 | switch(region.imageSubresource.aspectMask) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 483 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 484 | case VK_IMAGE_ASPECT_COLOR_BIT: |
| 485 | case VK_IMAGE_ASPECT_DEPTH_BIT: |
| 486 | case VK_IMAGE_ASPECT_STENCIL_BIT: |
| 487 | case VK_IMAGE_ASPECT_PLANE_0_BIT: |
| 488 | case VK_IMAGE_ASPECT_PLANE_1_BIT: |
| 489 | case VK_IMAGE_ASPECT_PLANE_2_BIT: |
| 490 | break; |
| 491 | default: |
| 492 | UNSUPPORTED("aspectMask %x", int(region.imageSubresource.aspectMask)); |
| 493 | break; |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 494 | } |
| 495 | |
Chris Forbes | 529eda3 | 2019-05-08 10:27:05 -0700 | [diff] [blame] | 496 | auto aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask); |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 497 | Format copyFormat = getFormat(aspect); |
Chris Forbes | 9219c64 | 2019-05-07 07:30:01 -0700 | [diff] [blame] | 498 | |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 499 | VkExtent3D imageExtent = imageExtentInBlocks(region.imageExtent, aspect); |
| 500 | VkExtent2D bufferExtent = bufferExtentInBlocks({ imageExtent.width, imageExtent.height }, region); |
Chris Forbes | 529eda3 | 2019-05-08 10:27:05 -0700 | [diff] [blame] | 501 | int bytesPerBlock = copyFormat.bytesPerBlock(); |
| 502 | int bufferRowPitchBytes = bufferExtent.width * bytesPerBlock; |
| 503 | int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes; |
Nicolas Capens | 2aace0d | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 504 | ASSERT(samples == 1); |
Chris Forbes | 529eda3 | 2019-05-08 10:27:05 -0700 | [diff] [blame] | 505 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 506 | uint8_t *bufferMemory = static_cast<uint8_t *>(buffer->getOffsetPointer(region.bufferOffset)); |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 507 | uint8_t *imageMemory = static_cast<uint8_t *>(getTexelPointer(region.imageOffset, { region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, region.imageSubresource.baseArrayLayer })); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 508 | uint8_t *srcMemory = bufferIsSource ? bufferMemory : imageMemory; |
| 509 | uint8_t *dstMemory = bufferIsSource ? imageMemory : bufferMemory; |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 510 | int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel); |
| 511 | int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel); |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 512 | |
| 513 | int srcSlicePitchBytes = bufferIsSource ? bufferSlicePitchBytes : imageSlicePitchBytes; |
| 514 | int dstSlicePitchBytes = bufferIsSource ? imageSlicePitchBytes : bufferSlicePitchBytes; |
| 515 | int srcRowPitchBytes = bufferIsSource ? bufferRowPitchBytes : imageRowPitchBytes; |
| 516 | int dstRowPitchBytes = bufferIsSource ? imageRowPitchBytes : bufferRowPitchBytes; |
| 517 | |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 518 | VkExtent3D mipLevelExtent = getMipLevelExtent(aspect, region.imageSubresource.mipLevel); |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 519 | bool isSingleSlice = (imageExtent.depth == 1); |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 520 | bool isSingleRow = (imageExtent.height == 1) && isSingleSlice; |
| 521 | bool isEntireRow = (imageExtent.width == mipLevelExtent.width) && |
| 522 | (imageRowPitchBytes == bufferRowPitchBytes); |
| 523 | bool isEntireSlice = isEntireRow && (imageExtent.height == mipLevelExtent.height) && |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 524 | (imageSlicePitchBytes == bufferSlicePitchBytes); |
Alexis Hetu | 0459596 | 2018-12-14 11:07:39 -0500 | [diff] [blame] | 525 | |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 526 | VkDeviceSize copySize = 0; |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 527 | VkDeviceSize bufferLayerSize = 0; |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 528 | if(isSingleRow) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 529 | { |
Chris Forbes | 529eda3 | 2019-05-08 10:27:05 -0700 | [diff] [blame] | 530 | copySize = imageExtent.width * bytesPerBlock; |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 531 | bufferLayerSize = copySize; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 532 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 533 | else if(isEntireRow && isSingleSlice) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 534 | { |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 535 | copySize = imageExtent.height * imageRowPitchBytes; |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 536 | bufferLayerSize = copySize; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 537 | } |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 538 | else if(isEntireSlice) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 539 | { |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 540 | copySize = imageExtent.depth * imageSlicePitchBytes; // Copy multiple slices |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 541 | bufferLayerSize = copySize; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 542 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 543 | else if(isEntireRow) // Copy slice by slice |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 544 | { |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 545 | copySize = imageExtent.height * imageRowPitchBytes; |
| 546 | bufferLayerSize = copySize * imageExtent.depth; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 547 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 548 | else // Copy row by row |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 549 | { |
Chris Forbes | 529eda3 | 2019-05-08 10:27:05 -0700 | [diff] [blame] | 550 | copySize = imageExtent.width * bytesPerBlock; |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 551 | bufferLayerSize = copySize * imageExtent.depth * imageExtent.height; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 552 | } |
| 553 | |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 554 | VkDeviceSize imageLayerSize = getLayerSize(aspect); |
| 555 | VkDeviceSize srcLayerSize = bufferIsSource ? bufferLayerSize : imageLayerSize; |
| 556 | VkDeviceSize dstLayerSize = bufferIsSource ? imageLayerSize : bufferLayerSize; |
| 557 | |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 558 | for(uint32_t i = 0; i < region.imageSubresource.layerCount; i++) |
Alexis Hetu | 0459596 | 2018-12-14 11:07:39 -0500 | [diff] [blame] | 559 | { |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 560 | if(isSingleRow || (isEntireRow && isSingleSlice) || isEntireSlice) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 561 | { |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 562 | ASSERT(((bufferIsSource ? dstMemory : srcMemory) + copySize) < end()); |
| 563 | ASSERT(((bufferIsSource ? srcMemory : dstMemory) + copySize) < buffer->end()); |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 564 | memcpy(dstMemory, srcMemory, copySize); |
| 565 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 566 | else if(isEntireRow) // Copy slice by slice |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 567 | { |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 568 | uint8_t *srcSliceMemory = srcMemory; |
| 569 | uint8_t *dstSliceMemory = dstMemory; |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 570 | for(uint32_t z = 0; z < imageExtent.depth; z++) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 571 | { |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 572 | ASSERT(((bufferIsSource ? dstSliceMemory : srcSliceMemory) + copySize) < end()); |
| 573 | ASSERT(((bufferIsSource ? srcSliceMemory : dstSliceMemory) + copySize) < buffer->end()); |
| 574 | memcpy(dstSliceMemory, srcSliceMemory, copySize); |
| 575 | srcSliceMemory += srcSlicePitchBytes; |
| 576 | dstSliceMemory += dstSlicePitchBytes; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 577 | } |
| 578 | } |
Nicolas Capens | ad65826 | 2020-07-03 10:06:27 -0400 | [diff] [blame] | 579 | else // Copy row by row |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 580 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 581 | uint8_t *srcLayerMemory = srcMemory; |
| 582 | uint8_t *dstLayerMemory = dstMemory; |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 583 | for(uint32_t z = 0; z < imageExtent.depth; z++) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 584 | { |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 585 | uint8_t *srcSliceMemory = srcLayerMemory; |
| 586 | uint8_t *dstSliceMemory = dstLayerMemory; |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 587 | for(uint32_t y = 0; y < imageExtent.height; y++) |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 588 | { |
Nicolas Capens | c55fd97 | 2020-07-02 16:35:23 -0400 | [diff] [blame] | 589 | ASSERT(((bufferIsSource ? dstSliceMemory : srcSliceMemory) + copySize) < end()); |
| 590 | ASSERT(((bufferIsSource ? srcSliceMemory : dstSliceMemory) + copySize) < buffer->end()); |
| 591 | memcpy(dstSliceMemory, srcSliceMemory, copySize); |
| 592 | srcSliceMemory += srcRowPitchBytes; |
| 593 | dstSliceMemory += dstRowPitchBytes; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 594 | } |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 595 | srcLayerMemory += srcSlicePitchBytes; |
| 596 | dstLayerMemory += dstSlicePitchBytes; |
Alexis Hetu | 753c67c | 2018-12-14 16:42:24 -0500 | [diff] [blame] | 597 | } |
| 598 | } |
| 599 | |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 600 | srcMemory += srcLayerSize; |
| 601 | dstMemory += dstLayerSize; |
Alexis Hetu | 0459596 | 2018-12-14 11:07:39 -0500 | [diff] [blame] | 602 | } |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 603 | |
Chris Forbes | 9219c64 | 2019-05-07 07:30:01 -0700 | [diff] [blame] | 604 | if(bufferIsSource) |
| 605 | { |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 606 | contentsChanged({ region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, 1, |
| 607 | region.imageSubresource.baseArrayLayer, region.imageSubresource.layerCount }); |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 608 | } |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 609 | } |
| 610 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 611 | void Image::copyTo(Buffer *dstBuffer, const VkBufferImageCopy ®ion) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 612 | { |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 613 | copy(dstBuffer, region, false); |
| 614 | } |
| 615 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 616 | void Image::copyFrom(Buffer *srcBuffer, const VkBufferImageCopy ®ion) |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 617 | { |
| 618 | copy(srcBuffer, region, true); |
| 619 | } |
| 620 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 621 | void *Image::getTexelPointer(const VkOffset3D &offset, const VkImageSubresource &subresource) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 622 | { |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 623 | VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask); |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 624 | return deviceMemory->getOffsetPointer(texelOffsetBytesInStorage(offset, subresource) + |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 625 | getMemoryOffset(aspect, subresource.mipLevel, subresource.arrayLayer)); |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 626 | } |
| 627 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 628 | VkExtent3D Image::imageExtentInBlocks(const VkExtent3D &extent, VkImageAspectFlagBits aspect) const |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 629 | { |
| 630 | VkExtent3D adjustedExtent = extent; |
| 631 | Format usedFormat = getFormat(aspect); |
| 632 | if(usedFormat.isCompressed()) |
| 633 | { |
| 634 | // When using a compressed format, we use the block as the base unit, instead of the texel |
| 635 | int blockWidth = usedFormat.blockWidth(); |
| 636 | int blockHeight = usedFormat.blockHeight(); |
| 637 | |
Alexis Hetu | 0839cbd | 2019-03-27 15:09:51 -0400 | [diff] [blame] | 638 | // Mip level allocations will round up to the next block for compressed texture |
| 639 | adjustedExtent.width = ((adjustedExtent.width + blockWidth - 1) / blockWidth); |
| 640 | adjustedExtent.height = ((adjustedExtent.height + blockHeight - 1) / blockHeight); |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 641 | } |
| 642 | return adjustedExtent; |
| 643 | } |
| 644 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 645 | VkOffset3D Image::imageOffsetInBlocks(const VkOffset3D &offset, VkImageAspectFlagBits aspect) const |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 646 | { |
| 647 | VkOffset3D adjustedOffset = offset; |
| 648 | Format usedFormat = getFormat(aspect); |
| 649 | if(usedFormat.isCompressed()) |
| 650 | { |
| 651 | // When using a compressed format, we use the block as the base unit, instead of the texel |
| 652 | int blockWidth = usedFormat.blockWidth(); |
| 653 | int blockHeight = usedFormat.blockHeight(); |
| 654 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 655 | ASSERT(((offset.x % blockWidth) == 0) && ((offset.y % blockHeight) == 0)); // We can't offset within a block |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 656 | |
| 657 | adjustedOffset.x /= blockWidth; |
| 658 | adjustedOffset.y /= blockHeight; |
| 659 | } |
| 660 | return adjustedOffset; |
| 661 | } |
| 662 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 663 | VkExtent2D Image::bufferExtentInBlocks(const VkExtent2D &extent, const VkBufferImageCopy ®ion) const |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 664 | { |
| 665 | VkExtent2D adjustedExtent = extent; |
| 666 | VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask); |
| 667 | Format usedFormat = getFormat(aspect); |
| 668 | if(region.bufferRowLength != 0) |
| 669 | { |
| 670 | adjustedExtent.width = region.bufferRowLength; |
| 671 | |
| 672 | if(usedFormat.isCompressed()) |
| 673 | { |
| 674 | int blockWidth = usedFormat.blockWidth(); |
| 675 | ASSERT((adjustedExtent.width % blockWidth) == 0); |
| 676 | adjustedExtent.width /= blockWidth; |
| 677 | } |
| 678 | } |
| 679 | if(region.bufferImageHeight != 0) |
| 680 | { |
| 681 | adjustedExtent.height = region.bufferImageHeight; |
| 682 | |
| 683 | if(usedFormat.isCompressed()) |
| 684 | { |
| 685 | int blockHeight = usedFormat.blockHeight(); |
| 686 | ASSERT((adjustedExtent.height % blockHeight) == 0); |
| 687 | adjustedExtent.height /= blockHeight; |
| 688 | } |
| 689 | } |
| 690 | return adjustedExtent; |
| 691 | } |
| 692 | |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 693 | int Image::borderSize() const |
Alexis Hetu | 6db9a89 | 2019-04-08 15:53:32 -0400 | [diff] [blame] | 694 | { |
| 695 | // We won't add a border to compressed cube textures, we'll add it when we decompress the texture |
| 696 | return (isCube() && !format.isCompressed()) ? 1 : 0; |
| 697 | } |
| 698 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 699 | VkDeviceSize Image::texelOffsetBytesInStorage(const VkOffset3D &offset, const VkImageSubresource &subresource) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 700 | { |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 701 | VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask); |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 702 | VkOffset3D adjustedOffset = imageOffsetInBlocks(offset, aspect); |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 703 | int border = borderSize(); |
Alexis Hetu | 979f940 | 2019-03-27 11:33:15 -0400 | [diff] [blame] | 704 | return adjustedOffset.z * slicePitchBytes(aspect, subresource.mipLevel) + |
Alexis Hetu | 6db9a89 | 2019-04-08 15:53:32 -0400 | [diff] [blame] | 705 | (adjustedOffset.y + border) * rowPitchBytes(aspect, subresource.mipLevel) + |
| 706 | (adjustedOffset.x + border) * getFormat(aspect).bytesPerBlock(); |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 707 | } |
| 708 | |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 709 | VkExtent3D Image::getMipLevelExtent(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 710 | { |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 711 | VkExtent3D mipLevelExtent; |
| 712 | mipLevelExtent.width = extent.width >> mipLevel; |
| 713 | mipLevelExtent.height = extent.height >> mipLevel; |
| 714 | mipLevelExtent.depth = extent.depth >> mipLevel; |
| 715 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 716 | if(mipLevelExtent.width == 0) { mipLevelExtent.width = 1; } |
Nicolas Capens | 7e01e4e | 2019-05-18 08:19:07 -0400 | [diff] [blame] | 717 | if(mipLevelExtent.height == 0) { mipLevelExtent.height = 1; } |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 718 | if(mipLevelExtent.depth == 0) { mipLevelExtent.depth = 1; } |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 719 | |
| 720 | switch(aspect) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 721 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 722 | case VK_IMAGE_ASPECT_COLOR_BIT: |
| 723 | case VK_IMAGE_ASPECT_DEPTH_BIT: |
| 724 | case VK_IMAGE_ASPECT_STENCIL_BIT: |
| 725 | case VK_IMAGE_ASPECT_PLANE_0_BIT: // Vulkan 1.1 Table 31. Plane Format Compatibility Table: plane 0 of all defined formats is full resolution. |
| 726 | break; |
| 727 | case VK_IMAGE_ASPECT_PLANE_1_BIT: |
| 728 | case VK_IMAGE_ASPECT_PLANE_2_BIT: |
| 729 | switch(format) |
| 730 | { |
| 731 | case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: |
| 732 | case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: |
| 733 | ASSERT(mipLevelExtent.width % 2 == 0 && mipLevelExtent.height % 2 == 0); // Vulkan 1.1: "Images in this format must be defined with a width and height that is a multiple of two." |
| 734 | // Vulkan 1.1 Table 31. Plane Format Compatibility Table: |
| 735 | // Half-resolution U and V planes. |
| 736 | mipLevelExtent.width /= 2; |
| 737 | mipLevelExtent.height /= 2; |
| 738 | break; |
| 739 | default: |
| 740 | UNSUPPORTED("format %d", int(format)); |
| 741 | } |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 742 | break; |
| 743 | default: |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 744 | UNSUPPORTED("aspect %x", int(aspect)); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 745 | } |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 746 | |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 747 | return mipLevelExtent; |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 748 | } |
Alexis Hetu | 0459596 | 2018-12-14 11:07:39 -0500 | [diff] [blame] | 749 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 750 | int Image::rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 751 | { |
| 752 | // Depth and Stencil pitch should be computed separately |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 753 | ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 754 | (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 755 | |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 756 | VkExtent3D mipLevelExtent = getMipLevelExtent(aspect, mipLevel); |
| 757 | Format usedFormat = getFormat(aspect); |
| 758 | if(usedFormat.isCompressed()) |
| 759 | { |
| 760 | VkExtent3D extentInBlocks = imageExtentInBlocks(mipLevelExtent, aspect); |
| 761 | return extentInBlocks.width * usedFormat.bytesPerBlock(); |
| 762 | } |
| 763 | |
| 764 | return usedFormat.pitchB(mipLevelExtent.width, borderSize(), true); |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 765 | } |
| 766 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 767 | int Image::slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 768 | { |
| 769 | // Depth and Stencil slice should be computed separately |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 770 | ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 771 | (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)); |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 772 | |
| 773 | VkExtent3D mipLevelExtent = getMipLevelExtent(aspect, mipLevel); |
Alexis Hetu | 0839cbd | 2019-03-27 15:09:51 -0400 | [diff] [blame] | 774 | Format usedFormat = getFormat(aspect); |
| 775 | if(usedFormat.isCompressed()) |
| 776 | { |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 777 | VkExtent3D extentInBlocks = imageExtentInBlocks(mipLevelExtent, aspect); |
| 778 | return extentInBlocks.height * extentInBlocks.width * usedFormat.bytesPerBlock(); |
Alexis Hetu | 0839cbd | 2019-03-27 15:09:51 -0400 | [diff] [blame] | 779 | } |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 780 | |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 781 | return usedFormat.sliceB(mipLevelExtent.width, mipLevelExtent.height, borderSize(), true); |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 782 | } |
| 783 | |
Alexis Hetu | 6a1d92b | 2019-03-11 17:34:13 -0400 | [diff] [blame] | 784 | Format Image::getFormat(VkImageAspectFlagBits aspect) const |
Alexis Hetu | e0b5a4b | 2018-12-14 12:11:02 -0500 | [diff] [blame] | 785 | { |
Nicolas Capens | cfe11c7 | 2019-05-16 09:58:26 -0400 | [diff] [blame] | 786 | return format.getAspectFormat(aspect); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 787 | } |
| 788 | |
Alexis Hetu | ed30373 | 2019-01-16 15:47:19 -0500 | [diff] [blame] | 789 | bool Image::isCube() const |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 790 | { |
Alexis Hetu | ed30373 | 2019-01-16 15:47:19 -0500 | [diff] [blame] | 791 | return (flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && (imageType == VK_IMAGE_TYPE_2D); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 792 | } |
| 793 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 794 | uint8_t *Image::end() const |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 795 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 796 | return reinterpret_cast<uint8_t *>(deviceMemory->getOffsetPointer(deviceMemory->getCommittedMemoryInBytes() + 1)); |
Alexis Hetu | 377077a | 2019-03-14 15:10:51 -0400 | [diff] [blame] | 797 | } |
| 798 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 799 | VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect) const |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 800 | { |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 801 | switch(format) |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 802 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 803 | case VK_FORMAT_D16_UNORM_S8_UINT: |
| 804 | case VK_FORMAT_D24_UNORM_S8_UINT: |
| 805 | case VK_FORMAT_D32_SFLOAT_S8_UINT: |
| 806 | if(aspect == VK_IMAGE_ASPECT_STENCIL_BIT) |
| 807 | { |
| 808 | // Offset by depth buffer to get to stencil buffer |
| 809 | return memoryOffset + getStorageSize(VK_IMAGE_ASPECT_DEPTH_BIT); |
| 810 | } |
| 811 | break; |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 812 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 813 | case VK_FORMAT_G8_B8_R8_3PLANE_420_UNORM: |
| 814 | if(aspect == VK_IMAGE_ASPECT_PLANE_2_BIT) |
| 815 | { |
| 816 | return memoryOffset + getStorageSize(VK_IMAGE_ASPECT_PLANE_1_BIT) + getStorageSize(VK_IMAGE_ASPECT_PLANE_0_BIT); |
| 817 | } |
| 818 | // Fall through to 2PLANE case: |
| 819 | case VK_FORMAT_G8_B8R8_2PLANE_420_UNORM: |
| 820 | if(aspect == VK_IMAGE_ASPECT_PLANE_1_BIT) |
| 821 | { |
| 822 | return memoryOffset + getStorageSize(VK_IMAGE_ASPECT_PLANE_0_BIT); |
| 823 | } |
| 824 | else |
| 825 | { |
| 826 | ASSERT(aspect == VK_IMAGE_ASPECT_PLANE_0_BIT); |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 827 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 828 | return memoryOffset; |
| 829 | } |
| 830 | break; |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 831 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 832 | default: |
| 833 | break; |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 834 | } |
| 835 | |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 836 | return memoryOffset; |
| 837 | } |
| 838 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 839 | VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 840 | { |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 841 | VkDeviceSize offset = getMemoryOffset(aspect); |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 842 | for(uint32_t i = 0; i < mipLevel; ++i) |
| 843 | { |
Alexis Hetu | 54ec759 | 2019-03-20 14:37:16 -0400 | [diff] [blame] | 844 | offset += getMultiSampledLevelSize(aspect, i); |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 845 | } |
| 846 | return offset; |
| 847 | } |
| 848 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 849 | VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 850 | { |
Alexis Hetu | 32ac831 | 2019-04-15 17:20:29 -0400 | [diff] [blame] | 851 | return layer * getLayerOffset(aspect, mipLevel) + getMemoryOffset(aspect, mipLevel); |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 852 | } |
| 853 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 854 | VkDeviceSize Image::getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 855 | { |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 856 | return getMipLevelExtent(aspect, mipLevel).depth * slicePitchBytes(aspect, mipLevel); |
Alexis Hetu | a233cea | 2018-12-07 11:53:19 -0500 | [diff] [blame] | 857 | } |
| 858 | |
Alexis Hetu | 54ec759 | 2019-03-20 14:37:16 -0400 | [diff] [blame] | 859 | VkDeviceSize Image::getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
| 860 | { |
| 861 | return getMipLevelSize(aspect, mipLevel) * samples; |
| 862 | } |
| 863 | |
Alexis Hetu | 32ac831 | 2019-04-15 17:20:29 -0400 | [diff] [blame] | 864 | bool Image::is3DSlice() const |
| 865 | { |
| 866 | return ((imageType == VK_IMAGE_TYPE_3D) && (flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT)); |
| 867 | } |
| 868 | |
| 869 | VkDeviceSize Image::getLayerOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const |
| 870 | { |
| 871 | if(is3DSlice()) |
| 872 | { |
| 873 | // When the VkImageSubresourceRange structure is used to select a subset of the slices of a 3D |
Chris Forbes | 9219c64 | 2019-05-07 07:30:01 -0700 | [diff] [blame] | 874 | // image's mip level in order to create a 2D or 2D array image view of a 3D image created with |
Alexis Hetu | 32ac831 | 2019-04-15 17:20:29 -0400 | [diff] [blame] | 875 | // VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT, baseArrayLayer and layerCount specify the first |
| 876 | // slice index and the number of slices to include in the created image view. |
| 877 | ASSERT(samples == VK_SAMPLE_COUNT_1_BIT); |
| 878 | |
| 879 | // Offset to the proper slice of the 3D image's mip level |
| 880 | return slicePitchBytes(aspect, mipLevel); |
| 881 | } |
| 882 | |
| 883 | return getLayerSize(aspect); |
| 884 | } |
| 885 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 886 | VkDeviceSize Image::getLayerSize(VkImageAspectFlagBits aspect) const |
Alexis Hetu | 809d011 | 2018-12-17 17:00:28 -0500 | [diff] [blame] | 887 | { |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 888 | VkDeviceSize layerSize = 0; |
| 889 | |
| 890 | for(uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel) |
| 891 | { |
Alexis Hetu | 54ec759 | 2019-03-20 14:37:16 -0400 | [diff] [blame] | 892 | layerSize += getMultiSampledLevelSize(aspect, mipLevel); |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 893 | } |
| 894 | |
| 895 | return layerSize; |
| 896 | } |
| 897 | |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 898 | VkDeviceSize Image::getStorageSize(VkImageAspectFlags aspectMask) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 899 | { |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 900 | if((aspectMask & ~(VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT | |
| 901 | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT | VK_IMAGE_ASPECT_PLANE_2_BIT)) != 0) |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 902 | { |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 903 | UNSUPPORTED("aspectMask %x", int(aspectMask)); |
Chris Forbes | 2995dc2 | 2019-03-02 14:57:20 -0800 | [diff] [blame] | 904 | } |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 905 | |
| 906 | VkDeviceSize storageSize = 0; |
| 907 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 908 | if(aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_COLOR_BIT); |
| 909 | if(aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_DEPTH_BIT); |
Nicolas Capens | ba87330 | 2019-05-16 11:25:27 -0400 | [diff] [blame] | 910 | if(aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_STENCIL_BIT); |
| 911 | if(aspectMask & VK_IMAGE_ASPECT_PLANE_0_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_PLANE_0_BIT); |
| 912 | if(aspectMask & VK_IMAGE_ASPECT_PLANE_1_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_PLANE_1_BIT); |
| 913 | if(aspectMask & VK_IMAGE_ASPECT_PLANE_2_BIT) storageSize += getLayerSize(VK_IMAGE_ASPECT_PLANE_2_BIT); |
| 914 | |
| 915 | return arrayLayers * storageSize; |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 916 | } |
| 917 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 918 | const Image *Image::getSampledImage(const vk::Format &imageViewFormat) const |
Alexis Hetu | 62ad1ee | 2019-05-16 14:20:16 -0400 | [diff] [blame] | 919 | { |
| 920 | bool isImageViewCompressed = imageViewFormat.isCompressed(); |
| 921 | if(decompressedImage && !isImageViewCompressed) |
| 922 | { |
| 923 | ASSERT(flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT); |
| 924 | ASSERT(format.bytesPerBlock() == imageViewFormat.bytesPerBlock()); |
| 925 | } |
| 926 | // If the ImageView's format is compressed, then we do need to decompress the image so that |
| 927 | // it may be sampled properly by texture sampling functions, which don't support compressed |
| 928 | // textures. If the ImageView's format is NOT compressed, then we reinterpret cast the |
| 929 | // compressed image into the ImageView's format, so we must return the compressed image as is. |
| 930 | return (decompressedImage && isImageViewCompressed) ? decompressedImage : this; |
| 931 | } |
| 932 | |
Nicolas Capens | 32f4be1 | 2020-06-10 13:14:07 -0400 | [diff] [blame] | 933 | void Image::blitTo(Image *dstImage, const VkImageBlit ®ion, VkFilter filter) const |
Alexis Hetu | 809d011 | 2018-12-17 17:00:28 -0500 | [diff] [blame] | 934 | { |
Alexis Hetu | 63ae924 | 2019-06-06 13:52:15 -0400 | [diff] [blame] | 935 | device->getBlitter()->blit(this, dstImage, region, filter); |
Alexis Hetu | 809d011 | 2018-12-17 17:00:28 -0500 | [diff] [blame] | 936 | } |
| 937 | |
Nicolas Capens | 32f4be1 | 2020-06-10 13:14:07 -0400 | [diff] [blame] | 938 | void Image::copyTo(uint8_t *dst, unsigned int dstPitch) const |
Antonio Maiorano | 26c6c4a | 2019-10-17 15:33:47 -0400 | [diff] [blame] | 939 | { |
Nicolas Capens | 32f4be1 | 2020-06-10 13:14:07 -0400 | [diff] [blame] | 940 | device->getBlitter()->copy(this, dst, dstPitch); |
Antonio Maiorano | 26c6c4a | 2019-10-17 15:33:47 -0400 | [diff] [blame] | 941 | } |
| 942 | |
Nicolas Capens | 32f4be1 | 2020-06-10 13:14:07 -0400 | [diff] [blame] | 943 | void Image::resolveTo(Image *dstImage, const VkImageResolve ®ion) const |
Alexis Hetu | e5e33cd | 2019-04-11 10:24:52 -0400 | [diff] [blame] | 944 | { |
| 945 | VkImageBlit blitRegion; |
| 946 | |
| 947 | blitRegion.srcOffsets[0] = blitRegion.srcOffsets[1] = region.srcOffset; |
| 948 | blitRegion.srcOffsets[1].x += region.extent.width; |
| 949 | blitRegion.srcOffsets[1].y += region.extent.height; |
| 950 | blitRegion.srcOffsets[1].z += region.extent.depth; |
| 951 | |
| 952 | blitRegion.dstOffsets[0] = blitRegion.dstOffsets[1] = region.dstOffset; |
| 953 | blitRegion.dstOffsets[1].x += region.extent.width; |
| 954 | blitRegion.dstOffsets[1].y += region.extent.height; |
| 955 | blitRegion.dstOffsets[1].z += region.extent.depth; |
| 956 | |
| 957 | blitRegion.srcSubresource = region.srcSubresource; |
| 958 | blitRegion.dstSubresource = region.dstSubresource; |
| 959 | |
Alexis Hetu | 63ae924 | 2019-06-06 13:52:15 -0400 | [diff] [blame] | 960 | device->getBlitter()->blit(this, dstImage, blitRegion, VK_FILTER_NEAREST); |
Alexis Hetu | e5e33cd | 2019-04-11 10:24:52 -0400 | [diff] [blame] | 961 | } |
| 962 | |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 963 | VkFormat Image::getClearFormat() const |
Alexis Hetu | 9fbaf69 | 2018-11-19 11:30:43 -0500 | [diff] [blame] | 964 | { |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 965 | // Set the proper format for the clear value, as described here: |
| 966 | // https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#clears-values |
Nicolas Capens | 9d9f30d | 2020-01-12 03:26:18 -0500 | [diff] [blame] | 967 | if(format.isSignedUnnormalizedInteger()) |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 968 | { |
| 969 | return VK_FORMAT_R32G32B32A32_SINT; |
| 970 | } |
Nicolas Capens | 9d9f30d | 2020-01-12 03:26:18 -0500 | [diff] [blame] | 971 | else if(format.isUnsignedUnnormalizedInteger()) |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 972 | { |
| 973 | return VK_FORMAT_R32G32B32A32_UINT; |
| 974 | } |
| 975 | |
| 976 | return VK_FORMAT_R32G32B32A32_SFLOAT; |
| 977 | } |
| 978 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 979 | uint32_t Image::getLastLayerIndex(const VkImageSubresourceRange &subresourceRange) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 980 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 981 | return ((subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) ? arrayLayers : (subresourceRange.baseArrayLayer + subresourceRange.layerCount)) - 1; |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 982 | } |
| 983 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 984 | uint32_t Image::getLastMipLevel(const VkImageSubresourceRange &subresourceRange) const |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 985 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 986 | return ((subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS) ? mipLevels : (subresourceRange.baseMipLevel + subresourceRange.levelCount)) - 1; |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 987 | } |
| 988 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 989 | void Image::clear(void *pixelData, VkFormat pixelFormat, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D &renderArea) |
Alexis Hetu | 7521150 | 2019-01-18 16:08:45 -0500 | [diff] [blame] | 990 | { |
Alexis Hetu | 04dae5e | 2019-04-08 13:41:50 -0400 | [diff] [blame] | 991 | device->getBlitter()->clear(pixelData, pixelFormat, this, viewFormat, subresourceRange, &renderArea); |
Alexis Hetu | 7521150 | 2019-01-18 16:08:45 -0500 | [diff] [blame] | 992 | } |
| 993 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 994 | void Image::clear(const VkClearColorValue &color, const VkImageSubresourceRange &subresourceRange) |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 995 | { |
Nicolas Capens | dd0e600 | 2020-01-24 01:21:47 -0500 | [diff] [blame] | 996 | ASSERT(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 997 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 998 | device->getBlitter()->clear((void *)color.float32, getClearFormat(), this, format, subresourceRange); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 999 | } |
| 1000 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1001 | void Image::clear(const VkClearDepthStencilValue &color, const VkImageSubresourceRange &subresourceRange) |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1002 | { |
Nicolas Capens | dd0e600 | 2020-01-24 01:21:47 -0500 | [diff] [blame] | 1003 | ASSERT((subresourceRange.aspectMask & ~(VK_IMAGE_ASPECT_DEPTH_BIT | |
| 1004 | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1005 | |
| 1006 | if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) |
| 1007 | { |
Alexis Hetu | 3364227 | 2019-03-01 11:55:59 -0500 | [diff] [blame] | 1008 | VkImageSubresourceRange depthSubresourceRange = subresourceRange; |
| 1009 | depthSubresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1010 | device->getBlitter()->clear((void *)(&color.depth), VK_FORMAT_D32_SFLOAT, this, format, depthSubresourceRange); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1011 | } |
| 1012 | |
| 1013 | if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) |
| 1014 | { |
Alexis Hetu | 3364227 | 2019-03-01 11:55:59 -0500 | [diff] [blame] | 1015 | VkImageSubresourceRange stencilSubresourceRange = subresourceRange; |
| 1016 | stencilSubresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1017 | device->getBlitter()->clear((void *)(&color.stencil), VK_FORMAT_S8_UINT, this, format, stencilSubresourceRange); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1018 | } |
| 1019 | } |
| 1020 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1021 | void Image::clear(const VkClearValue &clearValue, const vk::Format &viewFormat, const VkRect2D &renderArea, const VkImageSubresourceRange &subresourceRange) |
Alexis Hetu | eca9ca6 | 2019-01-16 14:21:33 -0500 | [diff] [blame] | 1022 | { |
Nicolas Capens | dd0e600 | 2020-01-24 01:21:47 -0500 | [diff] [blame] | 1023 | ASSERT((subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) || |
| 1024 | (subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | |
| 1025 | VK_IMAGE_ASPECT_STENCIL_BIT))); |
Alexis Hetu | caea0ba | 2018-12-07 16:20:44 -0500 | [diff] [blame] | 1026 | |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1027 | if(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) |
| 1028 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1029 | clear((void *)(clearValue.color.float32), getClearFormat(), viewFormat, subresourceRange, renderArea); |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1030 | } |
| 1031 | else |
| 1032 | { |
Alexis Hetu | 7521150 | 2019-01-18 16:08:45 -0500 | [diff] [blame] | 1033 | if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) |
| 1034 | { |
Alexis Hetu | 3364227 | 2019-03-01 11:55:59 -0500 | [diff] [blame] | 1035 | VkImageSubresourceRange depthSubresourceRange = subresourceRange; |
| 1036 | depthSubresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1037 | clear((void *)(&clearValue.depthStencil.depth), VK_FORMAT_D32_SFLOAT, viewFormat, depthSubresourceRange, renderArea); |
Alexis Hetu | 7521150 | 2019-01-18 16:08:45 -0500 | [diff] [blame] | 1038 | } |
| 1039 | |
| 1040 | if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) |
| 1041 | { |
Alexis Hetu | 3364227 | 2019-03-01 11:55:59 -0500 | [diff] [blame] | 1042 | VkImageSubresourceRange stencilSubresourceRange = subresourceRange; |
| 1043 | stencilSubresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1044 | clear((void *)(&clearValue.depthStencil.stencil), VK_FORMAT_S8_UINT, viewFormat, stencilSubresourceRange, renderArea); |
Alexis Hetu | 7521150 | 2019-01-18 16:08:45 -0500 | [diff] [blame] | 1045 | } |
Alexis Hetu | 7ca9f4a | 2019-01-17 14:51:43 -0500 | [diff] [blame] | 1046 | } |
Alexis Hetu | 9fbaf69 | 2018-11-19 11:30:43 -0500 | [diff] [blame] | 1047 | } |
| 1048 | |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1049 | bool Image::requiresPreprocessing() const |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1050 | { |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1051 | return (isCube() && (arrayLayers >= 6)) || decompressedImage; |
| 1052 | } |
| 1053 | |
| 1054 | void Image::contentsChanged(const VkImageSubresourceRange &subresourceRange, ContentsChangedContext contentsChangedContext) |
| 1055 | { |
| 1056 | // If this function is called after (possibly) writing to this image from a shader, |
| 1057 | // this must have the VK_IMAGE_USAGE_STORAGE_BIT set for the write operation to be |
| 1058 | // valid. Otherwise, we can't have legally written to this image, so we know we can |
| 1059 | // skip updating dirtyResources. |
| 1060 | if((contentsChangedContext == USING_STORAGE) && !(usage & VK_IMAGE_USAGE_STORAGE_BIT)) |
| 1061 | { |
| 1062 | return; |
| 1063 | } |
| 1064 | |
| 1065 | // If this isn't a cube or a compressed image, we'll never need dirtyResources, |
| 1066 | // so we can skip updating dirtyResources |
| 1067 | if(!requiresPreprocessing()) |
| 1068 | { |
| 1069 | return; |
| 1070 | } |
| 1071 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1072 | uint32_t lastLayer = getLastLayerIndex(subresourceRange); |
| 1073 | uint32_t lastMipLevel = getLastMipLevel(subresourceRange); |
| 1074 | |
| 1075 | VkImageSubresource subresource = { |
| 1076 | subresourceRange.aspectMask, |
| 1077 | subresourceRange.baseMipLevel, |
| 1078 | subresourceRange.baseArrayLayer |
| 1079 | }; |
| 1080 | |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1081 | marl::lock lock(mutex); |
| 1082 | for(subresource.arrayLayer = subresourceRange.baseArrayLayer; |
| 1083 | subresource.arrayLayer <= lastLayer; |
| 1084 | subresource.arrayLayer++) |
| 1085 | { |
| 1086 | for(subresource.mipLevel = subresourceRange.baseMipLevel; |
| 1087 | subresource.mipLevel <= lastMipLevel; |
| 1088 | subresource.mipLevel++) |
| 1089 | { |
| 1090 | dirtySubresources.insert(subresource); |
| 1091 | } |
| 1092 | } |
| 1093 | } |
| 1094 | |
| 1095 | void Image::prepareForSampling(const VkImageSubresourceRange &subresourceRange) |
| 1096 | { |
| 1097 | // If this isn't a cube or a compressed image, there's nothing to do |
| 1098 | if(!requiresPreprocessing()) |
| 1099 | { |
| 1100 | return; |
| 1101 | } |
| 1102 | |
| 1103 | uint32_t lastLayer = getLastLayerIndex(subresourceRange); |
| 1104 | uint32_t lastMipLevel = getLastMipLevel(subresourceRange); |
| 1105 | |
| 1106 | VkImageSubresource subresource = { |
| 1107 | subresourceRange.aspectMask, |
| 1108 | subresourceRange.baseMipLevel, |
| 1109 | subresourceRange.baseArrayLayer |
| 1110 | }; |
| 1111 | |
| 1112 | marl::lock lock(mutex); |
| 1113 | |
| 1114 | if(dirtySubresources.empty()) |
| 1115 | { |
| 1116 | return; |
| 1117 | } |
| 1118 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1119 | // First, decompress all relevant dirty subregions |
| 1120 | for(subresource.arrayLayer = subresourceRange.baseArrayLayer; |
| 1121 | subresource.arrayLayer <= lastLayer; |
| 1122 | subresource.arrayLayer++) |
| 1123 | { |
| 1124 | for(subresource.mipLevel = subresourceRange.baseMipLevel; |
| 1125 | subresource.mipLevel <= lastMipLevel; |
| 1126 | subresource.mipLevel++) |
| 1127 | { |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1128 | auto it = dirtySubresources.find(subresource); |
| 1129 | if(it != dirtySubresources.end()) |
| 1130 | { |
| 1131 | decompress(subresource); |
| 1132 | } |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1133 | } |
| 1134 | } |
| 1135 | |
| 1136 | // Second, update cubemap borders |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1137 | for(subresource.arrayLayer = subresourceRange.baseArrayLayer; |
| 1138 | subresource.arrayLayer <= lastLayer; |
| 1139 | subresource.arrayLayer++) |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1140 | { |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1141 | for(subresource.mipLevel = subresourceRange.baseMipLevel; |
| 1142 | subresource.mipLevel <= lastMipLevel; |
| 1143 | subresource.mipLevel++) |
| 1144 | { |
| 1145 | auto it = dirtySubresources.find(subresource); |
| 1146 | if(it != dirtySubresources.end()) |
| 1147 | { |
| 1148 | if(updateCube(subresource)) |
| 1149 | { |
| 1150 | // updateCube() updates all layers of all cubemaps at once, so remove entries to avoid duplicating effort |
| 1151 | VkImageSubresource cleanSubresource = subresource; |
| 1152 | for(cleanSubresource.arrayLayer = 0; cleanSubresource.arrayLayer < arrayLayers - 5;) |
| 1153 | { |
| 1154 | // Delete one cube's worth of dirty subregions |
| 1155 | for(uint32_t i = 0; i < 6; i++, cleanSubresource.arrayLayer++) |
| 1156 | { |
| 1157 | auto it = dirtySubresources.find(cleanSubresource); |
| 1158 | if(it != dirtySubresources.end()) |
| 1159 | { |
| 1160 | dirtySubresources.erase(it); |
| 1161 | } |
| 1162 | } |
| 1163 | } |
| 1164 | } |
| 1165 | } |
| 1166 | } |
| 1167 | } |
| 1168 | |
| 1169 | // Finally, mark all updated subregions clean |
| 1170 | for(subresource.arrayLayer = subresourceRange.baseArrayLayer; |
| 1171 | subresource.arrayLayer <= lastLayer; |
| 1172 | subresource.arrayLayer++) |
| 1173 | { |
| 1174 | for(subresource.mipLevel = subresourceRange.baseMipLevel; |
| 1175 | subresource.mipLevel <= lastMipLevel; |
| 1176 | subresource.mipLevel++) |
| 1177 | { |
| 1178 | auto it = dirtySubresources.find(subresource); |
| 1179 | if(it != dirtySubresources.end()) |
| 1180 | { |
| 1181 | dirtySubresources.erase(it); |
| 1182 | } |
| 1183 | } |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1184 | } |
| 1185 | } |
| 1186 | |
| 1187 | void Image::decompress(const VkImageSubresource &subresource) |
| 1188 | { |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1189 | if(decompressedImage) |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1190 | { |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1191 | switch(format) |
| 1192 | { |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1193 | case VK_FORMAT_EAC_R11_UNORM_BLOCK: |
| 1194 | case VK_FORMAT_EAC_R11_SNORM_BLOCK: |
| 1195 | case VK_FORMAT_EAC_R11G11_UNORM_BLOCK: |
| 1196 | case VK_FORMAT_EAC_R11G11_SNORM_BLOCK: |
| 1197 | case VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK: |
| 1198 | case VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK: |
| 1199 | case VK_FORMAT_ETC2_R8G8B8A1_UNORM_BLOCK: |
| 1200 | case VK_FORMAT_ETC2_R8G8B8A1_SRGB_BLOCK: |
| 1201 | case VK_FORMAT_ETC2_R8G8B8A8_UNORM_BLOCK: |
| 1202 | case VK_FORMAT_ETC2_R8G8B8A8_SRGB_BLOCK: |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1203 | decodeETC2(subresource); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1204 | break; |
| 1205 | case VK_FORMAT_BC1_RGB_UNORM_BLOCK: |
| 1206 | case VK_FORMAT_BC1_RGB_SRGB_BLOCK: |
| 1207 | case VK_FORMAT_BC1_RGBA_UNORM_BLOCK: |
| 1208 | case VK_FORMAT_BC1_RGBA_SRGB_BLOCK: |
| 1209 | case VK_FORMAT_BC2_UNORM_BLOCK: |
| 1210 | case VK_FORMAT_BC2_SRGB_BLOCK: |
| 1211 | case VK_FORMAT_BC3_UNORM_BLOCK: |
| 1212 | case VK_FORMAT_BC3_SRGB_BLOCK: |
| 1213 | case VK_FORMAT_BC4_UNORM_BLOCK: |
| 1214 | case VK_FORMAT_BC4_SNORM_BLOCK: |
| 1215 | case VK_FORMAT_BC5_UNORM_BLOCK: |
| 1216 | case VK_FORMAT_BC5_SNORM_BLOCK: |
Ben Clayton | 5751f9e | 2020-03-11 10:41:32 +0000 | [diff] [blame] | 1217 | case VK_FORMAT_BC6H_UFLOAT_BLOCK: |
| 1218 | case VK_FORMAT_BC6H_SFLOAT_BLOCK: |
| 1219 | case VK_FORMAT_BC7_UNORM_BLOCK: |
| 1220 | case VK_FORMAT_BC7_SRGB_BLOCK: |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1221 | decodeBC(subresource); |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1222 | break; |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1223 | case VK_FORMAT_ASTC_4x4_UNORM_BLOCK: |
| 1224 | case VK_FORMAT_ASTC_5x4_UNORM_BLOCK: |
| 1225 | case VK_FORMAT_ASTC_5x5_UNORM_BLOCK: |
| 1226 | case VK_FORMAT_ASTC_6x5_UNORM_BLOCK: |
| 1227 | case VK_FORMAT_ASTC_6x6_UNORM_BLOCK: |
| 1228 | case VK_FORMAT_ASTC_8x5_UNORM_BLOCK: |
| 1229 | case VK_FORMAT_ASTC_8x6_UNORM_BLOCK: |
| 1230 | case VK_FORMAT_ASTC_8x8_UNORM_BLOCK: |
| 1231 | case VK_FORMAT_ASTC_10x5_UNORM_BLOCK: |
| 1232 | case VK_FORMAT_ASTC_10x6_UNORM_BLOCK: |
| 1233 | case VK_FORMAT_ASTC_10x8_UNORM_BLOCK: |
| 1234 | case VK_FORMAT_ASTC_10x10_UNORM_BLOCK: |
| 1235 | case VK_FORMAT_ASTC_12x10_UNORM_BLOCK: |
| 1236 | case VK_FORMAT_ASTC_12x12_UNORM_BLOCK: |
| 1237 | case VK_FORMAT_ASTC_4x4_SRGB_BLOCK: |
| 1238 | case VK_FORMAT_ASTC_5x4_SRGB_BLOCK: |
| 1239 | case VK_FORMAT_ASTC_5x5_SRGB_BLOCK: |
| 1240 | case VK_FORMAT_ASTC_6x5_SRGB_BLOCK: |
| 1241 | case VK_FORMAT_ASTC_6x6_SRGB_BLOCK: |
| 1242 | case VK_FORMAT_ASTC_8x5_SRGB_BLOCK: |
| 1243 | case VK_FORMAT_ASTC_8x6_SRGB_BLOCK: |
| 1244 | case VK_FORMAT_ASTC_8x8_SRGB_BLOCK: |
| 1245 | case VK_FORMAT_ASTC_10x5_SRGB_BLOCK: |
| 1246 | case VK_FORMAT_ASTC_10x6_SRGB_BLOCK: |
| 1247 | case VK_FORMAT_ASTC_10x8_SRGB_BLOCK: |
| 1248 | case VK_FORMAT_ASTC_10x10_SRGB_BLOCK: |
| 1249 | case VK_FORMAT_ASTC_12x10_SRGB_BLOCK: |
| 1250 | case VK_FORMAT_ASTC_12x12_SRGB_BLOCK: |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1251 | decodeASTC(subresource); |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1252 | break; |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1253 | default: |
| 1254 | break; |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1255 | } |
| 1256 | } |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1257 | } |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1258 | |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1259 | bool Image::updateCube(const VkImageSubresource &subres) |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1260 | { |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1261 | if(isCube() && (arrayLayers >= 6)) |
| 1262 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1263 | VkImageSubresource subresource = subres; |
Corentin Wallez | 8def906 | 2020-02-18 16:36:56 +0100 | [diff] [blame] | 1264 | |
| 1265 | // Update the borders of all the groups of 6 layers that can be part of a cubemaps but don't |
| 1266 | // touch leftover layers that cannot be part of cubemaps. |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1267 | for(subresource.arrayLayer = 0; subresource.arrayLayer < arrayLayers - 5; subresource.arrayLayer += 6) |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1268 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1269 | device->getBlitter()->updateBorders(decompressedImage ? decompressedImage : this, subresource); |
Alexis Hetu | b317d96 | 2019-04-29 14:07:31 -0400 | [diff] [blame] | 1270 | } |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1271 | |
| 1272 | return true; |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1273 | } |
Alexis Hetu | 4f438a5 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1274 | |
| 1275 | return false; |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1276 | } |
| 1277 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1278 | void Image::decodeETC2(const VkImageSubresource &subresource) |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1279 | { |
| 1280 | ASSERT(decompressedImage); |
| 1281 | |
| 1282 | ETC_Decoder::InputType inputType = GetInputType(format); |
| 1283 | |
Alexis Hetu | 8b7597e | 2019-05-06 15:14:21 -0400 | [diff] [blame] | 1284 | int bytes = decompressedImage->format.bytes(); |
| 1285 | bool fakeAlpha = (format == VK_FORMAT_ETC2_R8G8B8_UNORM_BLOCK) || (format == VK_FORMAT_ETC2_R8G8B8_SRGB_BLOCK); |
| 1286 | size_t sizeToWrite = 0; |
| 1287 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1288 | VkExtent3D mipLevelExtent = getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresource.aspectMask), subresource.mipLevel); |
| 1289 | |
| 1290 | int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel); |
| 1291 | |
| 1292 | if(fakeAlpha) |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1293 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1294 | // To avoid overflow in case of cube textures, which are offset in memory to account for the border, |
| 1295 | // compute the size from the first pixel to the last pixel, excluding any padding or border before |
| 1296 | // the first pixel or after the last pixel. |
| 1297 | sizeToWrite = ((mipLevelExtent.height - 1) * pitchB) + (mipLevelExtent.width * bytes); |
| 1298 | } |
| 1299 | |
| 1300 | for(int32_t depth = 0; depth < static_cast<int32_t>(mipLevelExtent.depth); depth++) |
| 1301 | { |
| 1302 | uint8_t *source = static_cast<uint8_t *>(getTexelPointer({ 0, 0, depth }, subresource)); |
| 1303 | uint8_t *dest = static_cast<uint8_t *>(decompressedImage->getTexelPointer({ 0, 0, depth }, subresource)); |
| 1304 | |
| 1305 | if(fakeAlpha) |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1306 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1307 | ASSERT((dest + sizeToWrite) < decompressedImage->end()); |
| 1308 | memset(dest, 0xFF, sizeToWrite); |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1309 | } |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1310 | |
| 1311 | ETC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height, |
| 1312 | pitchB, bytes, inputType); |
Alexis Hetu | ac87334 | 2019-04-17 15:59:03 -0400 | [diff] [blame] | 1313 | } |
| 1314 | } |
| 1315 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1316 | void Image::decodeBC(const VkImageSubresource &subresource) |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 1317 | { |
| 1318 | ASSERT(decompressedImage); |
| 1319 | |
| 1320 | int n = GetBCn(format); |
| 1321 | int noAlphaU = GetNoAlphaOrUnsigned(format); |
| 1322 | |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 1323 | int bytes = decompressedImage->format.bytes(); |
| 1324 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1325 | VkExtent3D mipLevelExtent = getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresource.aspectMask), subresource.mipLevel); |
| 1326 | |
| 1327 | int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel); |
| 1328 | |
| 1329 | for(int32_t depth = 0; depth < static_cast<int32_t>(mipLevelExtent.depth); depth++) |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 1330 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1331 | uint8_t *source = static_cast<uint8_t *>(getTexelPointer({ 0, 0, depth }, subresource)); |
| 1332 | uint8_t *dest = static_cast<uint8_t *>(decompressedImage->getTexelPointer({ 0, 0, depth }, subresource)); |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 1333 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1334 | BC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height, |
| 1335 | pitchB, bytes, n, noAlphaU); |
Alexis Hetu | c77b1d8 | 2019-12-11 11:43:44 -0500 | [diff] [blame] | 1336 | } |
| 1337 | } |
| 1338 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1339 | void Image::decodeASTC(const VkImageSubresource &subresource) |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1340 | { |
| 1341 | ASSERT(decompressedImage); |
| 1342 | |
| 1343 | int xBlockSize = format.blockWidth(); |
| 1344 | int yBlockSize = format.blockHeight(); |
| 1345 | int zBlockSize = 1; |
| 1346 | bool isUnsigned = format.isUnsignedComponent(0); |
| 1347 | |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1348 | int bytes = decompressedImage->format.bytes(); |
| 1349 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1350 | VkExtent3D mipLevelExtent = getMipLevelExtent(static_cast<VkImageAspectFlagBits>(subresource.aspectMask), subresource.mipLevel); |
| 1351 | |
| 1352 | int xblocks = (mipLevelExtent.width + xBlockSize - 1) / xBlockSize; |
| 1353 | int yblocks = (mipLevelExtent.height + yBlockSize - 1) / yBlockSize; |
| 1354 | int zblocks = (zBlockSize > 1) ? (mipLevelExtent.depth + zBlockSize - 1) / zBlockSize : 1; |
| 1355 | |
| 1356 | if(xblocks <= 0 || yblocks <= 0 || zblocks <= 0) |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1357 | { |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1358 | return; |
| 1359 | } |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1360 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1361 | int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel); |
| 1362 | int sliceB = decompressedImage->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel); |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1363 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1364 | for(int32_t depth = 0; depth < static_cast<int32_t>(mipLevelExtent.depth); depth++) |
| 1365 | { |
| 1366 | uint8_t *source = static_cast<uint8_t *>(getTexelPointer({ 0, 0, depth }, subresource)); |
| 1367 | uint8_t *dest = static_cast<uint8_t *>(decompressedImage->getTexelPointer({ 0, 0, depth }, subresource)); |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1368 | |
Alexis Hetu | 4615971 | 2020-06-15 16:13:51 -0400 | [diff] [blame] | 1369 | ASTC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height, mipLevelExtent.depth, bytes, pitchB, sliceB, |
| 1370 | xBlockSize, yBlockSize, zBlockSize, xblocks, yblocks, zblocks, isUnsigned); |
Alexis Hetu | 1b90087 | 2020-02-24 12:09:16 -0500 | [diff] [blame] | 1371 | } |
| 1372 | } |
| 1373 | |
Ben Clayton | 2ed93ab | 2019-12-17 20:38:03 +0000 | [diff] [blame] | 1374 | } // namespace vk |