blob: d35c4adde46d01f5e79fa0cb47251cc08bee74d1 [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "third_party/blink/renderer/modules/webgpu/texture_utils.h"
#include "third_party/blink/renderer/modules/webgpu/gpu_device.h"
namespace blink {
namespace {
struct TexelBlockInfo {
uint32_t byteSize;
uint32_t width;
uint32_t height;
};
TexelBlockInfo GetTexelBlockInfoForCopy(WGPUTextureFormat format,
WGPUTextureAspect aspect) {
constexpr TexelBlockInfo kInvalidTexelBlockInfo = {0, 0, 0};
switch (aspect) {
case WGPUTextureAspect_All:
switch (format) {
case WGPUTextureFormat_R8Unorm:
case WGPUTextureFormat_R8Snorm:
case WGPUTextureFormat_R8Uint:
case WGPUTextureFormat_R8Sint:
return {1u, 1u, 1u};
case WGPUTextureFormat_R16Uint:
case WGPUTextureFormat_R16Sint:
case WGPUTextureFormat_R16Float:
case WGPUTextureFormat_RG8Unorm:
case WGPUTextureFormat_RG8Snorm:
case WGPUTextureFormat_RG8Uint:
case WGPUTextureFormat_RG8Sint:
return {2u, 1u, 1u};
case WGPUTextureFormat_R32Float:
case WGPUTextureFormat_R32Uint:
case WGPUTextureFormat_R32Sint:
case WGPUTextureFormat_RG16Uint:
case WGPUTextureFormat_RG16Sint:
case WGPUTextureFormat_RG16Float:
case WGPUTextureFormat_RGBA8Unorm:
case WGPUTextureFormat_RGBA8UnormSrgb:
case WGPUTextureFormat_RGBA8Snorm:
case WGPUTextureFormat_RGBA8Uint:
case WGPUTextureFormat_RGBA8Sint:
case WGPUTextureFormat_BGRA8Unorm:
case WGPUTextureFormat_BGRA8UnormSrgb:
case WGPUTextureFormat_RGB10A2Unorm:
case WGPUTextureFormat_RG11B10Ufloat:
case WGPUTextureFormat_RGB9E5Ufloat:
return {4u, 1u, 1u};
case WGPUTextureFormat_RG32Float:
case WGPUTextureFormat_RG32Uint:
case WGPUTextureFormat_RG32Sint:
case WGPUTextureFormat_RGBA16Uint:
case WGPUTextureFormat_RGBA16Sint:
case WGPUTextureFormat_RGBA16Float:
return {8u, 1u, 1u};
case WGPUTextureFormat_RGBA32Float:
case WGPUTextureFormat_RGBA32Uint:
case WGPUTextureFormat_RGBA32Sint:
return {16u, 1u, 1u};
case WGPUTextureFormat_Depth16Unorm:
return {2u, 1u, 1u};
case WGPUTextureFormat_Stencil8:
return {1u, 1u, 1u};
case WGPUTextureFormat_BC1RGBAUnorm:
case WGPUTextureFormat_BC1RGBAUnormSrgb:
case WGPUTextureFormat_BC4RUnorm:
case WGPUTextureFormat_BC4RSnorm:
return {8u, 4u, 4u};
case WGPUTextureFormat_BC2RGBAUnorm:
case WGPUTextureFormat_BC2RGBAUnormSrgb:
case WGPUTextureFormat_BC3RGBAUnorm:
case WGPUTextureFormat_BC3RGBAUnormSrgb:
case WGPUTextureFormat_BC5RGUnorm:
case WGPUTextureFormat_BC5RGSnorm:
case WGPUTextureFormat_BC6HRGBUfloat:
case WGPUTextureFormat_BC6HRGBFloat:
case WGPUTextureFormat_BC7RGBAUnorm:
case WGPUTextureFormat_BC7RGBAUnormSrgb:
return {16u, 4u, 4u};
case WGPUTextureFormat_ETC2RGB8Unorm:
case WGPUTextureFormat_ETC2RGB8UnormSrgb:
case WGPUTextureFormat_ETC2RGB8A1Unorm:
case WGPUTextureFormat_ETC2RGB8A1UnormSrgb:
case WGPUTextureFormat_EACR11Unorm:
case WGPUTextureFormat_EACR11Snorm:
return {8u, 4u, 4u};
case WGPUTextureFormat_ETC2RGBA8Unorm:
case WGPUTextureFormat_ETC2RGBA8UnormSrgb:
case WGPUTextureFormat_EACRG11Unorm:
case WGPUTextureFormat_EACRG11Snorm:
return {16u, 4u, 4u};
case WGPUTextureFormat_ASTC4x4Unorm:
case WGPUTextureFormat_ASTC4x4UnormSrgb:
return {16u, 4u, 4u};
case WGPUTextureFormat_ASTC5x4Unorm:
case WGPUTextureFormat_ASTC5x4UnormSrgb:
return {16u, 5u, 4u};
case WGPUTextureFormat_ASTC5x5Unorm:
case WGPUTextureFormat_ASTC5x5UnormSrgb:
return {16u, 5u, 5u};
case WGPUTextureFormat_ASTC6x5Unorm:
case WGPUTextureFormat_ASTC6x5UnormSrgb:
return {16u, 6u, 5u};
case WGPUTextureFormat_ASTC6x6Unorm:
case WGPUTextureFormat_ASTC6x6UnormSrgb:
return {16u, 6u, 6u};
case WGPUTextureFormat_ASTC8x5Unorm:
case WGPUTextureFormat_ASTC8x5UnormSrgb:
return {16u, 8u, 5u};
case WGPUTextureFormat_ASTC8x6Unorm:
case WGPUTextureFormat_ASTC8x6UnormSrgb:
return {16u, 8u, 6u};
case WGPUTextureFormat_ASTC8x8Unorm:
case WGPUTextureFormat_ASTC8x8UnormSrgb:
return {16u, 8u, 8u};
case WGPUTextureFormat_ASTC10x5Unorm:
case WGPUTextureFormat_ASTC10x5UnormSrgb:
return {16u, 10u, 5u};
case WGPUTextureFormat_ASTC10x6Unorm:
case WGPUTextureFormat_ASTC10x6UnormSrgb:
return {16u, 10u, 6u};
case WGPUTextureFormat_ASTC10x8Unorm:
case WGPUTextureFormat_ASTC10x8UnormSrgb:
return {16u, 10u, 8u};
case WGPUTextureFormat_ASTC10x10Unorm:
case WGPUTextureFormat_ASTC10x10UnormSrgb:
return {16u, 10u, 10u};
case WGPUTextureFormat_ASTC12x10Unorm:
case WGPUTextureFormat_ASTC12x10UnormSrgb:
return {16u, 12u, 10u};
case WGPUTextureFormat_ASTC12x12Unorm:
case WGPUTextureFormat_ASTC12x12UnormSrgb:
return {16u, 12u, 12u};
default:
return kInvalidTexelBlockInfo;
}
// Copies to depth/stencil aspects are fairly restricted, see
// https://gpuweb.github.io/gpuweb/#depth-formats so we only list
// combinations of format and aspects that can be copied to with a
// WriteTexture.
case WGPUTextureAspect_DepthOnly:
switch (format) {
case WGPUTextureFormat_Depth16Unorm:
return GetTexelBlockInfoForCopy(format, WGPUTextureAspect_All);
default:
return kInvalidTexelBlockInfo;
}
case WGPUTextureAspect_StencilOnly:
switch (format) {
case WGPUTextureFormat_Depth24PlusStencil8:
case WGPUTextureFormat_Depth32FloatStencil8:
return {1u, 1u, 1u};
case WGPUTextureFormat_Stencil8:
return GetTexelBlockInfoForCopy(format, WGPUTextureAspect_All);
default:
return kInvalidTexelBlockInfo;
}
default:
NOTREACHED();
return kInvalidTexelBlockInfo;
}
}
} // anonymous namespace
size_t EstimateWriteTextureBytesUpperBound(WGPUTextureDataLayout layout,
WGPUExtent3D extent,
WGPUTextureFormat format,
WGPUTextureAspect aspect) {
// Check for empty copies because of depth first so we can early out. Note
// that we can't early out because of height or width being 0 because padding
// images still need to be accounted for.
if (extent.depthOrArrayLayers == 0) {
return 0;
}
TexelBlockInfo blockInfo = GetTexelBlockInfoForCopy(format, aspect);
// Unknown format/aspect combination will be validated by the GPU process
// again.
if (blockInfo.byteSize == 0) {
return 0;
}
// If the block size doesn't divide the extent, a validation error will be
// produced on the GPU process side so we don't need to guard against it.
uint32_t widthInBlocks = extent.width / blockInfo.width;
uint32_t heightInBlocks = extent.height / blockInfo.height;
// Use checked numerics even though the GPU process will guard against OOB
// because otherwise UBSan will complain about overflows. Note that if
// bytesPerRow or rowsPerImage are WGPU_COPY_STRIDE_UNDEFINED and used, the
// GPU process will also create a validation error because it means that they
// are used when copySize.height/depthOrArrayLayers > 1.
base::CheckedNumeric<size_t> requiredBytesInCopy = 0;
// WebGPU requires that the padding bytes for images are counted, even if the
// copy is empty.
if (extent.depthOrArrayLayers > 1) {
requiredBytesInCopy = layout.bytesPerRow;
requiredBytesInCopy *= layout.rowsPerImage;
requiredBytesInCopy *= (extent.depthOrArrayLayers - 1);
}
if (heightInBlocks != 0) {
base::CheckedNumeric<size_t> lastRowBytes = widthInBlocks;
lastRowBytes *= blockInfo.byteSize;
base::CheckedNumeric<size_t> lastImageBytes = layout.bytesPerRow;
lastImageBytes *= (heightInBlocks - 1);
lastImageBytes += lastRowBytes;
requiredBytesInCopy += lastImageBytes;
}
return requiredBytesInCopy.ValueOrDefault(0);
}
} // namespace blink