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:
Jiawei Shao 2019-06-01 02:30:51 +00:00 committed by Commit Bot service account
parent 8dfc593eb7
commit c2750abd0c
4 changed files with 204 additions and 6 deletions

View File

@ -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": {

View File

@ -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 {};
} }

View File

@ -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;
} }
} }

View File

@ -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