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