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