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 ®ion) 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 ®ion) 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 ®ion)
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 ®ion)
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 ®ion)
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 ®ion)
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 ®ion, 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 ®ion) 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