spirv-reader: Add (handle) Usage abstraction

Bug: tint:109
Change-Id: I5cb8f35636c61cf2f837271a51c4753117b288be
Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32387
Commit-Queue: David Neto <dneto@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Auto-Submit: David Neto <dneto@google.com>
This commit is contained in:
David Neto 2020-11-17 18:32:18 +00:00 committed by Commit Bot service account
parent cebde298f9
commit bd7ab2cd5f
5 changed files with 619 additions and 0 deletions

View File

@ -470,6 +470,8 @@ source_set("libtint_spv_reader_src") {
"src/reader/spirv/parser.h",
"src/reader/spirv/parser_impl.cc",
"src/reader/spirv/parser_impl.h",
"src/reader/spirv/usage.cc",
"src/reader/spirv/usage.h",
]
deps = [
@ -855,6 +857,7 @@ source_set("tint_unittests_spv_reader_src") {
"src/reader/spirv/parser_test.cc",
"src/reader/spirv/spirv_tools_helpers_test.cc",
"src/reader/spirv/spirv_tools_helpers_test.h",
"src/reader/spirv/usage_test.cc",
]
configs += [

View File

@ -273,6 +273,8 @@ if(${TINT_BUILD_SPV_READER})
reader/spirv/parser.h
reader/spirv/parser_impl.cc
reader/spirv/parser_impl.h
reader/spirv/usage.cc
reader/spirv/usage.h
)
endif()
@ -459,6 +461,7 @@ if(${TINT_BUILD_SPV_READER})
reader/spirv/parser_test.cc
reader/spirv/spirv_tools_helpers_test.cc
reader/spirv/spirv_tools_helpers_test.h
reader/spirv/usage_test.cc
)
endif()

186
src/reader/spirv/usage.cc Normal file
View File

@ -0,0 +1,186 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "src/reader/spirv/usage.h"
namespace tint {
namespace reader {
namespace spirv {
Usage::Usage() {}
Usage::Usage(const Usage& other) = default;
Usage::~Usage() = default;
std::ostream& Usage::operator<<(std::ostream& out) const {
out << "Usage(";
if (IsSampler()) {
out << "Sampler(";
if (is_comparison_sampler_) {
out << " comparison";
}
out << " )";
}
if (IsTexture()) {
out << "Texture(";
if (is_sampled_) {
out << " is_sampled";
}
if (is_multisampled_) {
out << " ms";
}
if (is_depth_) {
out << " depth";
}
if (is_storage_read_) {
out << " read";
}
if (is_storage_write_) {
out << " write";
}
out << " )";
}
out << ")";
return out;
}
bool Usage::IsValid() const {
// Check sampler state internal consistency.
if (is_comparison_sampler_ && !is_sampler_) {
return false;
}
// Check texture state.
// |is_texture_| is implied by any of the later texture-based properties.
if ((IsStorageTexture() || is_sampled_ || is_multisampled_ || is_depth_) &&
!is_texture_) {
return false;
}
if (is_texture_) {
// Multisampled implies sampled.
if (is_multisampled_) {
if (!is_sampled_) {
return false;
}
}
// Depth implies sampled.
if (is_depth_) {
if (!is_sampled_) {
return false;
}
}
// Sampled can't be storage.
if (is_sampled_) {
if (IsStorageTexture()) {
return false;
}
}
// Storage can't be sampled.
if (IsStorageTexture()) {
if (is_sampled_) {
return false;
}
}
// Storage texture can't also be a sampler.
if (IsStorageTexture()) {
if (is_sampler_) {
return false;
}
}
// Can't be both read and write. This is a restriction in WebGPU.
if (is_storage_read_ && is_storage_write_) {
return false;
}
}
return true;
}
bool Usage::IsComplete() const {
if (!IsValid()) {
return false;
}
if (IsSampler()) {
return true;
}
if (IsTexture()) {
return is_sampled_ || IsStorageTexture();
}
return false;
}
bool Usage::operator==(const Usage& other) const {
return is_sampler_ == other.is_sampler_ &&
is_comparison_sampler_ == other.is_comparison_sampler_ &&
is_texture_ == other.is_texture_ && is_sampled_ == other.is_sampled_ &&
is_multisampled_ == other.is_multisampled_ &&
is_depth_ == other.is_depth_ &&
is_storage_read_ == other.is_storage_read_ &&
is_storage_write_ == other.is_storage_write_;
}
void Usage::Add(const Usage& other) {
is_sampler_ = is_sampler_ || other.is_sampler_;
is_comparison_sampler_ =
is_comparison_sampler_ || other.is_comparison_sampler_;
is_texture_ = is_texture_ || other.is_texture_;
is_sampled_ = is_sampled_ || other.is_sampled_;
is_multisampled_ = is_multisampled_ || other.is_multisampled_;
is_depth_ = is_depth_ || other.is_depth_;
is_storage_read_ = is_storage_read_ || other.is_storage_read_;
is_storage_write_ = is_storage_write_ || other.is_storage_write_;
}
void Usage::AddSampler() {
is_sampler_ = true;
}
void Usage::AddComparisonSampler() {
AddSampler();
is_comparison_sampler_ = true;
}
void Usage::AddTexture() {
is_texture_ = true;
}
void Usage::AddStorageReadTexture() {
AddTexture();
is_storage_read_ = true;
}
void Usage::AddStorageWriteTexture() {
AddTexture();
is_storage_write_ = true;
}
void Usage::AddSampledTexture() {
AddTexture();
is_sampled_ = true;
}
void Usage::AddMultisampledTexture() {
AddSampledTexture();
is_multisampled_ = true;
}
void Usage::AddDepthTexture() {
AddSampledTexture();
is_depth_ = true;
}
} // namespace spirv
} // namespace reader
} // namespace tint

