blob: f52ebcdfab7bcfdb1cd827fd9a35008cb6d56565 [file] [log] [blame]
Alexis Hetuf62f3752018-11-15 14:51:15 -05001// 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 Clayton2ed93ab2019-12-17 20:38:03 +000015#include "VkImage.hpp"
Nicolas Capensa4347a92020-03-01 08:29:25 -050016
Alexis Hetua233cea2018-12-07 11:53:19 -050017#include "VkBuffer.hpp"
Alexis Hetu0da99f52019-02-27 12:54:52 -050018#include "VkDevice.hpp"
Ben Clayton2ed93ab2019-12-17 20:38:03 +000019#include "VkDeviceMemory.hpp"
Nicolas Capens51b28002020-01-30 16:41:00 -050020#include "Device/ASTC_Decoder.hpp"
Alexis Hetuc77b1d82019-12-11 11:43:44 -050021#include "Device/BC_Decoder.hpp"
Ben Clayton2ed93ab2019-12-17 20:38:03 +000022#include "Device/Blitter.hpp"
Alexis Hetuac873342019-04-17 15:59:03 -040023#include "Device/ETC_Decoder.hpp"
Alexis Hetuf62f3752018-11-15 14:51:15 -050024
Alexis Hetu52445952019-10-31 17:51:07 -040025#ifdef __ANDROID__
Ben Clayton2ed93ab2019-12-17 20:38:03 +000026# include "System/GrallocAndroid.hpp"
Alexis Hetu52445952019-10-31 17:51:07 -040027#endif
28
Nicolas Capensa4347a92020-03-01 08:29:25 -050029#include <cstring>
30
Nicolas Capens157ba262019-12-10 17:49:14 -050031namespace {
32
Ben Clayton2ed93ab2019-12-17 20:38:03 +000033ETC_Decoder::InputType GetInputType(const vk::Format &format)
Chris Forbes2995dc22019-03-02 14:57:20 -080034{
Nicolas Capens157ba262019-12-10 17:49:14 -050035 switch(format)
Alexis Hetuac873342019-04-17 15:59:03 -040036 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +000037 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 Capens865f8892020-01-21 14:27:10 -050055 UNSUPPORTED("format: %d", int(format));
Ben Clayton2ed93ab2019-12-17 20:38:03 +000056 return ETC_Decoder::ETC_RGBA;
Alexis Hetuac873342019-04-17 15:59:03 -040057 }
Chris Forbes2995dc22019-03-02 14:57:20 -080058}
59
Ben Clayton2ed93ab2019-12-17 20:38:03 +000060int GetBCn(const vk::Format &format)
Alexis Hetuc77b1d82019-12-11 11:43:44 -050061{
62 switch(format)
63 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +000064 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 Clayton5751f9e2020-03-11 10:41:32 +000081 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 Clayton2ed93ab2019-12-17 20:38:03 +000087 default:
Nicolas Capens865f8892020-01-21 14:27:10 -050088 UNSUPPORTED("format: %d", int(format));
Ben Clayton2ed93ab2019-12-17 20:38:03 +000089 return 0;
Alexis Hetuc77b1d82019-12-11 11:43:44 -050090 }
91}
92
93// Returns true for BC1 if we have an RGB format, false for RGBA
Sean Risserc101f742020-06-04 15:00:15 -040094// Returns true for BC4, BC5, BC6H if we have an unsigned format, false for signed
95// Ignored by BC2, BC3, and BC7
Ben Clayton2ed93ab2019-12-17 20:38:03 +000096bool GetNoAlphaOrUnsigned(const vk::Format &format)
Alexis Hetuc77b1d82019-12-11 11:43:44 -050097{
98 switch(format)
99 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000100 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 Risserc101f742020-06-04 15:00:15 -0400104 case VK_FORMAT_BC6H_UFLOAT_BLOCK:
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000105 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 Clayton5751f9e2020-03-11 10:41:32 +0000114 case VK_FORMAT_BC6H_SFLOAT_BLOCK:
115 case VK_FORMAT_BC7_SRGB_BLOCK:
116 case VK_FORMAT_BC7_UNORM_BLOCK:
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000117 return false;
118 default:
Nicolas Capens865f8892020-01-21 14:27:10 -0500119 UNSUPPORTED("format: %d", int(format));
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000120 return false;
Alexis Hetuc77b1d82019-12-11 11:43:44 -0500121 }
122}
123
Nicolas Capens157ba262019-12-10 17:49:14 -0500124} // anonymous namespace
125
126namespace vk {
Alexis Hetuf62f3752018-11-15 14:51:15 -0500127
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000128Image::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 Hetuf62f3752018-11-15 14:51:15 -0500139{
Alexis Hetuac873342019-04-17 15:59:03 -0400140 if(format.isCompressed())
141 {
Nicolas Capens0c736802019-05-27 12:53:31 -0400142 VkImageCreateInfo compressedImageCreateInfo = *pCreateInfo;
143 compressedImageCreateInfo.format = format.getDecompressedFormat();
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000144 decompressedImage = new(mem) Image(&compressedImageCreateInfo, nullptr, device);
Alexis Hetuac873342019-04-17 15:59:03 -0400145 }
David 'Digit' Turner359bc802019-08-14 17:46:07 +0200146
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000147 const auto *nextInfo = reinterpret_cast<const VkBaseInStructure *>(pCreateInfo->pNext);
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500148 for(; nextInfo != nullptr; nextInfo = nextInfo->pNext)
David 'Digit' Turner359bc802019-08-14 17:46:07 +0200149 {
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500150 if(nextInfo->sType == VK_STRUCTURE_TYPE_EXTERNAL_MEMORY_IMAGE_CREATE_INFO)
David 'Digit' Turner359bc802019-08-14 17:46:07 +0200151 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000152 const auto *externalInfo = reinterpret_cast<const VkExternalMemoryImageCreateInfo *>(nextInfo);
David 'Digit' Turner359bc802019-08-14 17:46:07 +0200153 supportedExternalMemoryHandleTypes = externalInfo->handleTypes;
154 }
155 }
Alexis Hetuf62f3752018-11-15 14:51:15 -0500156}
157
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000158void Image::destroy(const VkAllocationCallbacks *pAllocator)
Alexis Hetuf62f3752018-11-15 14:51:15 -0500159{
Alexis Hetuac873342019-04-17 15:59:03 -0400160 if(decompressedImage)
161 {
162 vk::deallocate(decompressedImage, pAllocator);
163 }
Alexis Hetuf62f3752018-11-15 14:51:15 -0500164}
165
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000166size_t Image::ComputeRequiredAllocationSize(const VkImageCreateInfo *pCreateInfo)
Alexis Hetuf62f3752018-11-15 14:51:15 -0500167{
Nicolas Capens0c736802019-05-27 12:53:31 -0400168 return Format(pCreateInfo->format).isCompressed() ? sizeof(Image) : 0;
Alexis Hetuf62f3752018-11-15 14:51:15 -0500169}
170
Alexis Hetua233cea2018-12-07 11:53:19 -0500171const VkMemoryRequirements Image::getMemoryRequirements() const
172{
173 VkMemoryRequirements memoryRequirements;
174 memoryRequirements.alignment = vk::REQUIRED_MEMORY_ALIGNMENT;
175 memoryRequirements.memoryTypeBits = vk::MEMORY_TYPE_GENERIC_BIT;
Nicolas Capenscfe11c72019-05-16 09:58:26 -0400176 memoryRequirements.size = getStorageSize(format.getAspects()) +
177 (decompressedImage ? decompressedImage->getStorageSize(decompressedImage->format.getAspects()) : 0);
Alexis Hetua233cea2018-12-07 11:53:19 -0500178 return memoryRequirements;
179}
180
Alexis Hetu07741882020-04-01 16:49:03 -0400181size_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 Clayton2ed93ab2019-12-17 20:38:03 +0000217bool Image::canBindToMemory(DeviceMemory *pDeviceMemory) const
David 'Digit' Turner359bc802019-08-14 17:46:07 +0200218{
219 return pDeviceMemory->checkExternalMemoryHandleType(supportedExternalMemoryHandleTypes);
220}
221
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000222void Image::bind(DeviceMemory *pDeviceMemory, VkDeviceSize pMemoryOffset)
Alexis Hetua233cea2018-12-07 11:53:19 -0500223{
Alexis Hetu7d96f512019-06-13 18:23:56 -0400224 deviceMemory = pDeviceMemory;
Alexis Hetua233cea2018-12-07 11:53:19 -0500225 memoryOffset = pMemoryOffset;
Alexis Hetuac873342019-04-17 15:59:03 -0400226 if(decompressedImage)
227 {
228 decompressedImage->deviceMemory = deviceMemory;
Nicolas Capenscfe11c72019-05-16 09:58:26 -0400229 decompressedImage->memoryOffset = memoryOffset + getStorageSize(format.getAspects());
Alexis Hetuac873342019-04-17 15:59:03 -0400230 }
Alexis Hetua233cea2018-12-07 11:53:19 -0500231}
232
Alexis Hetu52445952019-10-31 17:51:07 -0400233#ifdef __ANDROID__
234VkResult Image::prepareForExternalUseANDROID() const
235{
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000236 void *nativeBuffer = nullptr;
Alexis Hetu52445952019-10-31 17:51:07 -0400237 VkExtent3D extent = getMipLevelExtent(VK_IMAGE_ASPECT_COLOR_BIT, 0);
238
Jason Macnak1de497c2020-04-08 11:31:50 -0700239 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 Hetu52445952019-10-31 17:51:07 -0400250 {
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 Clayton2ed93ab2019-12-17 20:38:03 +0000263 uint8_t *srcBuffer = static_cast<uint8_t *>(deviceMemory->getOffsetPointer(0));
264 uint8_t *dstBuffer = static_cast<uint8_t *>(nativeBuffer);
Alexis Hetu52445952019-10-31 17:51:07 -0400265 for(uint32_t i = 0; i < extent.height; i++)
266 {
267 memcpy(dstBuffer + (i * bufferRowBytes), srcBuffer + (i * imageRowBytes), imageRowBytes);
268 }
269
Jason Macnak1de497c2020-04-08 11:31:50 -0700270 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 Hetu52445952019-10-31 17:51:07 -0400276 {
277 return VK_ERROR_OUT_OF_DATE_KHR;
278 }
279
280 return VK_SUCCESS;
281}
282
283VkDeviceMemory Image::getExternalMemory() const
284{
285 return backingMemory.externalMemory ? *deviceMemory : VkDeviceMemory{ VK_NULL_HANDLE };
286}
287#endif
288
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000289void Image::getSubresourceLayout(const VkImageSubresource *pSubresource, VkSubresourceLayout *pLayout) const
Alexis Hetu6ab37b02019-01-24 17:02:45 -0500290{
Chris Forbes2995dc22019-03-02 14:57:20 -0800291 // By spec, aspectMask has a single bit set.
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500292 if(!((pSubresource->aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000293 (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 Forbes2995dc22019-03-02 14:57:20 -0800298 {
Nicolas Capens7e01e4e2019-05-18 08:19:07 -0400299 UNSUPPORTED("aspectMask %X", pSubresource->aspectMask);
Chris Forbes2995dc22019-03-02 14:57:20 -0800300 }
Nicolas Capens7e01e4e2019-05-18 08:19:07 -0400301
Chris Forbes2995dc22019-03-02 14:57:20 -0800302 auto aspect = static_cast<VkImageAspectFlagBits>(pSubresource->aspectMask);
303 pLayout->offset = getMemoryOffset(aspect, pSubresource->mipLevel, pSubresource->arrayLayer);
Alexis Hetu54ec7592019-03-20 14:37:16 -0400304 pLayout->size = getMultiSampledLevelSize(aspect, pSubresource->mipLevel);
Chris Forbes2995dc22019-03-02 14:57:20 -0800305 pLayout->rowPitch = rowPitchBytes(aspect, pSubresource->mipLevel);
306 pLayout->depthPitch = slicePitchBytes(aspect, pSubresource->mipLevel);
307 pLayout->arrayPitch = getLayerSize(aspect);
Alexis Hetu6ab37b02019-01-24 17:02:45 -0500308}
309
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000310void Image::copyTo(Image *dstImage, const VkImageCopy &region) const
Alexis Hetua233cea2018-12-07 11:53:19 -0500311{
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 Hetua233cea2018-12-07 11:53:19 -0500314
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500315 if(!((region.srcSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000316 (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 Hetua233cea2018-12-07 11:53:19 -0500321 {
Alexis Hetua384afc2019-12-12 15:12:30 -0500322 UNSUPPORTED("srcSubresource.aspectMask %X", region.srcSubresource.aspectMask);
Alexis Hetua233cea2018-12-07 11:53:19 -0500323 }
324
Nicolas Capens81bc9d92019-12-16 15:05:57 -0500325 if(!((region.dstSubresource.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000326 (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 Hetua233cea2018-12-07 11:53:19 -0500331 {
Alexis Hetua384afc2019-12-12 15:12:30 -0500332 UNSUPPORTED("dstSubresource.aspectMask %X", region.dstSubresource.aspectMask);
Alexis Hetua233cea2018-12-07 11:53:19 -0500333 }
334
Alexis Hetua384afc2019-12-12 15:12:30 -0500335 VkImageAspectFlagBits srcAspect = static_cast<VkImageAspectFlagBits>(region.srcSubresource.aspectMask);
336 VkImageAspectFlagBits dstAspect = static_cast<VkImageAspectFlagBits>(region.dstSubresource.aspectMask);
Chris Forbes4ac42db2019-05-08 07:40:24 -0700337
338 Format srcFormat = getFormat(srcAspect);
Alexis Hetu63ae9242019-06-06 13:52:15 -0400339 Format dstFormat = dstImage->getFormat(dstAspect);
Nicolas Capensc55fd972020-07-02 16:35:23 -0400340 int bytesPerBlock = srcFormat.bytesPerBlock();
341 ASSERT(bytesPerBlock == dstFormat.bytesPerBlock());
Nicolas Capens2aace0d2020-07-02 16:35:23 -0400342 ASSERT(samples == dstImage->samples);
Chris Forbes2995dc22019-03-02 14:57:20 -0800343
Alexis Hetua384afc2019-12-12 15:12:30 -0500344 VkExtent3D srcExtent = getMipLevelExtent(srcAspect, region.srcSubresource.mipLevel);
345 VkExtent3D dstExtent = dstImage->getMipLevelExtent(dstAspect, region.dstSubresource.mipLevel);
346 VkExtent3D copyExtent = imageExtentInBlocks(region.extent, srcAspect);
Alexis Hetua233cea2018-12-07 11:53:19 -0500347
Nicolas Capensad658262020-07-03 10:06:27 -0400348 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 Capens2aace0d2020-07-02 16:35:23 -0400374 // Multisample images are currently implemented similar to 3D images by storing one sample per slice.
375 // TODO(b/160600347): Store samples consecutively.
Nicolas Capensad658262020-07-03 10:06:27 -0400376 uint32_t sliceCount = both3D ? copyExtent.depth : samples;
Nicolas Capens2aace0d2020-07-02 16:35:23 -0400377
378 bool isSingleSlice = (sliceCount == 1);
Nicolas Capensad658262020-07-03 10:06:27 -0400379 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 Capensc55fd972020-07-02 16:35:23 -0400394 // 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 Capensad658262020-07-03 10:06:27 -0400396 // both source and destination slices have the same size in bytes
397 bool isEntireSlice = isEntireRow &&
Alexis Hetu979f9402019-03-27 11:33:15 -0400398 (copyExtent.height == srcExtent.height) &&
399 (copyExtent.height == dstExtent.height) &&
Nicolas Capensad658262020-07-03 10:06:27 -0400400 (srcDepthPitch == dstDepthPitch);
Alexis Hetua233cea2018-12-07 11:53:19 -0500401
Nicolas Capensad658262020-07-03 10:06:27 -0400402 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 Hetu377077a2019-03-14 15:10:51 -0400404
Nicolas Capensad658262020-07-03 10:06:27 -0400405 for(uint32_t layer = 0; layer < layerCount; layer++)
406 {
407 if(isSingleRow) // Copy one row
Alexis Hetua233cea2018-12-07 11:53:19 -0500408 {
Nicolas Capensad658262020-07-03 10:06:27 -0400409 size_t copySize = copyExtent.width * bytesPerBlock;
410 ASSERT((srcLayer + copySize) < end());
411 ASSERT((dstLayer + copySize) < dstImage->end());
412 memcpy(dstLayer, srcLayer, copySize);
Alexis Hetua233cea2018-12-07 11:53:19 -0500413 }
Nicolas Capensad658262020-07-03 10:06:27 -0400414 else if(isEntireRow && isSingleSlice) // Copy one slice
Alexis Hetua233cea2018-12-07 11:53:19 -0500415 {
Nicolas Capensad658262020-07-03 10:06:27 -0400416 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 Hetua233cea2018-12-07 11:53:19 -0500435 {
Nicolas Capensad658262020-07-03 10:06:27 -0400436 ASSERT((srcSlice + sliceSize) < end());
437 ASSERT((dstSlice + sliceSize) < dstImage->end());
438
439 memcpy(dstSlice, srcSlice, sliceSize);
440
441 dstSlice += dstDepthPitch;
442 srcSlice += srcDepthPitch;
Alexis Hetua233cea2018-12-07 11:53:19 -0500443 }
444 }
Nicolas Capensad658262020-07-03 10:06:27 -0400445 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 Hetua233cea2018-12-07 11:53:19 -0500474 }
Alexis Hetua384afc2019-12-12 15:12:30 -0500475
Alexis Hetu4f438a52020-06-15 16:13:51 -0400476 dstImage->contentsChanged({ region.dstSubresource.aspectMask, region.dstSubresource.mipLevel, 1,
477 region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount });
Alexis Hetua233cea2018-12-07 11:53:19 -0500478}
479
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000480void Image::copy(Buffer *buffer, const VkBufferImageCopy &region, bool bufferIsSource)
Alexis Hetua233cea2018-12-07 11:53:19 -0500481{
Nicolas Capensba873302019-05-16 11:25:27 -0400482 switch(region.imageSubresource.aspectMask)
Alexis Hetua233cea2018-12-07 11:53:19 -0500483 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000484 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 Hetua233cea2018-12-07 11:53:19 -0500494 }
495
Chris Forbes529eda32019-05-08 10:27:05 -0700496 auto aspect = static_cast<VkImageAspectFlagBits>(region.imageSubresource.aspectMask);
Alexis Hetu979f9402019-03-27 11:33:15 -0400497 Format copyFormat = getFormat(aspect);
Chris Forbes9219c642019-05-07 07:30:01 -0700498
Alexis Hetu979f9402019-03-27 11:33:15 -0400499 VkExtent3D imageExtent = imageExtentInBlocks(region.imageExtent, aspect);
500 VkExtent2D bufferExtent = bufferExtentInBlocks({ imageExtent.width, imageExtent.height }, region);
Chris Forbes529eda32019-05-08 10:27:05 -0700501 int bytesPerBlock = copyFormat.bytesPerBlock();
502 int bufferRowPitchBytes = bufferExtent.width * bytesPerBlock;
503 int bufferSlicePitchBytes = bufferExtent.height * bufferRowPitchBytes;
Nicolas Capens2aace0d2020-07-02 16:35:23 -0400504 ASSERT(samples == 1);
Chris Forbes529eda32019-05-08 10:27:05 -0700505
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000506 uint8_t *bufferMemory = static_cast<uint8_t *>(buffer->getOffsetPointer(region.bufferOffset));
Alexis Hetu46159712020-06-15 16:13:51 -0400507 uint8_t *imageMemory = static_cast<uint8_t *>(getTexelPointer(region.imageOffset, { region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, region.imageSubresource.baseArrayLayer }));
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000508 uint8_t *srcMemory = bufferIsSource ? bufferMemory : imageMemory;
509 uint8_t *dstMemory = bufferIsSource ? imageMemory : bufferMemory;
Chris Forbes2995dc22019-03-02 14:57:20 -0800510 int imageRowPitchBytes = rowPitchBytes(aspect, region.imageSubresource.mipLevel);
511 int imageSlicePitchBytes = slicePitchBytes(aspect, region.imageSubresource.mipLevel);
Alexis Hetu753c67c2018-12-14 16:42:24 -0500512
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 Capensba873302019-05-16 11:25:27 -0400518 VkExtent3D mipLevelExtent = getMipLevelExtent(aspect, region.imageSubresource.mipLevel);
Nicolas Capensc55fd972020-07-02 16:35:23 -0400519 bool isSingleSlice = (imageExtent.depth == 1);
Nicolas Capensad658262020-07-03 10:06:27 -0400520 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 Clayton2ed93ab2019-12-17 20:38:03 +0000524 (imageSlicePitchBytes == bufferSlicePitchBytes);
Alexis Hetu04595962018-12-14 11:07:39 -0500525
Alexis Hetu753c67c2018-12-14 16:42:24 -0500526 VkDeviceSize copySize = 0;
Alexis Hetu377077a2019-03-14 15:10:51 -0400527 VkDeviceSize bufferLayerSize = 0;
Nicolas Capensad658262020-07-03 10:06:27 -0400528 if(isSingleRow)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500529 {
Chris Forbes529eda32019-05-08 10:27:05 -0700530 copySize = imageExtent.width * bytesPerBlock;
Alexis Hetu377077a2019-03-14 15:10:51 -0400531 bufferLayerSize = copySize;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500532 }
Nicolas Capensad658262020-07-03 10:06:27 -0400533 else if(isEntireRow && isSingleSlice)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500534 {
Alexis Hetu979f9402019-03-27 11:33:15 -0400535 copySize = imageExtent.height * imageRowPitchBytes;
Alexis Hetu377077a2019-03-14 15:10:51 -0400536 bufferLayerSize = copySize;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500537 }
Nicolas Capensc55fd972020-07-02 16:35:23 -0400538 else if(isEntireSlice)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500539 {
Nicolas Capensc55fd972020-07-02 16:35:23 -0400540 copySize = imageExtent.depth * imageSlicePitchBytes; // Copy multiple slices
Alexis Hetu377077a2019-03-14 15:10:51 -0400541 bufferLayerSize = copySize;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500542 }
Nicolas Capensad658262020-07-03 10:06:27 -0400543 else if(isEntireRow) // Copy slice by slice
Alexis Hetu753c67c2018-12-14 16:42:24 -0500544 {
Alexis Hetu979f9402019-03-27 11:33:15 -0400545 copySize = imageExtent.height * imageRowPitchBytes;
546 bufferLayerSize = copySize * imageExtent.depth;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500547 }
Nicolas Capensad658262020-07-03 10:06:27 -0400548 else // Copy row by row
Alexis Hetu753c67c2018-12-14 16:42:24 -0500549 {
Chris Forbes529eda32019-05-08 10:27:05 -0700550 copySize = imageExtent.width * bytesPerBlock;
Alexis Hetu979f9402019-03-27 11:33:15 -0400551 bufferLayerSize = copySize * imageExtent.depth * imageExtent.height;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500552 }
553
Alexis Hetu377077a2019-03-14 15:10:51 -0400554 VkDeviceSize imageLayerSize = getLayerSize(aspect);
555 VkDeviceSize srcLayerSize = bufferIsSource ? bufferLayerSize : imageLayerSize;
556 VkDeviceSize dstLayerSize = bufferIsSource ? imageLayerSize : bufferLayerSize;
557
Alexis Hetueca9ca62019-01-16 14:21:33 -0500558 for(uint32_t i = 0; i < region.imageSubresource.layerCount; i++)
Alexis Hetu04595962018-12-14 11:07:39 -0500559 {
Nicolas Capensad658262020-07-03 10:06:27 -0400560 if(isSingleRow || (isEntireRow && isSingleSlice) || isEntireSlice)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500561 {
Alexis Hetu377077a2019-03-14 15:10:51 -0400562 ASSERT(((bufferIsSource ? dstMemory : srcMemory) + copySize) < end());
563 ASSERT(((bufferIsSource ? srcMemory : dstMemory) + copySize) < buffer->end());
Alexis Hetu753c67c2018-12-14 16:42:24 -0500564 memcpy(dstMemory, srcMemory, copySize);
565 }
Nicolas Capensad658262020-07-03 10:06:27 -0400566 else if(isEntireRow) // Copy slice by slice
Alexis Hetu753c67c2018-12-14 16:42:24 -0500567 {
Nicolas Capensc55fd972020-07-02 16:35:23 -0400568 uint8_t *srcSliceMemory = srcMemory;
569 uint8_t *dstSliceMemory = dstMemory;
Alexis Hetu979f9402019-03-27 11:33:15 -0400570 for(uint32_t z = 0; z < imageExtent.depth; z++)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500571 {
Nicolas Capensc55fd972020-07-02 16:35:23 -0400572 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 Hetu753c67c2018-12-14 16:42:24 -0500577 }
578 }
Nicolas Capensad658262020-07-03 10:06:27 -0400579 else // Copy row by row
Alexis Hetu753c67c2018-12-14 16:42:24 -0500580 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000581 uint8_t *srcLayerMemory = srcMemory;
582 uint8_t *dstLayerMemory = dstMemory;
Alexis Hetu979f9402019-03-27 11:33:15 -0400583 for(uint32_t z = 0; z < imageExtent.depth; z++)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500584 {
Nicolas Capensc55fd972020-07-02 16:35:23 -0400585 uint8_t *srcSliceMemory = srcLayerMemory;
586 uint8_t *dstSliceMemory = dstLayerMemory;
Alexis Hetu979f9402019-03-27 11:33:15 -0400587 for(uint32_t y = 0; y < imageExtent.height; y++)
Alexis Hetu753c67c2018-12-14 16:42:24 -0500588 {
Nicolas Capensc55fd972020-07-02 16:35:23 -0400589 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 Hetu753c67c2018-12-14 16:42:24 -0500594 }
Alexis Hetu377077a2019-03-14 15:10:51 -0400595 srcLayerMemory += srcSlicePitchBytes;
596 dstLayerMemory += dstSlicePitchBytes;
Alexis Hetu753c67c2018-12-14 16:42:24 -0500597 }
598 }
599
Alexis Hetu377077a2019-03-14 15:10:51 -0400600 srcMemory += srcLayerSize;
601 dstMemory += dstLayerSize;
Alexis Hetu04595962018-12-14 11:07:39 -0500602 }
Alexis Hetuac873342019-04-17 15:59:03 -0400603
Chris Forbes9219c642019-05-07 07:30:01 -0700604 if(bufferIsSource)
605 {
Alexis Hetu4f438a52020-06-15 16:13:51 -0400606 contentsChanged({ region.imageSubresource.aspectMask, region.imageSubresource.mipLevel, 1,
607 region.imageSubresource.baseArrayLayer, region.imageSubresource.layerCount });
Alexis Hetuac873342019-04-17 15:59:03 -0400608 }
Alexis Hetua233cea2018-12-07 11:53:19 -0500609}
610
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000611void Image::copyTo(Buffer *dstBuffer, const VkBufferImageCopy &region)
Alexis Hetua233cea2018-12-07 11:53:19 -0500612{
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500613 copy(dstBuffer, region, false);
614}
615
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000616void Image::copyFrom(Buffer *srcBuffer, const VkBufferImageCopy &region)
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500617{
618 copy(srcBuffer, region, true);
619}
620
Alexis Hetu46159712020-06-15 16:13:51 -0400621void *Image::getTexelPointer(const VkOffset3D &offset, const VkImageSubresource &subresource) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500622{
Chris Forbes2995dc22019-03-02 14:57:20 -0800623 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
Alexis Hetueca9ca62019-01-16 14:21:33 -0500624 return deviceMemory->getOffsetPointer(texelOffsetBytesInStorage(offset, subresource) +
Alexis Hetu46159712020-06-15 16:13:51 -0400625 getMemoryOffset(aspect, subresource.mipLevel, subresource.arrayLayer));
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500626}
627
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000628VkExtent3D Image::imageExtentInBlocks(const VkExtent3D &extent, VkImageAspectFlagBits aspect) const
Alexis Hetu979f9402019-03-27 11:33:15 -0400629{
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 Hetu0839cbd2019-03-27 15:09:51 -0400638 // 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 Hetu979f9402019-03-27 11:33:15 -0400641 }
642 return adjustedExtent;
643}
644
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000645VkOffset3D Image::imageOffsetInBlocks(const VkOffset3D &offset, VkImageAspectFlagBits aspect) const
Alexis Hetu979f9402019-03-27 11:33:15 -0400646{
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 Clayton2ed93ab2019-12-17 20:38:03 +0000655 ASSERT(((offset.x % blockWidth) == 0) && ((offset.y % blockHeight) == 0)); // We can't offset within a block
Alexis Hetu979f9402019-03-27 11:33:15 -0400656
657 adjustedOffset.x /= blockWidth;
658 adjustedOffset.y /= blockHeight;
659 }
660 return adjustedOffset;
661}
662
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000663VkExtent2D Image::bufferExtentInBlocks(const VkExtent2D &extent, const VkBufferImageCopy &region) const
Alexis Hetu979f9402019-03-27 11:33:15 -0400664{
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 Capensba873302019-05-16 11:25:27 -0400693int Image::borderSize() const
Alexis Hetu6db9a892019-04-08 15:53:32 -0400694{
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 Hetu46159712020-06-15 16:13:51 -0400699VkDeviceSize Image::texelOffsetBytesInStorage(const VkOffset3D &offset, const VkImageSubresource &subresource) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500700{
Chris Forbes2995dc22019-03-02 14:57:20 -0800701 VkImageAspectFlagBits aspect = static_cast<VkImageAspectFlagBits>(subresource.aspectMask);
Alexis Hetu979f9402019-03-27 11:33:15 -0400702 VkOffset3D adjustedOffset = imageOffsetInBlocks(offset, aspect);
Nicolas Capensba873302019-05-16 11:25:27 -0400703 int border = borderSize();
Alexis Hetu979f9402019-03-27 11:33:15 -0400704 return adjustedOffset.z * slicePitchBytes(aspect, subresource.mipLevel) +
Alexis Hetu6db9a892019-04-08 15:53:32 -0400705 (adjustedOffset.y + border) * rowPitchBytes(aspect, subresource.mipLevel) +
706 (adjustedOffset.x + border) * getFormat(aspect).bytesPerBlock();
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500707}
708
Nicolas Capensba873302019-05-16 11:25:27 -0400709VkExtent3D Image::getMipLevelExtent(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500710{
Alexis Hetueca9ca62019-01-16 14:21:33 -0500711 VkExtent3D mipLevelExtent;
712 mipLevelExtent.width = extent.width >> mipLevel;
713 mipLevelExtent.height = extent.height >> mipLevel;
714 mipLevelExtent.depth = extent.depth >> mipLevel;
715
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000716 if(mipLevelExtent.width == 0) { mipLevelExtent.width = 1; }
Nicolas Capens7e01e4e2019-05-18 08:19:07 -0400717 if(mipLevelExtent.height == 0) { mipLevelExtent.height = 1; }
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000718 if(mipLevelExtent.depth == 0) { mipLevelExtent.depth = 1; }
Nicolas Capensba873302019-05-16 11:25:27 -0400719
720 switch(aspect)
Alexis Hetua233cea2018-12-07 11:53:19 -0500721 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000722 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 Capensba873302019-05-16 11:25:27 -0400742 break;
743 default:
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000744 UNSUPPORTED("aspect %x", int(aspect));
Alexis Hetua233cea2018-12-07 11:53:19 -0500745 }
Nicolas Capensba873302019-05-16 11:25:27 -0400746
Alexis Hetueca9ca62019-01-16 14:21:33 -0500747 return mipLevelExtent;
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500748}
Alexis Hetu04595962018-12-14 11:07:39 -0500749
Chris Forbes2995dc22019-03-02 14:57:20 -0800750int Image::rowPitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500751{
752 // Depth and Stencil pitch should be computed separately
Chris Forbes2995dc22019-03-02 14:57:20 -0800753 ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000754 (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
Nicolas Capensba873302019-05-16 11:25:27 -0400755
Alexis Hetu1b900872020-02-24 12:09:16 -0500756 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 Hetue0b5a4b2018-12-14 12:11:02 -0500765}
766
Chris Forbes2995dc22019-03-02 14:57:20 -0800767int Image::slicePitchBytes(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500768{
769 // Depth and Stencil slice should be computed separately
Chris Forbes2995dc22019-03-02 14:57:20 -0800770 ASSERT((aspect & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) !=
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000771 (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT));
Nicolas Capensba873302019-05-16 11:25:27 -0400772
773 VkExtent3D mipLevelExtent = getMipLevelExtent(aspect, mipLevel);
Alexis Hetu0839cbd2019-03-27 15:09:51 -0400774 Format usedFormat = getFormat(aspect);
775 if(usedFormat.isCompressed())
776 {
Alexis Hetu1b900872020-02-24 12:09:16 -0500777 VkExtent3D extentInBlocks = imageExtentInBlocks(mipLevelExtent, aspect);
778 return extentInBlocks.height * extentInBlocks.width * usedFormat.bytesPerBlock();
Alexis Hetu0839cbd2019-03-27 15:09:51 -0400779 }
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500780
Nicolas Capensba873302019-05-16 11:25:27 -0400781 return usedFormat.sliceB(mipLevelExtent.width, mipLevelExtent.height, borderSize(), true);
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500782}
783
Alexis Hetu6a1d92b2019-03-11 17:34:13 -0400784Format Image::getFormat(VkImageAspectFlagBits aspect) const
Alexis Hetue0b5a4b2018-12-14 12:11:02 -0500785{
Nicolas Capenscfe11c72019-05-16 09:58:26 -0400786 return format.getAspectFormat(aspect);
Alexis Hetua233cea2018-12-07 11:53:19 -0500787}
788
Alexis Hetued303732019-01-16 15:47:19 -0500789bool Image::isCube() const
Alexis Hetua233cea2018-12-07 11:53:19 -0500790{
Alexis Hetued303732019-01-16 15:47:19 -0500791 return (flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) && (imageType == VK_IMAGE_TYPE_2D);
Alexis Hetua233cea2018-12-07 11:53:19 -0500792}
793
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000794uint8_t *Image::end() const
Alexis Hetu377077a2019-03-14 15:10:51 -0400795{
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000796 return reinterpret_cast<uint8_t *>(deviceMemory->getOffsetPointer(deviceMemory->getCommittedMemoryInBytes() + 1));
Alexis Hetu377077a2019-03-14 15:10:51 -0400797}
798
Chris Forbes2995dc22019-03-02 14:57:20 -0800799VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect) const
Alexis Hetua233cea2018-12-07 11:53:19 -0500800{
Alexis Hetueca9ca62019-01-16 14:21:33 -0500801 switch(format)
Alexis Hetua233cea2018-12-07 11:53:19 -0500802 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000803 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 Capensba873302019-05-16 11:25:27 -0400812
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000813 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 Capensba873302019-05-16 11:25:27 -0400827
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000828 return memoryOffset;
829 }
830 break;
Nicolas Capensba873302019-05-16 11:25:27 -0400831
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000832 default:
833 break;
Alexis Hetua233cea2018-12-07 11:53:19 -0500834 }
835
Alexis Hetueca9ca62019-01-16 14:21:33 -0500836 return memoryOffset;
837}
838
Chris Forbes2995dc22019-03-02 14:57:20 -0800839VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500840{
Chris Forbes2995dc22019-03-02 14:57:20 -0800841 VkDeviceSize offset = getMemoryOffset(aspect);
Alexis Hetueca9ca62019-01-16 14:21:33 -0500842 for(uint32_t i = 0; i < mipLevel; ++i)
843 {
Alexis Hetu54ec7592019-03-20 14:37:16 -0400844 offset += getMultiSampledLevelSize(aspect, i);
Alexis Hetueca9ca62019-01-16 14:21:33 -0500845 }
846 return offset;
847}
848
Chris Forbes2995dc22019-03-02 14:57:20 -0800849VkDeviceSize Image::getMemoryOffset(VkImageAspectFlagBits aspect, uint32_t mipLevel, uint32_t layer) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500850{
Alexis Hetu32ac8312019-04-15 17:20:29 -0400851 return layer * getLayerOffset(aspect, mipLevel) + getMemoryOffset(aspect, mipLevel);
Alexis Hetueca9ca62019-01-16 14:21:33 -0500852}
853
Chris Forbes2995dc22019-03-02 14:57:20 -0800854VkDeviceSize Image::getMipLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500855{
Nicolas Capensba873302019-05-16 11:25:27 -0400856 return getMipLevelExtent(aspect, mipLevel).depth * slicePitchBytes(aspect, mipLevel);
Alexis Hetua233cea2018-12-07 11:53:19 -0500857}
858
Alexis Hetu54ec7592019-03-20 14:37:16 -0400859VkDeviceSize Image::getMultiSampledLevelSize(VkImageAspectFlagBits aspect, uint32_t mipLevel) const
860{
861 return getMipLevelSize(aspect, mipLevel) * samples;
862}
863
Alexis Hetu32ac8312019-04-15 17:20:29 -0400864bool Image::is3DSlice() const
865{
866 return ((imageType == VK_IMAGE_TYPE_3D) && (flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT));
867}
868
869VkDeviceSize 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 Forbes9219c642019-05-07 07:30:01 -0700874 // image's mip level in order to create a 2D or 2D array image view of a 3D image created with
Alexis Hetu32ac8312019-04-15 17:20:29 -0400875 // 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 Forbes2995dc22019-03-02 14:57:20 -0800886VkDeviceSize Image::getLayerSize(VkImageAspectFlagBits aspect) const
Alexis Hetu809d0112018-12-17 17:00:28 -0500887{
Alexis Hetueca9ca62019-01-16 14:21:33 -0500888 VkDeviceSize layerSize = 0;
889
890 for(uint32_t mipLevel = 0; mipLevel < mipLevels; ++mipLevel)
891 {
Alexis Hetu54ec7592019-03-20 14:37:16 -0400892 layerSize += getMultiSampledLevelSize(aspect, mipLevel);
Alexis Hetueca9ca62019-01-16 14:21:33 -0500893 }
894
895 return layerSize;
896}
897
Chris Forbes2995dc22019-03-02 14:57:20 -0800898VkDeviceSize Image::getStorageSize(VkImageAspectFlags aspectMask) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500899{
Nicolas Capensba873302019-05-16 11:25:27 -0400900 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 Forbes2995dc22019-03-02 14:57:20 -0800902 {
Nicolas Capensba873302019-05-16 11:25:27 -0400903 UNSUPPORTED("aspectMask %x", int(aspectMask));
Chris Forbes2995dc22019-03-02 14:57:20 -0800904 }
Nicolas Capensba873302019-05-16 11:25:27 -0400905
906 VkDeviceSize storageSize = 0;
907
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000908 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 Capensba873302019-05-16 11:25:27 -0400910 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 Hetueca9ca62019-01-16 14:21:33 -0500916}
917
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000918const Image *Image::getSampledImage(const vk::Format &imageViewFormat) const
Alexis Hetu62ad1ee2019-05-16 14:20:16 -0400919{
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 Capens32f4be12020-06-10 13:14:07 -0400933void Image::blitTo(Image *dstImage, const VkImageBlit &region, VkFilter filter) const
Alexis Hetu809d0112018-12-17 17:00:28 -0500934{
Alexis Hetu63ae9242019-06-06 13:52:15 -0400935 device->getBlitter()->blit(this, dstImage, region, filter);
Alexis Hetu809d0112018-12-17 17:00:28 -0500936}
937
Nicolas Capens32f4be12020-06-10 13:14:07 -0400938void Image::copyTo(uint8_t *dst, unsigned int dstPitch) const
Antonio Maiorano26c6c4a2019-10-17 15:33:47 -0400939{
Nicolas Capens32f4be12020-06-10 13:14:07 -0400940 device->getBlitter()->copy(this, dst, dstPitch);
Antonio Maiorano26c6c4a2019-10-17 15:33:47 -0400941}
942
Nicolas Capens32f4be12020-06-10 13:14:07 -0400943void Image::resolveTo(Image *dstImage, const VkImageResolve &region) const
Alexis Hetue5e33cd2019-04-11 10:24:52 -0400944{
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 Hetu63ae9242019-06-06 13:52:15 -0400960 device->getBlitter()->blit(this, dstImage, blitRegion, VK_FILTER_NEAREST);
Alexis Hetue5e33cd2019-04-11 10:24:52 -0400961}
962
Alexis Hetueca9ca62019-01-16 14:21:33 -0500963VkFormat Image::getClearFormat() const
Alexis Hetu9fbaf692018-11-19 11:30:43 -0500964{
Alexis Hetueca9ca62019-01-16 14:21:33 -0500965 // 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 Capens9d9f30d2020-01-12 03:26:18 -0500967 if(format.isSignedUnnormalizedInteger())
Alexis Hetueca9ca62019-01-16 14:21:33 -0500968 {
969 return VK_FORMAT_R32G32B32A32_SINT;
970 }
Nicolas Capens9d9f30d2020-01-12 03:26:18 -0500971 else if(format.isUnsignedUnnormalizedInteger())
Alexis Hetueca9ca62019-01-16 14:21:33 -0500972 {
973 return VK_FORMAT_R32G32B32A32_UINT;
974 }
975
976 return VK_FORMAT_R32G32B32A32_SFLOAT;
977}
978
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000979uint32_t Image::getLastLayerIndex(const VkImageSubresourceRange &subresourceRange) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500980{
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000981 return ((subresourceRange.layerCount == VK_REMAINING_ARRAY_LAYERS) ? arrayLayers : (subresourceRange.baseArrayLayer + subresourceRange.layerCount)) - 1;
Alexis Hetueca9ca62019-01-16 14:21:33 -0500982}
983
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000984uint32_t Image::getLastMipLevel(const VkImageSubresourceRange &subresourceRange) const
Alexis Hetueca9ca62019-01-16 14:21:33 -0500985{
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000986 return ((subresourceRange.levelCount == VK_REMAINING_MIP_LEVELS) ? mipLevels : (subresourceRange.baseMipLevel + subresourceRange.levelCount)) - 1;
Alexis Hetueca9ca62019-01-16 14:21:33 -0500987}
988
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000989void Image::clear(void *pixelData, VkFormat pixelFormat, const vk::Format &viewFormat, const VkImageSubresourceRange &subresourceRange, const VkRect2D &renderArea)
Alexis Hetu75211502019-01-18 16:08:45 -0500990{
Alexis Hetu04dae5e2019-04-08 13:41:50 -0400991 device->getBlitter()->clear(pixelData, pixelFormat, this, viewFormat, subresourceRange, &renderArea);
Alexis Hetu75211502019-01-18 16:08:45 -0500992}
993
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000994void Image::clear(const VkClearColorValue &color, const VkImageSubresourceRange &subresourceRange)
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -0500995{
Nicolas Capensdd0e6002020-01-24 01:21:47 -0500996 ASSERT(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -0500997
Ben Clayton2ed93ab2019-12-17 20:38:03 +0000998 device->getBlitter()->clear((void *)color.float32, getClearFormat(), this, format, subresourceRange);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -0500999}
1000
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001001void Image::clear(const VkClearDepthStencilValue &color, const VkImageSubresourceRange &subresourceRange)
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001002{
Nicolas Capensdd0e6002020-01-24 01:21:47 -05001003 ASSERT((subresourceRange.aspectMask & ~(VK_IMAGE_ASPECT_DEPTH_BIT |
1004 VK_IMAGE_ASPECT_STENCIL_BIT)) == 0);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001005
1006 if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
1007 {
Alexis Hetu33642272019-03-01 11:55:59 -05001008 VkImageSubresourceRange depthSubresourceRange = subresourceRange;
1009 depthSubresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001010 device->getBlitter()->clear((void *)(&color.depth), VK_FORMAT_D32_SFLOAT, this, format, depthSubresourceRange);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001011 }
1012
1013 if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
1014 {
Alexis Hetu33642272019-03-01 11:55:59 -05001015 VkImageSubresourceRange stencilSubresourceRange = subresourceRange;
1016 stencilSubresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001017 device->getBlitter()->clear((void *)(&color.stencil), VK_FORMAT_S8_UINT, this, format, stencilSubresourceRange);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001018 }
1019}
1020
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001021void Image::clear(const VkClearValue &clearValue, const vk::Format &viewFormat, const VkRect2D &renderArea, const VkImageSubresourceRange &subresourceRange)
Alexis Hetueca9ca62019-01-16 14:21:33 -05001022{
Nicolas Capensdd0e6002020-01-24 01:21:47 -05001023 ASSERT((subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT) ||
1024 (subresourceRange.aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT |
1025 VK_IMAGE_ASPECT_STENCIL_BIT)));
Alexis Hetucaea0ba2018-12-07 16:20:44 -05001026
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001027 if(subresourceRange.aspectMask == VK_IMAGE_ASPECT_COLOR_BIT)
1028 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001029 clear((void *)(clearValue.color.float32), getClearFormat(), viewFormat, subresourceRange, renderArea);
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001030 }
1031 else
1032 {
Alexis Hetu75211502019-01-18 16:08:45 -05001033 if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT)
1034 {
Alexis Hetu33642272019-03-01 11:55:59 -05001035 VkImageSubresourceRange depthSubresourceRange = subresourceRange;
1036 depthSubresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001037 clear((void *)(&clearValue.depthStencil.depth), VK_FORMAT_D32_SFLOAT, viewFormat, depthSubresourceRange, renderArea);
Alexis Hetu75211502019-01-18 16:08:45 -05001038 }
1039
1040 if(subresourceRange.aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)
1041 {
Alexis Hetu33642272019-03-01 11:55:59 -05001042 VkImageSubresourceRange stencilSubresourceRange = subresourceRange;
1043 stencilSubresourceRange.aspectMask = VK_IMAGE_ASPECT_STENCIL_BIT;
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001044 clear((void *)(&clearValue.depthStencil.stencil), VK_FORMAT_S8_UINT, viewFormat, stencilSubresourceRange, renderArea);
Alexis Hetu75211502019-01-18 16:08:45 -05001045 }
Alexis Hetu7ca9f4a2019-01-17 14:51:43 -05001046 }
Alexis Hetu9fbaf692018-11-19 11:30:43 -05001047}
1048
Alexis Hetu4f438a52020-06-15 16:13:51 -04001049bool Image::requiresPreprocessing() const
Alexis Hetuac873342019-04-17 15:59:03 -04001050{
Alexis Hetu4f438a52020-06-15 16:13:51 -04001051 return (isCube() && (arrayLayers >= 6)) || decompressedImage;
1052}
1053
1054void 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 Hetu46159712020-06-15 16:13:51 -04001072 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 Hetu4f438a52020-06-15 16:13:51 -04001081 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
1095void 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 Hetu46159712020-06-15 16:13:51 -04001119 // 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 Hetu4f438a52020-06-15 16:13:51 -04001128 auto it = dirtySubresources.find(subresource);
1129 if(it != dirtySubresources.end())
1130 {
1131 decompress(subresource);
1132 }
Alexis Hetu46159712020-06-15 16:13:51 -04001133 }
1134 }
1135
1136 // Second, update cubemap borders
Alexis Hetu4f438a52020-06-15 16:13:51 -04001137 for(subresource.arrayLayer = subresourceRange.baseArrayLayer;
1138 subresource.arrayLayer <= lastLayer;
1139 subresource.arrayLayer++)
Alexis Hetu46159712020-06-15 16:13:51 -04001140 {
Alexis Hetu4f438a52020-06-15 16:13:51 -04001141 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 Hetu46159712020-06-15 16:13:51 -04001184 }
1185}
1186
1187void Image::decompress(const VkImageSubresource &subresource)
1188{
Alexis Hetub317d962019-04-29 14:07:31 -04001189 if(decompressedImage)
Alexis Hetuac873342019-04-17 15:59:03 -04001190 {
Alexis Hetub317d962019-04-29 14:07:31 -04001191 switch(format)
1192 {
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001193 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 Hetu46159712020-06-15 16:13:51 -04001203 decodeETC2(subresource);
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001204 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 Clayton5751f9e2020-03-11 10:41:32 +00001217 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 Hetu46159712020-06-15 16:13:51 -04001221 decodeBC(subresource);
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001222 break;
Alexis Hetu1b900872020-02-24 12:09:16 -05001223 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 Hetu46159712020-06-15 16:13:51 -04001251 decodeASTC(subresource);
Alexis Hetu1b900872020-02-24 12:09:16 -05001252 break;
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001253 default:
1254 break;
Alexis Hetub317d962019-04-29 14:07:31 -04001255 }
1256 }
Alexis Hetu46159712020-06-15 16:13:51 -04001257}
Alexis Hetub317d962019-04-29 14:07:31 -04001258
Alexis Hetu4f438a52020-06-15 16:13:51 -04001259bool Image::updateCube(const VkImageSubresource &subres)
Alexis Hetu46159712020-06-15 16:13:51 -04001260{
Alexis Hetub317d962019-04-29 14:07:31 -04001261 if(isCube() && (arrayLayers >= 6))
1262 {
Alexis Hetu46159712020-06-15 16:13:51 -04001263 VkImageSubresource subresource = subres;
Corentin Wallez8def9062020-02-18 16:36:56 +01001264
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 Hetu46159712020-06-15 16:13:51 -04001267 for(subresource.arrayLayer = 0; subresource.arrayLayer < arrayLayers - 5; subresource.arrayLayer += 6)
Alexis Hetub317d962019-04-29 14:07:31 -04001268 {
Alexis Hetu46159712020-06-15 16:13:51 -04001269 device->getBlitter()->updateBorders(decompressedImage ? decompressedImage : this, subresource);
Alexis Hetub317d962019-04-29 14:07:31 -04001270 }
Alexis Hetu4f438a52020-06-15 16:13:51 -04001271
1272 return true;
Alexis Hetuac873342019-04-17 15:59:03 -04001273 }
Alexis Hetu4f438a52020-06-15 16:13:51 -04001274
1275 return false;
Alexis Hetuac873342019-04-17 15:59:03 -04001276}
1277
Alexis Hetu46159712020-06-15 16:13:51 -04001278void Image::decodeETC2(const VkImageSubresource &subresource)
Alexis Hetuac873342019-04-17 15:59:03 -04001279{
1280 ASSERT(decompressedImage);
1281
1282 ETC_Decoder::InputType inputType = GetInputType(format);
1283
Alexis Hetu8b7597e2019-05-06 15:14:21 -04001284 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 Hetu46159712020-06-15 16:13:51 -04001288 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 Hetuac873342019-04-17 15:59:03 -04001293 {
Alexis Hetu46159712020-06-15 16:13:51 -04001294 // 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 Hetuac873342019-04-17 15:59:03 -04001306 {
Alexis Hetu46159712020-06-15 16:13:51 -04001307 ASSERT((dest + sizeToWrite) < decompressedImage->end());
1308 memset(dest, 0xFF, sizeToWrite);
Alexis Hetuac873342019-04-17 15:59:03 -04001309 }
Alexis Hetu46159712020-06-15 16:13:51 -04001310
1311 ETC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height,
1312 pitchB, bytes, inputType);
Alexis Hetuac873342019-04-17 15:59:03 -04001313 }
1314}
1315
Alexis Hetu46159712020-06-15 16:13:51 -04001316void Image::decodeBC(const VkImageSubresource &subresource)
Alexis Hetuc77b1d82019-12-11 11:43:44 -05001317{
1318 ASSERT(decompressedImage);
1319
1320 int n = GetBCn(format);
1321 int noAlphaU = GetNoAlphaOrUnsigned(format);
1322
Alexis Hetuc77b1d82019-12-11 11:43:44 -05001323 int bytes = decompressedImage->format.bytes();
1324
Alexis Hetu46159712020-06-15 16:13:51 -04001325 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 Hetuc77b1d82019-12-11 11:43:44 -05001330 {
Alexis Hetu46159712020-06-15 16:13:51 -04001331 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 Hetuc77b1d82019-12-11 11:43:44 -05001333
Alexis Hetu46159712020-06-15 16:13:51 -04001334 BC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height,
1335 pitchB, bytes, n, noAlphaU);
Alexis Hetuc77b1d82019-12-11 11:43:44 -05001336 }
1337}
1338
Alexis Hetu46159712020-06-15 16:13:51 -04001339void Image::decodeASTC(const VkImageSubresource &subresource)
Alexis Hetu1b900872020-02-24 12:09:16 -05001340{
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 Hetu1b900872020-02-24 12:09:16 -05001348 int bytes = decompressedImage->format.bytes();
1349
Alexis Hetu46159712020-06-15 16:13:51 -04001350 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 Hetu1b900872020-02-24 12:09:16 -05001357 {
Alexis Hetu46159712020-06-15 16:13:51 -04001358 return;
1359 }
Alexis Hetu1b900872020-02-24 12:09:16 -05001360
Alexis Hetu46159712020-06-15 16:13:51 -04001361 int pitchB = decompressedImage->rowPitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel);
1362 int sliceB = decompressedImage->slicePitchBytes(VK_IMAGE_ASPECT_COLOR_BIT, subresource.mipLevel);
Alexis Hetu1b900872020-02-24 12:09:16 -05001363
Alexis Hetu46159712020-06-15 16:13:51 -04001364 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 Hetu1b900872020-02-24 12:09:16 -05001368
Alexis Hetu46159712020-06-15 16:13:51 -04001369 ASTC_Decoder::Decode(source, dest, mipLevelExtent.width, mipLevelExtent.height, mipLevelExtent.depth, bytes, pitchB, sliceB,
1370 xBlockSize, yBlockSize, zBlockSize, xblocks, yblocks, zblocks, isUnsigned);
Alexis Hetu1b900872020-02-24 12:09:16 -05001371 }
1372}
1373
Ben Clayton2ed93ab2019-12-17 20:38:03 +00001374} // namespace vk