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