130
src/reader/spirv/usage.h Normal file
View File

@ -0,0 +1,130 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef SRC_READER_SPIRV_USAGE_H_
#define SRC_READER_SPIRV_USAGE_H_
#include <ostream>
namespace tint {
namespace reader {
namespace spirv {
/// Records the properties of a sampler or texture based on how it's used
/// by image instructions inside function bodies.
///
/// For example:
///
/// If %X is the "Image" parameter of an OpImageWrite instruction then
/// - The memory object declaration underlying %X will gain
/// AddStorageWriteTexture usage
///
/// If %Y is the "Sampled Image" parameter of an OpImageSampleDrefExplicitLod
/// instruction, and %Y is composed from sampler %YSam and image %YIm, then:
/// - The memory object declaration underlying %YSam will gain
/// AddComparisonSampler usage
/// - The memory object declaration unederlying %YIm will gain
/// AddSampledTexture and AddDepthTexture usages
class Usage {
public:
Usage();
Usage(const Usage& other);
~Usage();
/// @returns true if this usage is internally consistent
bool IsValid() const;
/// @returns true if the usage fully determines a WebGPU binding type.
bool IsComplete() const;
/// @returns true if this usage is a sampler usage.
bool IsSampler() const { return is_sampler_; }
/// @returns true if this usage is a comparison sampler usage.
bool IsComparisonSampler() const { return is_comparison_sampler_; }
/// @returns true if this usage is a texture usage.
bool IsTexture() const { return is_texture_; }
/// @returns true if this usage is a sampled texture usage.
bool IsSampledTexture() const { return is_sampled_; }
/// @returns true if this usage is a multisampled texture usage.
bool IsMultisampledTexture() const { return is_multisampled_; }
/// @returns true if this usage is a dpeth texture usage.
bool IsDepthTexture() const { return is_depth_; }
/// @returns true if this usage is a read-only storage texture
bool IsStorageReadTexture() const { return is_storage_read_; }
/// @returns true if this usage is a write-only storage texture
bool IsStorageWriteTexture() const { return is_storage_write_; }
/// @returns true if this is a storage texture.
bool IsStorageTexture() const {
return is_storage_read_ || is_storage_write_;
}
/// Emits this usage to the given stream
/// @param out the output stream.
/// @returns the modified stream.
std::ostream& operator<<(std::ostream& out) const;
/// Equality operator
/// @param other the RHS of the equality test.
/// @returns true if |other| is identical to *this
bool operator==(const Usage& other) const;
/// Adds the usages from another usage object.
/// @param other the other usage
void Add(const Usage& other);
/// Records usage as a sampler.
void AddSampler();
/// Records usage as a comparison sampler.
void AddComparisonSampler();
/// Records usage as a texture of some kind.
void AddTexture();
/// Records usage as a read-only storage texture.
void AddStorageReadTexture();
// Records usage as a write-only storage texture.
void AddStorageWriteTexture();
// Records usage as a sampled texture.
void AddSampledTexture();
// Records usage as a multisampled texture.
void AddMultisampledTexture();
/// Records usage as a depth texture.
void AddDepthTexture();
private:
// Sampler properties.
bool is_sampler_ = false;
// A comparison sampler is always a sampler:
// |is_comparison_sampler_| implies |is_sampler_|
bool is_comparison_sampler_ = false;
// Texture properties.
// |is_texture_| is always implied by any of the others below.
bool is_texture_ = false;
bool is_sampled_ = false;
bool is_multisampled_ = false; // This implies it's sampled as well.
bool is_depth_ = false;
bool is_storage_read_ = false;
bool is_storage_write_ = false;
};
inline std::ostream& operator<<(std::ostream& out, const Usage& u) {
return u.operator<<(out);
}
} // namespace spirv
} // namespace reader
} // namespace tint
#endif // SRC_READER_SPIRV_USAGE_H_

View File

