[spirv-writer] Generate texture type

Change-Id: I9a3c75af1c5243f400cd98780736860e68b709ea
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/27580
Commit-Queue: Tomek Ponitka <tommek@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
Tomek Ponitka 2020-08-31 16:11:44 +00:00 committed by Commit Bot service account
parent 6803529d58
commit 3588406b78
3 changed files with 564 additions and 0 deletions

View File

@ -50,11 +50,18 @@
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/switch_statement.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/depth_texture_type.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/i32_type.h"
#include "src/ast/type/matrix_type.h"
#include "src/ast/type/pointer_type.h"
#include "src/ast/type/sampled_texture_type.h"
#include "src/ast/type/storage_texture_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/texture_type.h"
#include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type/void_type.h"
#include "src/ast/type_constructor_expression.h"
#include "src/ast/uint_literal.h"
#include "src/ast/unary_op_expression.h"
@ -1916,6 +1923,10 @@ uint32_t Builder::GenerateTypeIfNeeded(ast::type::Type* type) {
}
} else if (type->IsVoid()) {
push_type(spv::Op::OpTypeVoid, {result});
} else if (type->IsTexture()) {
if (!GenerateTextureType(type->AsTexture(), result)) {
return 0;
}
} else {
error_ = "unable to convert type: " + type->type_name();
return 0;
@ -1925,6 +1936,80 @@ uint32_t Builder::GenerateTypeIfNeeded(ast::type::Type* type) {
return id;
}
// TODO(tommek): Cover multisampled textures here when they're included in AST
bool Builder::GenerateTextureType(ast::type::TextureType* texture,
const Operand& result) {
uint32_t array_literal = 0u;
auto dim = texture->dim();
if (dim == ast::type::TextureDimension::k1dArray ||
dim == ast::type::TextureDimension::k2dArray ||
dim == ast::type::TextureDimension::k2dMsArray ||
dim == ast::type::TextureDimension::kCubeArray) {
array_literal = 1u;
}
uint32_t dim_literal = SpvDim2D;
if (dim == ast::type::TextureDimension::k1dArray ||
dim == ast::type::TextureDimension::k1d) {
dim_literal = SpvDim1D;
}
if (dim == ast::type::TextureDimension::k3d) {
dim_literal = SpvDim3D;
}
if (dim == ast::type::TextureDimension::kCube ||
dim == ast::type::TextureDimension::kCubeArray) {
dim_literal = SpvDimCube;
}
uint32_t ms_literal = 0u;
if (dim == ast::type::TextureDimension::k2dMs ||
dim == ast::type::TextureDimension::k2dMsArray) {
ms_literal = 1u;
}
uint32_t depth_literal = 0u;
if (texture->IsDepth()) {
depth_literal = 1u;
}
uint32_t sampled_literal = 2u;
if (texture->IsSampled() || texture->IsDepth()) {
sampled_literal = 1u;
}
uint32_t type_id = 0u;
if (texture->IsDepth()) {
ast::type::F32Type f32;
type_id = GenerateTypeIfNeeded(&f32);
} else if (texture->IsSampled()) {
type_id = GenerateTypeIfNeeded(texture->AsSampled()->type());
} else if (texture->IsStorage()) {
if (texture->AsStorage()->access() == ast::type::StorageAccess::kWrite) {
ast::type::VoidType void_type;
type_id = GenerateTypeIfNeeded(&void_type);
} else {
type_id = GenerateTypeIfNeeded(texture->AsStorage()->type());
}
}
if (type_id == 0u) {
return false;
}
uint32_t format_literal = SpvImageFormat_::SpvImageFormatUnknown;
if (texture->IsStorage()) {
format_literal =
convert_image_format_to_spv(texture->AsStorage()->image_format());
}
push_type(spv::Op::OpTypeImage,
{result, Operand::Int(type_id), Operand::Int(dim_literal),
Operand::Int(depth_literal), Operand::Int(array_literal),
Operand::Int(ms_literal), Operand::Int(sampled_literal),
Operand::Int(format_literal)});
return true;
}
bool Builder::GenerateArrayType(ast::type::ArrayType* ary,
const Operand& result) {
auto elem_type = GenerateTypeIfNeeded(ary->type());

View File

@ -329,6 +329,12 @@ class Builder {
/// @param type the type to create
/// @returns the ID to use for the given type. Returns 0 on unknown type.
uint32_t GenerateTypeIfNeeded(ast::type::Type* type);
/// Generates a texture type declaration
/// @param texture the texture to generate
/// @param result the result operand
/// @returns true if the texture was successfully generated
bool GenerateTextureType(ast::type::TextureType* texture,
const Operand& result);
/// Generates an array type declaration
/// @param ary the array to generate
/// @param result the result operand

View File

@ -15,20 +15,26 @@
#include <memory>
#include "gtest/gtest.h"
#include "src/ast/identifier_expression.h"
#include "src/ast/struct.h"
#include "src/ast/struct_member.h"
#include "src/ast/struct_member_offset_decoration.h"
#include "src/ast/type/alias_type.h"
#include "src/ast/type/array_type.h"
#include "src/ast/type/bool_type.h"
#include "src/ast/type/depth_texture_type.h"
#include "src/ast/type/f32_type.h"
#include "src/ast/type/i32_type.h"
#include "src/ast/type/matrix_type.h"
#include "src/ast/type/pointer_type.h"
#include "src/ast/type/sampled_texture_type.h"
#include "src/ast/type/storage_texture_type.h"
#include "src/ast/type/struct_type.h"
#include "src/ast/type/texture_type.h"
#include "src/ast/type/u32_type.h"
#include "src/ast/type/vector_type.h"
#include "src/ast/type/void_type.h"
#include "src/type_determiner.h"
#include "src/writer/spirv/builder.h"
#include "src/writer/spirv/spv_dump.h"
@ -689,6 +695,473 @@ INSTANTIATE_TEST_SUITE_P(
PtrData{ast::StorageClass::kPrivate, SpvStorageClassPrivate},
PtrData{ast::StorageClass::kFunction, SpvStorageClassFunction}));
using DepthTextureTypeTest = BuilderTest_Type;
TEST_F(DepthTextureTypeTest, Generate_2d) {
ast::type::DepthTextureType two_d(ast::type::TextureDimension::k2d);
ast::Module mod;
Builder b(&mod);
auto id_two_d = b.GenerateTypeIfNeeded(&two_d);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_two_d);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeImage %2 2D 1 0 0 1 Unknown
)");
}
TEST_F(DepthTextureTypeTest, Generate_2dArray) {
ast::type::DepthTextureType two_d_array(
ast::type::TextureDimension::k2dArray);
ast::Module mod;
Builder b(&mod);
auto id_two_d_array = b.GenerateTypeIfNeeded(&two_d_array);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_two_d_array);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeImage %2 2D 1 1 0 1 Unknown
)");
}
TEST_F(DepthTextureTypeTest, Generate_Cube) {
ast::type::DepthTextureType cube(ast::type::TextureDimension::kCube);
ast::Module mod;
Builder b(&mod);
auto id_cube = b.GenerateTypeIfNeeded(&cube);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_cube);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeImage %2 Cube 1 0 0 1 Unknown
)");
}
TEST_F(DepthTextureTypeTest, Generate_CubeArray) {
ast::type::DepthTextureType cube_array(
ast::type::TextureDimension::kCubeArray);
ast::Module mod;
Builder b(&mod);
auto id_cube_array = b.GenerateTypeIfNeeded(&cube_array);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_cube_array);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeFloat 32
%1 = OpTypeImage %2 Cube 1 1 0 1 Unknown
)");
}
enum class TextureType { kF32, kI32, kU32 };
inline std::ostream& operator<<(std::ostream& out, TextureType data) {
if (data == TextureType::kF32) {
out << "f32";
} else if (data == TextureType::kI32) {
out << "i32";
} else {
out << "u32";
}
return out;
}
class SampledTextureTypeTest : public testing::TestWithParam<TextureType> {
public:
std::unique_ptr<ast::type::Type> get_type(TextureType param) {
if (param == TextureType::kF32) {
return std::make_unique<ast::type::F32Type>();
}
if (param == TextureType::kI32) {
return std::make_unique<ast::type::I32Type>();
}
return std::make_unique<ast::type::U32Type>();
}
std::string get_type_line(TextureType param) {
if (param == TextureType::kI32) {
return "%2 = OpTypeInt 32 1\n";
}
if (param == TextureType::kU32) {
return "%2 = OpTypeInt 32 0\n";
}
return "%2 = OpTypeFloat 32\n";
}
};
TEST_P(SampledTextureTypeTest, Generate_1d) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType one_d(ast::type::TextureDimension::k1d,
type.get());
ast::Module mod;
Builder b(&mod);
auto id_one_d = b.GenerateTypeIfNeeded(&one_d);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_one_d);
EXPECT_EQ(DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 1D 0 0 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_1dArray) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType one_d_array(
ast::type::TextureDimension::k1dArray, type.get());
ast::Module mod;
Builder b(&mod);
auto id_one_d_array = b.GenerateTypeIfNeeded(&one_d_array);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_one_d_array);
EXPECT_EQ(DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 1D 0 1 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_2d) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType two_d(ast::type::TextureDimension::k2d,
type.get());
ast::Module mod;
Builder b(&mod);
auto id_two_d = b.GenerateTypeIfNeeded(&two_d);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_two_d);
EXPECT_EQ(DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 2D 0 0 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_2d_array) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType two_d_array(
ast::type::TextureDimension::k2dArray, type.get());
ast::Module mod;
Builder b(&mod);
auto id_two_d_array = b.GenerateTypeIfNeeded(&two_d_array);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_two_d_array);
EXPECT_EQ(DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 2D 0 1 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_3d) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType three_d(ast::type::TextureDimension::k3d,
type.get());
ast::Module mod;
Builder b(&mod);
auto id_three_d = b.GenerateTypeIfNeeded(&three_d);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_three_d);
EXPECT_EQ(DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 3D 0 0 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_Cube) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType cube(ast::type::TextureDimension::kCube,
type.get());
ast::Module mod;
Builder b(&mod);
auto id_cube = b.GenerateTypeIfNeeded(&cube);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_cube);
EXPECT_EQ(
DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 Cube 0 0 0 1 Unknown\n");
}
TEST_P(SampledTextureTypeTest, Generate_CubeArray) {
auto param = GetParam();
auto type = get_type(param);
ast::type::SampledTextureType cube_array(
ast::type::TextureDimension::kCubeArray, type.get());
ast::Module mod;
Builder b(&mod);
auto id_cube_array = b.GenerateTypeIfNeeded(&cube_array);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id_cube_array);
EXPECT_EQ(
DumpInstructions(b.types()),
get_type_line(param) + "%1 = OpTypeImage %2 Cube 0 1 0 1 Unknown\n");
}
INSTANTIATE_TEST_SUITE_P(BuilderTest_Type,
SampledTextureTypeTest,
testing::Values(TextureType::kU32,
TextureType::kI32,
TextureType::kF32));
class StorageTextureTypeTest
: public testing::TestWithParam<ast::type::ImageFormat> {
public:
std::string format_literal(ast::type::ImageFormat format) {
if (format == ast::type::ImageFormat::kR16Float) {
return "R16f\n";
}
if (format == ast::type::ImageFormat::kR8Snorm) {
return "R8Snorm\n";
}
return "R8\n";
}
std::string type_line(ast::type::ImageFormat format) {
if (format == ast::type::ImageFormat::kR8Snorm) {
return "%2 = OpTypeInt 32 1\n";
}
if (format == ast::type::ImageFormat::kR8Unorm) {
return "%2 = OpTypeInt 32 0\n";
}
return "%2 = OpTypeFloat 32\n";
}
};
TEST_P(StorageTextureTypeTest, GenerateReadonly_1d) {
auto format = GetParam();
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
Builder b(&mod);
ast::type::Type* type =
ctx.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
ast::type::TextureDimension::k1d, ast::type::StorageAccess::kRead,
format));
ASSERT_TRUE(td.Determine()) << td.error();
auto id = b.GenerateTypeIfNeeded(type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), type_line(format) +
"%1 = OpTypeImage %2 1D 0 0 0 2 " +
format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateReadonly_1d_array) {
auto format = GetParam();
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
Builder b(&mod);
ast::type::Type* type =
ctx.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
ast::type::TextureDimension::k1dArray,
ast::type::StorageAccess::kRead, format));
ASSERT_TRUE(td.Determine()) << td.error();
auto id = b.GenerateTypeIfNeeded(type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), type_line(format) +
"%1 = OpTypeImage %2 1D 0 1 0 2 " +
format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateReadonly_2d) {
auto format = GetParam();
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
Builder b(&mod);
ast::type::Type* type =
ctx.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
ast::type::TextureDimension::k2d, ast::type::StorageAccess::kRead,
format));
ASSERT_TRUE(td.Determine()) << td.error();
auto id = b.GenerateTypeIfNeeded(type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), type_line(format) +
"%1 = OpTypeImage %2 2D 0 0 0 2 " +
format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateReadonly_2dArray) {
auto format = GetParam();
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
Builder b(&mod);
ast::type::Type* type =
ctx.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
ast::type::TextureDimension::k2dArray,
ast::type::StorageAccess::kRead, format));
ASSERT_TRUE(td.Determine()) << td.error();
auto id = b.GenerateTypeIfNeeded(type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), type_line(format) +
"%1 = OpTypeImage %2 2D 0 1 0 2 " +
format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateReadonly_3d) {
auto format = GetParam();
Context ctx;
ast::Module mod;
TypeDeterminer td(&ctx, &mod);
Builder b(&mod);
ast::type::Type* type =
ctx.type_mgr().Get(std::make_unique<ast::type::StorageTextureType>(
ast::type::TextureDimension::k3d, ast::type::StorageAccess::kRead,
format));
ASSERT_TRUE(td.Determine()) << td.error();
auto id = b.GenerateTypeIfNeeded(type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), type_line(format) +
"%1 = OpTypeImage %2 3D 0 0 0 2 " +
format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateWriteonly_1d) {
auto format = GetParam();
ast::type::StorageTextureType type(ast::type::TextureDimension::k1d,
ast::type::StorageAccess::kWrite, format);
ast::Module mod;
Builder b(&mod);
auto id = b.GenerateTypeIfNeeded(&type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeImage %2 1D 0 0 0 2 )" + format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateWriteonly_1dArray) {
auto format = GetParam();
ast::type::StorageTextureType type(ast::type::TextureDimension::k1dArray,
ast::type::StorageAccess::kWrite, format);
ast::Module mod;
Builder b(&mod);
auto id = b.GenerateTypeIfNeeded(&type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeImage %2 1D 0 1 0 2 )" + format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateWriteonly_2d) {
auto format = GetParam();
ast::type::StorageTextureType type(ast::type::TextureDimension::k2d,
ast::type::StorageAccess::kWrite, format);
ast::Module mod;
Builder b(&mod);
auto id = b.GenerateTypeIfNeeded(&type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeImage %2 2D 0 0 0 2 )" + format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateWriteonly_2dArray) {
auto format = GetParam();
ast::type::StorageTextureType type(ast::type::TextureDimension::k2dArray,
ast::type::StorageAccess::kWrite, format);
ast::Module mod;
Builder b(&mod);
auto id = b.GenerateTypeIfNeeded(&type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeImage %2 2D 0 1 0 2 )" + format_literal(format));
}
TEST_P(StorageTextureTypeTest, GenerateWriteonly_3d) {
auto format = GetParam();
ast::type::StorageTextureType type(ast::type::TextureDimension::k3d,
ast::type::StorageAccess::kWrite, format);
ast::Module mod;
Builder b(&mod);
auto id = b.GenerateTypeIfNeeded(&type);
ASSERT_FALSE(b.has_error()) << b.error();
EXPECT_EQ(1u, id);
EXPECT_EQ(DumpInstructions(b.types()), R"(%2 = OpTypeVoid
%1 = OpTypeImage %2 3D 0 0 0 2 )" + format_literal(format));
}
INSTANTIATE_TEST_SUITE_P(BuilderTest_Type,
StorageTextureTypeTest,
testing::Values(ast::type::ImageFormat::kR16Float,
ast::type::ImageFormat::kR8Snorm,
ast::type::ImageFormat::kR8Unorm));
} // namespace
} // namespace spirv
} // namespace writer