Add validations on the creation of textures in BC formats
This patch adds all the BC compressed texture formats and the checks on the creation of textures in BC formats. If a texture is in BC format, then: 1. The width and height of the texture must be multiple of 4. 2. The usage of the texture can only be Sampled or TransferSrc or TransferDst. 3. The sample count of the texture can only be 1. BUG=dawn:42 TEST=dawn_unittests Change-Id: I0844fb6a1aadbb96d94a61fd969db07c21b6adf5 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/7600 Commit-Queue: Kai Ninomiya <kainino@chromium.org> Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
parent
8dfc593eb7
commit
c2750abd0c
19
dawn.json
19
dawn.json
|
@ -1010,7 +1010,24 @@
|
||||||
{"value": 4, "name": "r8 g8 uint"},
|
{"value": 4, "name": "r8 g8 uint"},
|
||||||
{"value": 5, "name": "r8 uint"},
|
{"value": 5, "name": "r8 uint"},
|
||||||
{"value": 6, "name": "b8 g8 r8 a8 unorm"},
|
{"value": 6, "name": "b8 g8 r8 a8 unorm"},
|
||||||
{"value": 7, "name": "d32 float s8 uint"}
|
{"value": 7, "name": "d32 float s8 uint"},
|
||||||
|
{"value": 8, "name": "BC1 RGBA unorm"},
|
||||||
|
{"value": 9, "name": "BC1 RGBA unorm srgb"},
|
||||||
|
{"value": 10, "name": "BC2 RGBA unorm"},
|
||||||
|
{"value": 11, "name": "BC2 RGBA unorm srgb"},
|
||||||
|
{"value": 12, "name": "BC3 RGBA unorm"},
|
||||||
|
{"value": 13, "name": "BC3 RGBA unorm srgb"},
|
||||||
|
{"value": 14, "name": "BC4 R unorm"},
|
||||||
|
{"value": 15, "name": "BC4 R snorm"},
|
||||||
|
{"value": 16, "name": "BC5 RG unorm"},
|
||||||
|
{"value": 17, "name": "BC5 RG snorm"},
|
||||||
|
{"value": 18, "name": "BC6H RGB ufloat"},
|
||||||
|
{"value": 19, "name": "BC6H RGB sfloat"},
|
||||||
|
{"value": 20, "name": "BC7 RGBA unorm"},
|
||||||
|
{"value": 21, "name": "BC7 RGBA unorm srgb"}
|
||||||
|
],
|
||||||
|
"TODO": [
|
||||||
|
"jiawei.shao@intel.com: support BC formats as extension"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"texture usage bit": {
|
"texture usage bit": {
|
||||||
|
|
|
@ -85,6 +85,40 @@ namespace dawn_native {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsBCFormat(dawn::TextureFormat format) {
|
||||||
|
switch (format) {
|
||||||
|
case dawn::TextureFormat::BC1RGBAUnorm:
|
||||||
|
case dawn::TextureFormat::BC1RGBAUnormSrgb:
|
||||||
|
case dawn::TextureFormat::BC2RGBAUnorm:
|
||||||
|
case dawn::TextureFormat::BC2RGBAUnormSrgb:
|
||||||
|
case dawn::TextureFormat::BC3RGBAUnorm:
|
||||||
|
case dawn::TextureFormat::BC3RGBAUnormSrgb:
|
||||||
|
case dawn::TextureFormat::BC4RUnorm:
|
||||||
|
case dawn::TextureFormat::BC4RSnorm:
|
||||||
|
case dawn::TextureFormat::BC5RGUnorm:
|
||||||
|
case dawn::TextureFormat::BC5RGSnorm:
|
||||||
|
case dawn::TextureFormat::BC6HRGBUfloat:
|
||||||
|
case dawn::TextureFormat::BC6HRGBSfloat:
|
||||||
|
case dawn::TextureFormat::BC7RGBAUnorm:
|
||||||
|
case dawn::TextureFormat::BC7RGBAUnormSrgb:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsCompressedFormat(dawn::TextureFormat format) {
|
||||||
|
return IsBCFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Is4x4CompressedFormat(dawn::TextureFormat format) {
|
||||||
|
return IsBCFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsWritableFormat(dawn::TextureFormat format) {
|
||||||
|
return !IsBCFormat(format);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO(jiawei.shao@intel.com): support more sample count.
|
// TODO(jiawei.shao@intel.com): support more sample count.
|
||||||
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor) {
|
MaybeError ValidateSampleCount(const TextureDescriptor* descriptor) {
|
||||||
if (!IsValidSampleCount(descriptor->sampleCount)) {
|
if (!IsValidSampleCount(descriptor->sampleCount)) {
|
||||||
|
@ -102,6 +136,11 @@ namespace dawn_native {
|
||||||
if (descriptor->arrayLayerCount > 1) {
|
if (descriptor->arrayLayerCount > 1) {
|
||||||
return DAWN_VALIDATION_ERROR("Multisampled 2D array texture is not supported.");
|
return DAWN_VALIDATION_ERROR("Multisampled 2D array texture is not supported.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IsCompressedFormat(descriptor->format)) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The sample counts of the textures in BC formats must be 1.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
|
@ -157,14 +196,46 @@ namespace dawn_native {
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeError ValidateTextureSize(const TextureDescriptor* descriptor) {
|
||||||
|
ASSERT(descriptor->size.width != 0 && descriptor->size.height != 0);
|
||||||
|
|
||||||
|
if (Log2(std::max(descriptor->size.width, descriptor->size.height)) + 1 <
|
||||||
|
descriptor->mipLevelCount) {
|
||||||
|
return DAWN_VALIDATION_ERROR("Texture has too many mip levels");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Is4x4CompressedFormat(descriptor->format)) {
|
||||||
|
if (descriptor->size.width % 4 != 0 || descriptor->size.height % 4 != 0) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"The size of the texture is incompatible with the texture format");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
||||||
|
MaybeError ValidateTextureUsageBit(const TextureDescriptor* descriptor) {
|
||||||
|
DAWN_TRY(ValidateTextureUsageBit(descriptor->usage));
|
||||||
|
if (!IsWritableFormat(descriptor->format)) {
|
||||||
|
constexpr dawn::TextureUsageBit kValidUsage = dawn::TextureUsageBit::Sampled |
|
||||||
|
dawn::TextureUsageBit::TransferSrc |
|
||||||
|
dawn::TextureUsageBit::TransferDst;
|
||||||
|
if (descriptor->usage & (~kValidUsage)) {
|
||||||
|
return DAWN_VALIDATION_ERROR(
|
||||||
|
"Texture format is incompatible with the texture usage");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
MaybeError ValidateTextureDescriptor(DeviceBase*, const TextureDescriptor* descriptor) {
|
MaybeError ValidateTextureDescriptor(DeviceBase*, const TextureDescriptor* descriptor) {
|
||||||
if (descriptor->nextInChain != nullptr) {
|
if (descriptor->nextInChain != nullptr) {
|
||||||
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
return DAWN_VALIDATION_ERROR("nextInChain must be nullptr");
|
||||||
}
|
}
|
||||||
|
|
||||||
DAWN_TRY(ValidateTextureUsageBit(descriptor->usage));
|
DAWN_TRY(ValidateTextureUsageBit(descriptor));
|
||||||
DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
|
DAWN_TRY(ValidateTextureDimension(descriptor->dimension));
|
||||||
DAWN_TRY(ValidateTextureFormat(descriptor->format));
|
DAWN_TRY(ValidateTextureFormat(descriptor->format));
|
||||||
DAWN_TRY(ValidateSampleCount(descriptor));
|
DAWN_TRY(ValidateSampleCount(descriptor));
|
||||||
|
@ -176,10 +247,7 @@ namespace dawn_native {
|
||||||
return DAWN_VALIDATION_ERROR("Cannot create an empty texture");
|
return DAWN_VALIDATION_ERROR("Cannot create an empty texture");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Log2(std::max(descriptor->size.width, descriptor->size.height)) + 1 <
|
DAWN_TRY(ValidateTextureSize(descriptor));
|
||||||
descriptor->mipLevelCount) {
|
|
||||||
return DAWN_VALIDATION_ERROR("Texture has too many mip levels");
|
|
||||||
}
|
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
|
@ -137,6 +137,9 @@ namespace dawn_native { namespace metal {
|
||||||
return MTLPixelFormatBGRA8Unorm;
|
return MTLPixelFormatBGRA8Unorm;
|
||||||
case dawn::TextureFormat::D32FloatS8Uint:
|
case dawn::TextureFormat::D32FloatS8Uint:
|
||||||
return MTLPixelFormatDepth32Float_Stencil8;
|
return MTLPixelFormatDepth32Float_Stencil8;
|
||||||
|
default:
|
||||||
|
UNREACHABLE();
|
||||||
|
return MTLPixelFormatRGBA8Unorm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -234,4 +234,114 @@ TEST_F(TextureValidationTest, EncodeDestroySubmit) {
|
||||||
// Submit should fail due to destroyed texture
|
// Submit should fail due to destroyed texture
|
||||||
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
ASSERT_DEVICE_ERROR(queue.Submit(1, &commands));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO(jiawei.shao@intel.com): use compressed texture formats as extensions.
|
||||||
|
// TODO(jiawei.shao@intel.com): add tests to verify we cannot create 1D or 3D textures with
|
||||||
|
// compressed texture formats.
|
||||||
|
class CompressedTextureFormatsValidationTests : public TextureValidationTest {
|
||||||
|
protected:
|
||||||
|
dawn::TextureDescriptor CreateDefaultTextureDescriptor() {
|
||||||
|
dawn::TextureDescriptor descriptor =
|
||||||
|
TextureValidationTest::CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.usage = dawn::TextureUsageBit::TransferSrc | dawn::TextureUsageBit::TransferDst |
|
||||||
|
dawn::TextureUsageBit::Sampled;
|
||||||
|
return descriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::array<dawn::TextureFormat, 14> kBCFormats = {
|
||||||
|
dawn::TextureFormat::BC1RGBAUnorm, dawn::TextureFormat::BC1RGBAUnormSrgb,
|
||||||
|
dawn::TextureFormat::BC2RGBAUnorm, dawn::TextureFormat::BC2RGBAUnormSrgb,
|
||||||
|
dawn::TextureFormat::BC3RGBAUnorm, dawn::TextureFormat::BC3RGBAUnormSrgb,
|
||||||
|
dawn::TextureFormat::BC4RUnorm, dawn::TextureFormat::BC4RSnorm,
|
||||||
|
dawn::TextureFormat::BC5RGUnorm, dawn::TextureFormat::BC5RGSnorm,
|
||||||
|
dawn::TextureFormat::BC6HRGBUfloat, dawn::TextureFormat::BC6HRGBSfloat,
|
||||||
|
dawn::TextureFormat::BC7RGBAUnorm, dawn::TextureFormat::BC7RGBAUnormSrgb};
|
||||||
|
};
|
||||||
|
|
||||||
|
// Test the validation of texture size when creating textures in compressed texture formats.
|
||||||
|
TEST_F(CompressedTextureFormatsValidationTests, TextureSize) {
|
||||||
|
// Test that it is invalid to use a number that is not a multiple of 4 (the compressed block
|
||||||
|
// width and height of all BC formats) as the width or height of textures in BC formats.
|
||||||
|
for (dawn::TextureFormat format : kBCFormats) {
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
ASSERT_TRUE(descriptor.size.width % 4 == 0 && descriptor.size.height % 4 == 0);
|
||||||
|
device.CreateTexture(&descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.size.width = 31;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.size.height = 31;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.size.width = 12;
|
||||||
|
descriptor.size.height = 32;
|
||||||
|
device.CreateTexture(&descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the validation of texture usages when creating textures in compressed texture formats.
|
||||||
|
TEST_F(CompressedTextureFormatsValidationTests, TextureUsage) {
|
||||||
|
// Test that only TransferSrc, TransferDst and Sampled are accepted as the texture usage of the
|
||||||
|
// textures in BC formats.
|
||||||
|
for (dawn::TextureFormat format : kBCFormats) {
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.usage = dawn::TextureUsageBit::OutputAttachment;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.usage = dawn::TextureUsageBit::Storage;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.usage = dawn::TextureUsageBit::Present;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the validation of sample count when creating textures in compressed texture formats.
|
||||||
|
TEST_F(CompressedTextureFormatsValidationTests, SampleCount) {
|
||||||
|
// Test that it is invalid to specify SampleCount > 1 when we create a texture in BC formats.
|
||||||
|
for (dawn::TextureFormat format : kBCFormats) {
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.sampleCount = 4;
|
||||||
|
ASSERT_DEVICE_ERROR(device.CreateTexture(&descriptor));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test the validation of creating 2D array textures in compressed texture formats.
|
||||||
|
TEST_F(CompressedTextureFormatsValidationTests, 2DArrayTexture) {
|
||||||
|
// Test that it is allowed to create a 2D array texture in BC formats.
|
||||||
|
for (dawn::TextureFormat format : kBCFormats) {
|
||||||
|
dawn::TextureDescriptor descriptor = CreateDefaultTextureDescriptor();
|
||||||
|
descriptor.format = format;
|
||||||
|
descriptor.arrayLayerCount = 6;
|
||||||
|
device.CreateTexture(&descriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
Loading…
Reference in New Issue