@ -0,0 +1,297 @@
// Copyright 2020 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <algorithm>
#include <sstream>
#include <vector>
#include "gmock/gmock.h"
#include "src/reader/spirv/parser_impl_test_helper.h"
#include "src/reader/spirv/usage.h"
namespace tint {
namespace reader {
namespace spirv {
namespace {
using ::testing::Eq;
TEST_F(SpvParserTest, Usage_Trivial_Properties) {
Usage u;
EXPECT_TRUE(u.IsValid());
EXPECT_FALSE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_FALSE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
}
TEST_F(SpvParserTest, Usage_Trivial_Output) {
std::ostringstream ss;
Usage u;
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage()"));
}
TEST_F(SpvParserTest, Usage_Equality_OneDifference) {
const int num_usages = 9;
std::vector<Usage> usages(num_usages);
usages[1].AddSampler();
usages[2].AddComparisonSampler();
usages[3].AddTexture();
usages[4].AddSampledTexture();
usages[5].AddMultisampledTexture();
usages[6].AddDepthTexture();
usages[7].AddStorageReadTexture();
usages[8].AddStorageWriteTexture();
for (int i = 0; i < num_usages; ++i) {
for (int j = 0; j < num_usages; ++j) {
const auto& lhs = usages[i];
const auto& rhs = usages[j];
if (i == j) {
EXPECT_TRUE(lhs == rhs);
} else {
EXPECT_FALSE(lhs == rhs);
}
}
}
}
TEST_F(SpvParserTest, Usage_Add) {
// Mix two nontrivial usages.
Usage a;
a.AddStorageReadTexture();
Usage b;
b.AddComparisonSampler();
a.Add(b);
EXPECT_FALSE(a.IsValid());
EXPECT_FALSE(a.IsComplete());
EXPECT_TRUE(a.IsSampler());
EXPECT_TRUE(a.IsComparisonSampler());
EXPECT_TRUE(a.IsTexture());
EXPECT_FALSE(a.IsSampledTexture());
EXPECT_FALSE(a.IsMultisampledTexture());
EXPECT_FALSE(a.IsDepthTexture());
EXPECT_TRUE(a.IsStorageReadTexture());
EXPECT_FALSE(a.IsStorageWriteTexture());
std::ostringstream ss;
ss << a;
EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison )Texture( read ))"));
}
TEST_F(SpvParserTest, Usage_AddSampler) {
std::ostringstream ss;
Usage u;
u.AddSampler();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_TRUE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_FALSE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Sampler( ))"));
// Check idempotency
auto copy(u);
u.AddSampler();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddComparisonSampler) {
std::ostringstream ss;
Usage u;
u.AddComparisonSampler();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_TRUE(u.IsSampler());
EXPECT_TRUE(u.IsComparisonSampler());
EXPECT_FALSE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Sampler( comparison ))"));
auto copy(u);
u.AddComparisonSampler();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddTexture) {
std::ostringstream ss;
Usage u;
u.AddTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_FALSE(u.IsComplete()); // Don't know if it's sampled or storage
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( ))"));
auto copy(u);
u.AddTexture();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddSampledTexture) {
std::ostringstream ss;
Usage u;
u.AddSampledTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_TRUE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ))"));
auto copy(u);
u.AddSampledTexture();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddMultisampledTexture) {
std::ostringstream ss;
Usage u;
u.AddMultisampledTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_TRUE(u.IsSampledTexture());
EXPECT_TRUE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled ms ))"));
auto copy(u);
u.AddMultisampledTexture();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddDepthTexture) {
std::ostringstream ss;
Usage u;
u.AddDepthTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_TRUE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_TRUE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( is_sampled depth ))"));
auto copy(u);
u.AddDepthTexture();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddStorageReadTexture) {
std::ostringstream ss;
Usage u;
u.AddStorageReadTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_TRUE(u.IsStorageReadTexture());
EXPECT_FALSE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( read ))"));
auto copy(u);
u.AddStorageReadTexture();
EXPECT_TRUE(u == copy);
}
TEST_F(SpvParserTest, Usage_AddStorageWriteTexture) {
std::ostringstream ss;
Usage u;
u.AddStorageWriteTexture();
EXPECT_TRUE(u.IsValid());
EXPECT_TRUE(u.IsComplete());
EXPECT_FALSE(u.IsSampler());
EXPECT_FALSE(u.IsComparisonSampler());
EXPECT_TRUE(u.IsTexture());
EXPECT_FALSE(u.IsSampledTexture());
EXPECT_FALSE(u.IsMultisampledTexture());
EXPECT_FALSE(u.IsDepthTexture());
EXPECT_FALSE(u.IsStorageReadTexture());
EXPECT_TRUE(u.IsStorageWriteTexture());
ss << u;
EXPECT_THAT(ss.str(), Eq("Usage(Texture( write ))"));
auto copy(u);
u.AddStorageWriteTexture();
EXPECT_TRUE(u == copy);
}
} // namespace
} // namespace spirv
} // namespace reader
} // namespace tint