Implement textureSample builtins
Handle wsgl parsing and spirv writing of: textureSample(), textureSampleBias(), textureSampleLevel(), textureSampleGrad(), textureSampleCompare() Handle the different signature for array texture types. Includes offset overloads. Change-Id: I6802d97cd9a7083f12439b32725b9a4b666b8c63 Reviewed-on: https://dawn-review.googlesource.com/c/tint/+/32985 Commit-Queue: Ben Clayton <bclayton@google.com> Reviewed-by: David Neto <dneto@google.com> Reviewed-by: Ryan Harrison <rharrison@chromium.org> Reviewed-by: dan sinclair <dsinclair@chromium.org>
This commit is contained in:
parent
2f4096b0d7
commit
3ea3c997b5
2
BUILD.gn
2
BUILD.gn
|
@ -755,6 +755,8 @@ source_set("tint_unittests_core_src") {
|
||||||
"src/ast/function_test.cc",
|
"src/ast/function_test.cc",
|
||||||
"src/ast/identifier_expression_test.cc",
|
"src/ast/identifier_expression_test.cc",
|
||||||
"src/ast/if_statement_test.cc",
|
"src/ast/if_statement_test.cc",
|
||||||
|
"src/ast/intrinsic_texture_helper_test.cc",
|
||||||
|
"src/ast/intrinsic_texture_helper_test.h",
|
||||||
"src/ast/int_literal_test.cc",
|
"src/ast/int_literal_test.cc",
|
||||||
"src/ast/location_decoration_test.cc",
|
"src/ast/location_decoration_test.cc",
|
||||||
"src/ast/loop_statement_test.cc",
|
"src/ast/loop_statement_test.cc",
|
||||||
|
|
|
@ -364,6 +364,8 @@ set(TINT_TEST_SRCS
|
||||||
ast/function_test.cc
|
ast/function_test.cc
|
||||||
ast/identifier_expression_test.cc
|
ast/identifier_expression_test.cc
|
||||||
ast/if_statement_test.cc
|
ast/if_statement_test.cc
|
||||||
|
ast/intrinsic_texture_helper_test.cc
|
||||||
|
ast/intrinsic_texture_helper_test.h
|
||||||
ast/int_literal_test.cc
|
ast/int_literal_test.cc
|
||||||
ast/location_decoration_test.cc
|
ast/location_decoration_test.cc
|
||||||
ast/loop_statement_test.cc
|
ast/loop_statement_test.cc
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
#ifndef SRC_AST_IDENTIFIER_EXPRESSION_H_
|
#ifndef SRC_AST_IDENTIFIER_EXPRESSION_H_
|
||||||
#define SRC_AST_IDENTIFIER_EXPRESSION_H_
|
#define SRC_AST_IDENTIFIER_EXPRESSION_H_
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include "src/ast/expression.h"
|
#include "src/ast/expression.h"
|
||||||
#include "src/ast/intrinsic.h"
|
#include "src/ast/intrinsic.h"
|
||||||
|
@ -45,6 +47,17 @@ class IdentifierExpression : public Expression {
|
||||||
void set_intrinsic(Intrinsic i) { intrinsic_ = i; }
|
void set_intrinsic(Intrinsic i) { intrinsic_ = i; }
|
||||||
/// @returns the intrinsic this identifier represents
|
/// @returns the intrinsic this identifier represents
|
||||||
Intrinsic intrinsic() const { return intrinsic_; }
|
Intrinsic intrinsic() const { return intrinsic_; }
|
||||||
|
|
||||||
|
/// Sets the intrinsic signature
|
||||||
|
/// @param s the intrinsic signature to set
|
||||||
|
void set_intrinsic_signature(std::unique_ptr<intrinsic::Signature> s) {
|
||||||
|
intrinsic_sig_ = std::move(s);
|
||||||
|
}
|
||||||
|
/// @returns the intrinsic signature for this identifier.
|
||||||
|
const intrinsic::Signature* intrinsic_signature() const {
|
||||||
|
return intrinsic_sig_.get();
|
||||||
|
}
|
||||||
|
|
||||||
/// @returns true if this identifier is for an intrinsic
|
/// @returns true if this identifier is for an intrinsic
|
||||||
bool IsIntrinsic() const { return intrinsic_ != Intrinsic::kNone; }
|
bool IsIntrinsic() const { return intrinsic_ != Intrinsic::kNone; }
|
||||||
|
|
||||||
|
@ -63,6 +76,7 @@ class IdentifierExpression : public Expression {
|
||||||
IdentifierExpression(const IdentifierExpression&) = delete;
|
IdentifierExpression(const IdentifierExpression&) = delete;
|
||||||
|
|
||||||
Intrinsic intrinsic_ = Intrinsic::kNone;
|
Intrinsic intrinsic_ = Intrinsic::kNone;
|
||||||
|
std::unique_ptr<intrinsic::Signature> intrinsic_sig_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -216,6 +216,9 @@ std::ostream& operator<<(std::ostream& out, Intrinsic i) {
|
||||||
case Intrinsic::kTextureSampleCompare:
|
case Intrinsic::kTextureSampleCompare:
|
||||||
out << "textureSampleCompare";
|
out << "textureSampleCompare";
|
||||||
break;
|
break;
|
||||||
|
case Intrinsic::kTextureSampleGrad:
|
||||||
|
out << "textureSampleGrad";
|
||||||
|
break;
|
||||||
case Intrinsic::kTextureSampleLevel:
|
case Intrinsic::kTextureSampleLevel:
|
||||||
out << "textureSampleLevel";
|
out << "textureSampleLevel";
|
||||||
break;
|
break;
|
||||||
|
@ -231,6 +234,12 @@ std::ostream& operator<<(std::ostream& out, Intrinsic i) {
|
||||||
|
|
||||||
namespace intrinsic {
|
namespace intrinsic {
|
||||||
|
|
||||||
|
Signature::~Signature() = default;
|
||||||
|
TextureSignature::~TextureSignature() = default;
|
||||||
|
|
||||||
|
TextureSignature::Parameters::Index::Index() = default;
|
||||||
|
TextureSignature::Parameters::Index::Index(const Index&) = default;
|
||||||
|
|
||||||
bool IsCoarseDerivative(ast::Intrinsic i) {
|
bool IsCoarseDerivative(ast::Intrinsic i) {
|
||||||
return i == Intrinsic::kDpdxCoarse || i == Intrinsic::kDpdyCoarse ||
|
return i == Intrinsic::kDpdxCoarse || i == Intrinsic::kDpdyCoarse ||
|
||||||
i == Intrinsic::kFwidthCoarse;
|
i == Intrinsic::kFwidthCoarse;
|
||||||
|
@ -256,7 +265,8 @@ bool IsTextureIntrinsic(ast::Intrinsic i) {
|
||||||
return i == Intrinsic::kTextureLoad || i == Intrinsic::kTextureSample ||
|
return i == Intrinsic::kTextureLoad || i == Intrinsic::kTextureSample ||
|
||||||
i == Intrinsic::kTextureSampleLevel ||
|
i == Intrinsic::kTextureSampleLevel ||
|
||||||
i == Intrinsic::kTextureSampleBias ||
|
i == Intrinsic::kTextureSampleBias ||
|
||||||
i == Intrinsic::kTextureSampleCompare;
|
i == Intrinsic::kTextureSampleCompare ||
|
||||||
|
i == Intrinsic::kTextureSampleGrad;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace intrinsic
|
} // namespace intrinsic
|
||||||
|
|
|
@ -89,6 +89,7 @@ enum class Intrinsic {
|
||||||
kTextureSample,
|
kTextureSample,
|
||||||
kTextureSampleBias,
|
kTextureSampleBias,
|
||||||
kTextureSampleCompare,
|
kTextureSampleCompare,
|
||||||
|
kTextureSampleGrad,
|
||||||
kTextureSampleLevel,
|
kTextureSampleLevel,
|
||||||
kTrunc
|
kTrunc
|
||||||
};
|
};
|
||||||
|
@ -99,6 +100,64 @@ std::ostream& operator<<(std::ostream& out, Intrinsic i);
|
||||||
|
|
||||||
namespace intrinsic {
|
namespace intrinsic {
|
||||||
|
|
||||||
|
/// Signature is the base struct for all intrinsic signature types.
|
||||||
|
/// Signatures are used to identify the particular overload for intrinsics that
|
||||||
|
/// have different signatures with the same function name.
|
||||||
|
struct Signature {
|
||||||
|
virtual ~Signature();
|
||||||
|
};
|
||||||
|
|
||||||
|
/// TextureSignature describes the signature of a texture intrinsic function.
|
||||||
|
struct TextureSignature : public Signature {
|
||||||
|
/// Parameters describes the parameters for the texture function.
|
||||||
|
struct Parameters {
|
||||||
|
/// kNotUsed is the constant that indicates the given parameter is not part
|
||||||
|
/// of the texture function signature.
|
||||||
|
static constexpr const size_t kNotUsed = ~static_cast<size_t>(0u);
|
||||||
|
/// Index holds each of the possible parameter indices. If a parameter index
|
||||||
|
/// is equal to `kNotUsed` then this parameter is not used by the function.
|
||||||
|
struct Index {
|
||||||
|
/// Constructor
|
||||||
|
Index();
|
||||||
|
/// Copy constructor
|
||||||
|
Index(const Index&);
|
||||||
|
/// `array_index` parameter index.
|
||||||
|
size_t array_index = kNotUsed;
|
||||||
|
/// `bias` parameter index.
|
||||||
|
size_t bias = kNotUsed;
|
||||||
|
/// `coords` parameter index.
|
||||||
|
size_t coords = kNotUsed;
|
||||||
|
/// `depth_ref` parameter index.
|
||||||
|
size_t depth_ref = kNotUsed;
|
||||||
|
/// `ddx` parameter index.
|
||||||
|
size_t ddx = kNotUsed;
|
||||||
|
/// `ddy` parameter index.
|
||||||
|
size_t ddy = kNotUsed;
|
||||||
|
/// `level` parameter index.
|
||||||
|
size_t level = kNotUsed;
|
||||||
|
/// `offset` parameter index.
|
||||||
|
size_t offset = kNotUsed;
|
||||||
|
/// `sampler` parameter index.
|
||||||
|
size_t sampler = kNotUsed;
|
||||||
|
/// `texture` parameter index.
|
||||||
|
size_t texture = kNotUsed;
|
||||||
|
};
|
||||||
|
/// The indices of all possible parameters.
|
||||||
|
Index idx;
|
||||||
|
/// Total number of parameters.
|
||||||
|
size_t count = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Construct an immutable `TextureSignature`.
|
||||||
|
/// @param p the texture intrinsic parameter signature.
|
||||||
|
explicit TextureSignature(const Parameters& p) : params(p) {}
|
||||||
|
|
||||||
|
~TextureSignature() override;
|
||||||
|
|
||||||
|
/// The texture intrinsic parameter signature.
|
||||||
|
const Parameters params;
|
||||||
|
};
|
||||||
|
|
||||||
/// Determines if the given |name| is a coarse derivative
|
/// Determines if the given |name| is a coarse derivative
|
||||||
/// @param i the intrinsic
|
/// @param i the intrinsic
|
||||||
/// @returns true if the given derivative is coarse.
|
/// @returns true if the given derivative is coarse.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,171 @@
|
||||||
|
// 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_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_
|
||||||
|
#define SRC_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "src/ast/builder.h"
|
||||||
|
#include "src/ast/type/sampler_type.h"
|
||||||
|
#include "src/ast/type/texture_type.h"
|
||||||
|
|
||||||
|
namespace tint {
|
||||||
|
namespace ast {
|
||||||
|
namespace intrinsic {
|
||||||
|
namespace test {
|
||||||
|
|
||||||
|
enum class TextureKind { kRegular, kDepth };
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, const TextureKind& kind) {
|
||||||
|
switch (kind) {
|
||||||
|
case TextureKind::kRegular:
|
||||||
|
out << "regular";
|
||||||
|
break;
|
||||||
|
case TextureKind::kDepth:
|
||||||
|
out << "depth";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class TextureDataType { kF32, kU32, kI32 };
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out, const TextureDataType& ty) {
|
||||||
|
switch (ty) {
|
||||||
|
case TextureDataType::kF32:
|
||||||
|
out << "f32";
|
||||||
|
break;
|
||||||
|
case TextureDataType::kU32:
|
||||||
|
out << "u32";
|
||||||
|
break;
|
||||||
|
case TextureDataType::kI32:
|
||||||
|
out << "i32";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class ValidTextureOverload {
|
||||||
|
kSample1dF32,
|
||||||
|
kSample1dArrayF32,
|
||||||
|
kSample2dF32,
|
||||||
|
kSample2dOffsetF32,
|
||||||
|
kSample2dArrayF32,
|
||||||
|
kSample2dArrayOffsetF32,
|
||||||
|
kSample3dF32,
|
||||||
|
kSample3dOffsetF32,
|
||||||
|
kSampleCubeF32,
|
||||||
|
kSampleCubeArrayF32,
|
||||||
|
kSampleDepth2dF32,
|
||||||
|
kSampleDepth2dOffsetF32,
|
||||||
|
kSampleDepth2dArrayF32,
|
||||||
|
kSampleDepth2dArrayOffsetF32,
|
||||||
|
kSampleDepthCubeF32,
|
||||||
|
kSampleDepthCubeArrayF32,
|
||||||
|
kSampleBias2dF32,
|
||||||
|
kSampleBias2dOffsetF32,
|
||||||
|
kSampleBias2dArrayF32,
|
||||||
|
kSampleBias2dArrayOffsetF32,
|
||||||
|
kSampleBias3dF32,
|
||||||
|
kSampleBias3dOffsetF32,
|
||||||
|
kSampleBiasCubeF32,
|
||||||
|
kSampleBiasCubeArrayF32,
|
||||||
|
kSampleLevel2dF32,
|
||||||
|
kSampleLevel2dOffsetF32,
|
||||||
|
kSampleLevel2dArrayF32,
|
||||||
|
kSampleLevel2dArrayOffsetF32,
|
||||||
|
kSampleLevel3dF32,
|
||||||
|
kSampleLevel3dOffsetF32,
|
||||||
|
kSampleLevelCubeF32,
|
||||||
|
kSampleLevelCubeArrayF32,
|
||||||
|
kSampleLevelDepth2dF32,
|
||||||
|
kSampleLevelDepth2dOffsetF32,
|
||||||
|
kSampleLevelDepth2dArrayF32,
|
||||||
|
kSampleLevelDepth2dArrayOffsetF32,
|
||||||
|
kSampleLevelDepthCubeF32,
|
||||||
|
kSampleLevelDepthCubeArrayF32,
|
||||||
|
kSampleGrad2dF32,
|
||||||
|
kSampleGrad2dOffsetF32,
|
||||||
|
kSampleGrad2dArrayF32,
|
||||||
|
kSampleGrad2dArrayOffsetF32,
|
||||||
|
kSampleGrad3dF32,
|
||||||
|
kSampleGrad3dOffsetF32,
|
||||||
|
kSampleGradCubeF32,
|
||||||
|
kSampleGradCubeArrayF32,
|
||||||
|
kSampleGradDepth2dF32,
|
||||||
|
kSampleGradDepth2dOffsetF32,
|
||||||
|
kSampleGradDepth2dArrayF32,
|
||||||
|
kSampleGradDepth2dArrayOffsetF32,
|
||||||
|
kSampleGradDepthCubeF32,
|
||||||
|
kSampleGradDepthCubeArrayF32,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Describes a texture intrinsic overload
|
||||||
|
struct TextureOverloadCase {
|
||||||
|
/// Constructor
|
||||||
|
TextureOverloadCase();
|
||||||
|
/// Constructor
|
||||||
|
TextureOverloadCase(ValidTextureOverload,
|
||||||
|
const char*,
|
||||||
|
TextureKind,
|
||||||
|
ast::type::SamplerKind,
|
||||||
|
ast::type::TextureDimension,
|
||||||
|
TextureDataType,
|
||||||
|
const char*,
|
||||||
|
std::function<ast::ExpressionList(ast::Builder*)>);
|
||||||
|
/// Copy constructor
|
||||||
|
TextureOverloadCase(const TextureOverloadCase&);
|
||||||
|
/// Destructor
|
||||||
|
~TextureOverloadCase();
|
||||||
|
|
||||||
|
/// @return a vector containing a large number of valid texture overloads
|
||||||
|
static std::vector<TextureOverloadCase> ValidCases();
|
||||||
|
|
||||||
|
/// The enumerator for this overload
|
||||||
|
ValidTextureOverload overload;
|
||||||
|
/// A human readable description of the overload
|
||||||
|
const char* description;
|
||||||
|
/// The texture kind for the texture parameter
|
||||||
|
TextureKind texture_kind;
|
||||||
|
/// The sampler kind for the sampler parameter
|
||||||
|
ast::type::SamplerKind sampler_kind;
|
||||||
|
/// The dimensions of the texture parameter
|
||||||
|
ast::type::TextureDimension texture_dimension;
|
||||||
|
/// The data type of the texture parameter
|
||||||
|
TextureDataType texture_data_type;
|
||||||
|
/// Name of the function. e.g. `textureSample`, `textureSampleGrad`, etc
|
||||||
|
const char* function;
|
||||||
|
/// A function that builds the AST arguments for the overload
|
||||||
|
std::function<ast::ExpressionList(ast::Builder*)> args;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline std::ostream& operator<<(std::ostream& out,
|
||||||
|
const TextureOverloadCase& data) {
|
||||||
|
out << "TextureOverloadCase" << static_cast<int>(data.overload) << "\n";
|
||||||
|
out << data.description << "\n";
|
||||||
|
out << "texture_kind: " << data.texture_kind << "\n";
|
||||||
|
out << "sampler_kind: " << data.sampler_kind << "\n";
|
||||||
|
out << "texture_dimension: " << data.texture_dimension << "\n";
|
||||||
|
out << "texture_data_type: " << data.texture_data_type << "\n";
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace test
|
||||||
|
} // namespace intrinsic
|
||||||
|
} // namespace ast
|
||||||
|
} // namespace tint
|
||||||
|
|
||||||
|
#endif // SRC_AST_INTRINSIC_TEXTURE_HELPER_TEST_H_
|
|
@ -529,6 +529,44 @@ class InspectorHelper {
|
||||||
body);
|
body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Generates a function that references a specific sampler variable
|
||||||
|
/// @param func_name name of the function created
|
||||||
|
/// @param texture_name name of the texture to be sampled
|
||||||
|
/// @param sampler_name name of the sampler to use
|
||||||
|
/// @param coords_name name of the coords variable to use
|
||||||
|
/// @param array_index name of the array index variable to use
|
||||||
|
/// @returns a function that references all of the values specified
|
||||||
|
ast::Function* MakeSamplerReferenceBodyFunction(
|
||||||
|
const std::string& func_name,
|
||||||
|
const std::string& texture_name,
|
||||||
|
const std::string& sampler_name,
|
||||||
|
const std::string& coords_name,
|
||||||
|
const std::string& array_index,
|
||||||
|
ast::type::Type* base_type) {
|
||||||
|
std::string result_name = "sampler_result";
|
||||||
|
|
||||||
|
auto* body = create<ast::BlockStatement>();
|
||||||
|
|
||||||
|
auto* call_result = create<ast::Variable>(
|
||||||
|
"sampler_result", ast::StorageClass::kFunction, vec_type(base_type, 4));
|
||||||
|
body->append(create<ast::VariableDeclStatement>(call_result));
|
||||||
|
|
||||||
|
ast::ExpressionList call_params;
|
||||||
|
call_params.push_back(create<ast::IdentifierExpression>(texture_name));
|
||||||
|
call_params.push_back(create<ast::IdentifierExpression>(sampler_name));
|
||||||
|
call_params.push_back(create<ast::IdentifierExpression>(coords_name));
|
||||||
|
call_params.push_back(create<ast::IdentifierExpression>(array_index));
|
||||||
|
auto* call_expr = create<ast::CallExpression>(
|
||||||
|
create<ast::IdentifierExpression>("textureSample"), call_params);
|
||||||
|
|
||||||
|
body->append(create<ast::AssignmentStatement>(
|
||||||
|
create<ast::IdentifierExpression>("sampler_result"), call_expr));
|
||||||
|
body->append(create<ast::ReturnStatement>());
|
||||||
|
|
||||||
|
return create<ast::Function>(func_name, ast::VariableList(), void_type(),
|
||||||
|
body);
|
||||||
|
}
|
||||||
|
|
||||||
/// Generates a function that references a specific comparison sampler
|
/// Generates a function that references a specific comparison sampler
|
||||||
/// variable.
|
/// variable.
|
||||||
/// @param func_name name of the function created
|
/// @param func_name name of the function created
|
||||||
|
@ -683,6 +721,9 @@ class InspectorGetComparisonSamplerResourceBindingsTest
|
||||||
public testing::Test {};
|
public testing::Test {};
|
||||||
class InspectorGetSampledTextureResourceBindingsTest : public InspectorHelper,
|
class InspectorGetSampledTextureResourceBindingsTest : public InspectorHelper,
|
||||||
public testing::Test {};
|
public testing::Test {};
|
||||||
|
class InspectorGetSampledArrayTextureResourceBindingsTest
|
||||||
|
: public InspectorHelper,
|
||||||
|
public testing::Test {};
|
||||||
struct GetSampledTextureTestParams {
|
struct GetSampledTextureTestParams {
|
||||||
ast::type::TextureDimension type_dim;
|
ast::type::TextureDimension type_dim;
|
||||||
inspector::ResourceBinding::TextureDimension inspector_dim;
|
inspector::ResourceBinding::TextureDimension inspector_dim;
|
||||||
|
@ -691,11 +732,19 @@ struct GetSampledTextureTestParams {
|
||||||
class InspectorGetSampledTextureResourceBindingsTestWithParam
|
class InspectorGetSampledTextureResourceBindingsTestWithParam
|
||||||
: public InspectorHelper,
|
: public InspectorHelper,
|
||||||
public testing::TestWithParam<GetSampledTextureTestParams> {};
|
public testing::TestWithParam<GetSampledTextureTestParams> {};
|
||||||
|
class InspectorGetSampledArrayTextureResourceBindingsTestWithParam
|
||||||
|
: public InspectorHelper,
|
||||||
|
public testing::TestWithParam<GetSampledTextureTestParams> {};
|
||||||
class InspectorGetMultisampledTextureResourceBindingsTest
|
class InspectorGetMultisampledTextureResourceBindingsTest
|
||||||
: public InspectorHelper,
|
: public InspectorHelper,
|
||||||
public testing::Test {};
|
public testing::Test {};
|
||||||
|
class InspectorGetMultisampledArrayTextureResourceBindingsTest
|
||||||
|
: public InspectorHelper,
|
||||||
|
public testing::Test {};
|
||||||
typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
|
typedef GetSampledTextureTestParams GetMultisampledTextureTestParams;
|
||||||
|
class InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam
|
||||||
|
: public InspectorHelper,
|
||||||
|
public testing::TestWithParam<GetMultisampledTextureTestParams> {};
|
||||||
class InspectorGetMultisampledTextureResourceBindingsTestWithParam
|
class InspectorGetMultisampledTextureResourceBindingsTestWithParam
|
||||||
: public InspectorHelper,
|
: public InspectorHelper,
|
||||||
public testing::TestWithParam<GetMultisampledTextureTestParams> {};
|
public testing::TestWithParam<GetMultisampledTextureTestParams> {};
|
||||||
|
@ -2008,18 +2057,6 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
ast::type::TextureDimension::k1d,
|
ast::type::TextureDimension::k1d,
|
||||||
inspector::ResourceBinding::TextureDimension::k1d,
|
inspector::ResourceBinding::TextureDimension::k1d,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kFloat},
|
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kSInt},
|
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
|
||||||
GetSampledTextureTestParams{
|
GetSampledTextureTestParams{
|
||||||
ast::type::TextureDimension::k2d,
|
ast::type::TextureDimension::k2d,
|
||||||
inspector::ResourceBinding::TextureDimension::k2d,
|
inspector::ResourceBinding::TextureDimension::k2d,
|
||||||
|
@ -2032,18 +2069,6 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
ast::type::TextureDimension::k2d,
|
ast::type::TextureDimension::k2d,
|
||||||
inspector::ResourceBinding::TextureDimension::k2d,
|
inspector::ResourceBinding::TextureDimension::k2d,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kFloat},
|
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kSInt},
|
|
||||||
GetSampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k2dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
|
||||||
GetSampledTextureTestParams{
|
GetSampledTextureTestParams{
|
||||||
ast::type::TextureDimension::k3d,
|
ast::type::TextureDimension::k3d,
|
||||||
inspector::ResourceBinding::TextureDimension::k3d,
|
inspector::ResourceBinding::TextureDimension::k3d,
|
||||||
|
@ -2067,6 +2092,65 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
GetSampledTextureTestParams{
|
GetSampledTextureTestParams{
|
||||||
ast::type::TextureDimension::kCube,
|
ast::type::TextureDimension::kCube,
|
||||||
inspector::ResourceBinding::TextureDimension::kCube,
|
inspector::ResourceBinding::TextureDimension::kCube,
|
||||||
|
inspector::ResourceBinding::SampledKind::kUInt}));
|
||||||
|
|
||||||
|
TEST_P(InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
|
||||||
|
textureSample) {
|
||||||
|
auto sampled_texture_type = MakeSampledTextureType(
|
||||||
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
|
AddSampledTexture("foo_texture", sampled_texture_type.get(), 0, 0);
|
||||||
|
AddSampler("foo_sampler", 0, 1);
|
||||||
|
auto* coord_type =
|
||||||
|
GetCoordsType(GetParam().type_dim, GetParam().sampled_kind);
|
||||||
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
|
AddGlobalVariable("foo_array_index", u32_type());
|
||||||
|
|
||||||
|
auto* func = MakeSamplerReferenceBodyFunction(
|
||||||
|
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_array_index",
|
||||||
|
GetBaseType(GetParam().sampled_kind));
|
||||||
|
func->add_decoration(
|
||||||
|
create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}));
|
||||||
|
mod()->AddFunction(func);
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetSampledTextureResourceBindings("ep");
|
||||||
|
ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
|
||||||
|
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
InspectorGetSampledArrayTextureResourceBindingsTest,
|
||||||
|
InspectorGetSampledArrayTextureResourceBindingsTestWithParam,
|
||||||
|
testing::Values(
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kFloat},
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kSInt},
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k2dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kFloat},
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k2dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kSInt},
|
||||||
|
GetSampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k2dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k2dArray,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
GetSampledTextureTestParams{
|
GetSampledTextureTestParams{
|
||||||
ast::type::TextureDimension::kCubeArray,
|
ast::type::TextureDimension::kCubeArray,
|
||||||
|
@ -2081,18 +2165,6 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
inspector::ResourceBinding::TextureDimension::kCubeArray,
|
inspector::ResourceBinding::TextureDimension::kCubeArray,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt}));
|
inspector::ResourceBinding::SampledKind::kUInt}));
|
||||||
|
|
||||||
TEST_F(InspectorGetMultisampledTextureResourceBindingsTest, Empty) {
|
|
||||||
auto* foo = MakeEmptyBodyFunction("foo");
|
|
||||||
foo->add_decoration(
|
|
||||||
create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}));
|
|
||||||
mod()->AddFunction(foo);
|
|
||||||
|
|
||||||
auto result = inspector()->GetSampledTextureResourceBindings("foo");
|
|
||||||
ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
|
|
||||||
|
|
||||||
EXPECT_EQ(0u, result.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
|
TEST_P(InspectorGetMultisampledTextureResourceBindingsTestWithParam,
|
||||||
textureSample) {
|
textureSample) {
|
||||||
auto multisampled_texture_type = MakeMultisampledTextureType(
|
auto multisampled_texture_type = MakeMultisampledTextureType(
|
||||||
|
@ -2138,18 +2210,6 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
ast::type::TextureDimension::k1d,
|
ast::type::TextureDimension::k1d,
|
||||||
inspector::ResourceBinding::TextureDimension::k1d,
|
inspector::ResourceBinding::TextureDimension::k1d,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
GetMultisampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kFloat},
|
|
||||||
GetMultisampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kSInt},
|
|
||||||
GetMultisampledTextureTestParams{
|
|
||||||
ast::type::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::TextureDimension::k1dArray,
|
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
|
||||||
GetMultisampledTextureTestParams{
|
GetMultisampledTextureTestParams{
|
||||||
ast::type::TextureDimension::k2d,
|
ast::type::TextureDimension::k2d,
|
||||||
inspector::ResourceBinding::TextureDimension::k2d,
|
inspector::ResourceBinding::TextureDimension::k2d,
|
||||||
|
@ -2161,6 +2221,65 @@ INSTANTIATE_TEST_SUITE_P(
|
||||||
GetMultisampledTextureTestParams{
|
GetMultisampledTextureTestParams{
|
||||||
ast::type::TextureDimension::k2d,
|
ast::type::TextureDimension::k2d,
|
||||||
inspector::ResourceBinding::TextureDimension::k2d,
|
inspector::ResourceBinding::TextureDimension::k2d,
|
||||||
|
inspector::ResourceBinding::SampledKind::kUInt}));
|
||||||
|
|
||||||
|
TEST_F(InspectorGetMultisampledArrayTextureResourceBindingsTest, Empty) {
|
||||||
|
auto* foo = MakeEmptyBodyFunction("foo");
|
||||||
|
foo->add_decoration(
|
||||||
|
create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}));
|
||||||
|
mod()->AddFunction(foo);
|
||||||
|
|
||||||
|
auto result = inspector()->GetSampledTextureResourceBindings("foo");
|
||||||
|
ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
|
||||||
|
|
||||||
|
EXPECT_EQ(0u, result.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_P(InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
|
||||||
|
textureSample) {
|
||||||
|
auto multisampled_texture_type = MakeMultisampledTextureType(
|
||||||
|
GetParam().type_dim, GetBaseType(GetParam().sampled_kind));
|
||||||
|
AddMultisampledTexture("foo_texture", multisampled_texture_type.get(), 0, 0);
|
||||||
|
AddSampler("foo_sampler", 0, 1);
|
||||||
|
auto* coord_type =
|
||||||
|
GetCoordsType(GetParam().type_dim, GetParam().sampled_kind);
|
||||||
|
AddGlobalVariable("foo_coords", coord_type);
|
||||||
|
AddGlobalVariable("foo_array_index", u32_type());
|
||||||
|
|
||||||
|
auto* func = MakeSamplerReferenceBodyFunction(
|
||||||
|
"ep", "foo_texture", "foo_sampler", "foo_coords", "foo_array_index",
|
||||||
|
GetBaseType(GetParam().sampled_kind));
|
||||||
|
func->add_decoration(
|
||||||
|
create<ast::StageDecoration>(ast::PipelineStage::kVertex, Source{}));
|
||||||
|
mod()->AddFunction(func);
|
||||||
|
|
||||||
|
ASSERT_TRUE(td()->Determine()) << td()->error();
|
||||||
|
|
||||||
|
auto result = inspector()->GetMultisampledTextureResourceBindings("ep");
|
||||||
|
ASSERT_FALSE(inspector()->has_error()) << inspector()->error();
|
||||||
|
|
||||||
|
ASSERT_EQ(1u, result.size());
|
||||||
|
EXPECT_EQ(0u, result[0].bind_group);
|
||||||
|
EXPECT_EQ(0u, result[0].binding);
|
||||||
|
EXPECT_EQ(GetParam().inspector_dim, result[0].dim);
|
||||||
|
EXPECT_EQ(GetParam().sampled_kind, result[0].sampled_kind);
|
||||||
|
}
|
||||||
|
|
||||||
|
INSTANTIATE_TEST_SUITE_P(
|
||||||
|
InspectorGetMultisampledArrayTextureResourceBindingsTest,
|
||||||
|
InspectorGetMultisampledArrayTextureResourceBindingsTestWithParam,
|
||||||
|
testing::Values(
|
||||||
|
GetMultisampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kFloat},
|
||||||
|
GetMultisampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::SampledKind::kSInt},
|
||||||
|
GetMultisampledTextureTestParams{
|
||||||
|
ast::type::TextureDimension::k1dArray,
|
||||||
|
inspector::ResourceBinding::TextureDimension::k1dArray,
|
||||||
inspector::ResourceBinding::SampledKind::kUInt},
|
inspector::ResourceBinding::SampledKind::kUInt},
|
||||||
GetMultisampledTextureTestParams{
|
GetMultisampledTextureTestParams{
|
||||||
ast::type::TextureDimension::k2dArray,
|
ast::type::TextureDimension::k2dArray,
|
||||||
|
|
|
@ -552,26 +552,7 @@ bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (ast::intrinsic::IsTextureIntrinsic(ident->intrinsic())) {
|
if (ast::intrinsic::IsTextureIntrinsic(ident->intrinsic())) {
|
||||||
// TODO(dsinclair): Remove the LOD param from textureLoad on storage
|
ast::intrinsic::TextureSignature::Parameters param;
|
||||||
// textures when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
|
||||||
uint32_t num_of_params =
|
|
||||||
(ident->intrinsic() == ast::Intrinsic::kTextureLoad ||
|
|
||||||
ident->intrinsic() == ast::Intrinsic::kTextureSample)
|
|
||||||
? 3
|
|
||||||
: 4;
|
|
||||||
if (expr->params().size() != num_of_params) {
|
|
||||||
set_error(expr->source(),
|
|
||||||
"incorrect number of parameters for " + ident->name() +
|
|
||||||
", got " + std::to_string(expr->params().size()) +
|
|
||||||
" and expected " + std::to_string(num_of_params));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kTextureSampleCompare) {
|
|
||||||
expr->func()->set_result_type(
|
|
||||||
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* texture_param = expr->params()[0];
|
auto* texture_param = expr->params()[0];
|
||||||
if (!texture_param->result_type()->UnwrapPtrIfNeeded()->IsTexture()) {
|
if (!texture_param->result_type()->UnwrapPtrIfNeeded()->IsTexture()) {
|
||||||
|
@ -581,6 +562,115 @@ bool TypeDeterminer::DetermineIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::type::TextureType* texture =
|
ast::type::TextureType* texture =
|
||||||
texture_param->result_type()->UnwrapPtrIfNeeded()->AsTexture();
|
texture_param->result_type()->UnwrapPtrIfNeeded()->AsTexture();
|
||||||
|
|
||||||
|
bool is_array = false;
|
||||||
|
switch (texture->dim()) {
|
||||||
|
case ast::type::TextureDimension::k1dArray:
|
||||||
|
case ast::type::TextureDimension::k2dArray:
|
||||||
|
case ast::type::TextureDimension::kCubeArray:
|
||||||
|
is_array = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (ident->intrinsic()) {
|
||||||
|
case ast::Intrinsic::kTextureLoad:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dsinclair): Remove the LOD param from textureLoad on storage
|
||||||
|
// textures when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.level = param.count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kTextureSample:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.sampler = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.offset = param.count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kTextureSampleBias:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.sampler = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
param.idx.bias = param.count++;
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.offset = param.count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kTextureSampleLevel:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.sampler = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
param.idx.level = param.count++;
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.offset = param.count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kTextureSampleCompare:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.sampler = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
param.idx.depth_ref = param.count++;
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.offset = param.count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ast::Intrinsic::kTextureSampleGrad:
|
||||||
|
param.idx.texture = param.count++;
|
||||||
|
param.idx.sampler = param.count++;
|
||||||
|
param.idx.coords = param.count++;
|
||||||
|
if (is_array) {
|
||||||
|
param.idx.array_index = param.count++;
|
||||||
|
}
|
||||||
|
param.idx.ddx = param.count++;
|
||||||
|
param.idx.ddy = param.count++;
|
||||||
|
if (expr->params().size() > param.count) {
|
||||||
|
param.idx.offset = param.count++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
set_error(expr->source(),
|
||||||
|
"Internal compiler error: Unreachable intrinsic " +
|
||||||
|
std::to_string(static_cast<int>(ident->intrinsic())));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (expr->params().size() != param.count) {
|
||||||
|
set_error(expr->source(),
|
||||||
|
"incorrect number of parameters for " + ident->name() +
|
||||||
|
", got " + std::to_string(expr->params().size()) +
|
||||||
|
" and expected " + std::to_string(param.count));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ident->set_intrinsic_signature(
|
||||||
|
std::make_unique<ast::intrinsic::TextureSignature>(param));
|
||||||
|
|
||||||
|
if (texture->IsDepth()) {
|
||||||
|
expr->func()->set_result_type(
|
||||||
|
ctx_.type_mgr().Get(std::make_unique<ast::type::F32Type>()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!texture->IsStorage() &&
|
if (!texture->IsStorage() &&
|
||||||
!(texture->IsSampled() || texture->IsMultisampled())) {
|
!(texture->IsSampled() || texture->IsMultisampled())) {
|
||||||
set_error(expr->source(), "invalid texture for " + ident->name());
|
set_error(expr->source(), "invalid texture for " + ident->name());
|
||||||
|
@ -925,6 +1015,8 @@ bool TypeDeterminer::SetIntrinsicIfNeeded(ast::IdentifierExpression* ident) {
|
||||||
ident->set_intrinsic(ast::Intrinsic::kTextureSampleBias);
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleBias);
|
||||||
} else if (ident->name() == "textureSampleCompare") {
|
} else if (ident->name() == "textureSampleCompare") {
|
||||||
ident->set_intrinsic(ast::Intrinsic::kTextureSampleCompare);
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleCompare);
|
||||||
|
} else if (ident->name() == "textureSampleGrad") {
|
||||||
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleGrad);
|
||||||
} else if (ident->name() == "textureSampleLevel") {
|
} else if (ident->name() == "textureSampleLevel") {
|
||||||
ident->set_intrinsic(ast::Intrinsic::kTextureSampleLevel);
|
ident->set_intrinsic(ast::Intrinsic::kTextureSampleLevel);
|
||||||
} else if (ident->name() == "trunc") {
|
} else if (ident->name() == "trunc") {
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1749,9 +1749,15 @@ uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto intrinsic = ident->intrinsic();
|
||||||
|
|
||||||
|
if (ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
|
||||||
|
GenerateTextureIntrinsic(ident, call, Operand::Int(result_type_id), result);
|
||||||
|
return result_id;
|
||||||
|
}
|
||||||
|
|
||||||
OperandList params = {Operand::Int(result_type_id), result};
|
OperandList params = {Operand::Int(result_type_id), result};
|
||||||
|
|
||||||
auto intrinsic = ident->intrinsic();
|
|
||||||
if (ast::intrinsic::IsFineDerivative(intrinsic) ||
|
if (ast::intrinsic::IsFineDerivative(intrinsic) ||
|
||||||
ast::intrinsic::IsCoarseDerivative(intrinsic)) {
|
ast::intrinsic::IsCoarseDerivative(intrinsic)) {
|
||||||
push_capability(SpvCapabilityDerivativeControl);
|
push_capability(SpvCapabilityDerivativeControl);
|
||||||
|
@ -1825,7 +1831,7 @@ uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
op = spv::Op::OpBitReverse;
|
op = spv::Op::OpBitReverse;
|
||||||
} else if (intrinsic == ast::Intrinsic::kSelect) {
|
} else if (intrinsic == ast::Intrinsic::kSelect) {
|
||||||
op = spv::Op::OpSelect;
|
op = spv::Op::OpSelect;
|
||||||
} else if (!ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
|
} else {
|
||||||
GenerateGLSLstd450Import();
|
GenerateGLSLstd450Import();
|
||||||
|
|
||||||
auto set_iter = import_name_to_id_.find(kGLSLstd450);
|
auto set_iter = import_name_to_id_.find(kGLSLstd450);
|
||||||
|
@ -1846,7 +1852,8 @@ uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
|
|
||||||
op = spv::Op::OpExtInst;
|
op = spv::Op::OpExtInst;
|
||||||
}
|
}
|
||||||
if (!ast::intrinsic::IsTextureIntrinsic(intrinsic) && op == spv::Op::OpNop) {
|
|
||||||
|
if (op == spv::Op::OpNop) {
|
||||||
error_ = "unable to determine operator for: " + ident->name();
|
error_ = "unable to determine operator for: " + ident->name();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1854,15 +1861,11 @@ uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
for (auto* p : call->params()) {
|
for (auto* p : call->params()) {
|
||||||
auto val_id = GenerateExpression(p);
|
auto val_id = GenerateExpression(p);
|
||||||
if (val_id == 0) {
|
if (val_id == 0) {
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
val_id = GenerateLoadIfNeeded(p->result_type(), val_id);
|
val_id = GenerateLoadIfNeeded(p->result_type(), val_id);
|
||||||
|
|
||||||
params.push_back(Operand::Int(val_id));
|
params.emplace_back(Operand::Int(val_id));
|
||||||
}
|
|
||||||
|
|
||||||
if (ast::intrinsic::IsTextureIntrinsic(intrinsic)) {
|
|
||||||
return GenerateTextureIntrinsic(ident, call, result_id, params);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
push_function_inst(op, params);
|
push_function_inst(op, params);
|
||||||
|
@ -1870,68 +1873,171 @@ uint32_t Builder::GenerateIntrinsic(ast::IdentifierExpression* ident,
|
||||||
return result_id;
|
return result_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
void Builder::GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
||||||
ast::CallExpression* call,
|
ast::CallExpression* call,
|
||||||
uint32_t result_id,
|
spirv::Operand result_type,
|
||||||
OperandList wgsl_params) {
|
spirv::Operand result_id) {
|
||||||
auto* texture_type =
|
auto* texture_type =
|
||||||
call->params()[0]->result_type()->UnwrapAll()->AsTexture();
|
call->params()[0]->result_type()->UnwrapAll()->AsTexture();
|
||||||
|
|
||||||
// TODO(dsinclair): Remove the LOD param from textureLoad on storage textures
|
auto* sig = static_cast<const ast::intrinsic::TextureSignature*>(
|
||||||
// when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
ident->intrinsic_signature());
|
||||||
|
assert(sig != nullptr);
|
||||||
|
auto& pidx = sig->params.idx;
|
||||||
|
auto const kNotUsed = ast::intrinsic::TextureSignature::Parameters::kNotUsed;
|
||||||
|
|
||||||
|
assert(pidx.texture != kNotUsed);
|
||||||
|
|
||||||
|
auto op = spv::Op::OpNop;
|
||||||
|
|
||||||
|
auto gen_param = [&](size_t idx) {
|
||||||
|
auto* p = call->params()[idx];
|
||||||
|
auto val_id = GenerateExpression(p);
|
||||||
|
if (val_id == 0) {
|
||||||
|
return Operand::Int(0);
|
||||||
|
}
|
||||||
|
val_id = GenerateLoadIfNeeded(p->result_type(), val_id);
|
||||||
|
|
||||||
|
return Operand::Int(val_id);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Populate the spirv_params with common parameters
|
||||||
|
OperandList spirv_params;
|
||||||
|
spirv_params.reserve(8); // Enough to fit most parameter lists
|
||||||
|
spirv_params.emplace_back(std::move(result_type)); // result type
|
||||||
|
spirv_params.emplace_back(std::move(result_id)); // result id
|
||||||
|
|
||||||
|
// Extra image operands, appended to spirv_params.
|
||||||
|
uint32_t spirv_operand_mask = 0;
|
||||||
|
OperandList spirv_operands;
|
||||||
|
spirv_operands.reserve(4); // Enough to fit most parameter lists
|
||||||
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kTextureLoad) {
|
if (ident->intrinsic() == ast::Intrinsic::kTextureLoad) {
|
||||||
std::vector<Operand> spirv_params = {
|
op = texture_type->IsStorage() ? spv::Op::OpImageRead
|
||||||
std::move(wgsl_params[0]), std::move(wgsl_params[1]),
|
: spv::Op::OpImageFetch;
|
||||||
std::move(wgsl_params[2]), std::move(wgsl_params[3])};
|
spirv_params.emplace_back(gen_param(pidx.texture));
|
||||||
if (texture_type->IsMultisampled()) {
|
spirv_params.emplace_back(gen_param(pidx.coords));
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsSampleMask));
|
|
||||||
|
// TODO(dsinclair): Remove the LOD param from textureLoad on storage
|
||||||
|
// textures when https://github.com/gpuweb/gpuweb/pull/1032 gets merged.
|
||||||
|
if (pidx.level != kNotUsed) {
|
||||||
|
if (texture_type->IsMultisampled()) {
|
||||||
|
spirv_operand_mask |= SpvImageOperandsSampleMask;
|
||||||
|
} else {
|
||||||
|
spirv_operand_mask |= SpvImageOperandsLodMask;
|
||||||
|
}
|
||||||
|
spirv_operands.emplace_back(gen_param(pidx.level));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
assert(pidx.sampler != kNotUsed);
|
||||||
|
|
||||||
|
auto sampler_param = gen_param(pidx.sampler);
|
||||||
|
auto texture_param = gen_param(pidx.texture);
|
||||||
|
auto sampled_image =
|
||||||
|
GenerateSampledImage(texture_type, texture_param, sampler_param);
|
||||||
|
|
||||||
|
// Populate the spirv_params with the common parameters
|
||||||
|
spirv_params.emplace_back(Operand::Int(sampled_image)); // sampled image
|
||||||
|
|
||||||
|
if (pidx.array_index != kNotUsed) {
|
||||||
|
// Array index needs to be appended to the coordinates.
|
||||||
|
auto* param_coords = call->params()[pidx.coords];
|
||||||
|
auto* param_array_index = call->params()[pidx.array_index];
|
||||||
|
|
||||||
|
uint32_t packed_coords_size;
|
||||||
|
ast::type::Type* packed_coords_el_ty; // Currenly must be f32.
|
||||||
|
if (param_coords->result_type()->IsVector()) {
|
||||||
|
auto* vec = param_coords->result_type()->AsVector();
|
||||||
|
packed_coords_size = vec->size() + 1;
|
||||||
|
packed_coords_el_ty = vec->type();
|
||||||
|
} else {
|
||||||
|
packed_coords_size = 2;
|
||||||
|
packed_coords_el_ty = param_coords->result_type();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cast param_array_index to the vector element type
|
||||||
|
ast::TypeConstructorExpression array_index_cast(packed_coords_el_ty,
|
||||||
|
{param_array_index});
|
||||||
|
array_index_cast.set_result_type(packed_coords_el_ty);
|
||||||
|
|
||||||
|
ast::type::VectorType packed_coords_ty(packed_coords_el_ty,
|
||||||
|
packed_coords_size);
|
||||||
|
|
||||||
|
ast::TypeConstructorExpression constructor{
|
||||||
|
&packed_coords_ty, {param_coords, &array_index_cast}};
|
||||||
|
auto packed_coords =
|
||||||
|
GenerateTypeConstructorExpression(&constructor, false);
|
||||||
|
|
||||||
|
spirv_params.emplace_back(Operand::Int(packed_coords)); // coordinates
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsLodMask));
|
spirv_params.emplace_back(gen_param(pidx.coords)); // coordinates
|
||||||
}
|
}
|
||||||
spirv_params.push_back(std::move(wgsl_params[4]));
|
|
||||||
|
|
||||||
auto op = spv::Op::OpImageFetch;
|
switch (ident->intrinsic()) {
|
||||||
if (texture_type->IsStorage()) {
|
case ast::Intrinsic::kTextureSample: {
|
||||||
op = spv::Op::OpImageRead;
|
op = spv::Op::OpImageSampleImplicitLod;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kTextureSampleBias: {
|
||||||
|
op = spv::Op::OpImageSampleImplicitLod;
|
||||||
|
assert(pidx.bias != kNotUsed);
|
||||||
|
spirv_operand_mask |= SpvImageOperandsBiasMask;
|
||||||
|
spirv_operands.emplace_back(gen_param(pidx.bias));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kTextureSampleLevel: {
|
||||||
|
op = spv::Op::OpImageSampleExplicitLod;
|
||||||
|
assert(pidx.level != kNotUsed);
|
||||||
|
spirv_operand_mask |= SpvImageOperandsLodMask;
|
||||||
|
spirv_operands.emplace_back(gen_param(pidx.level));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kTextureSampleGrad: {
|
||||||
|
op = spv::Op::OpImageSampleExplicitLod;
|
||||||
|
assert(pidx.ddx != kNotUsed);
|
||||||
|
assert(pidx.ddy != kNotUsed);
|
||||||
|
spirv_operand_mask |= SpvImageOperandsGradMask;
|
||||||
|
spirv_operands.emplace_back(gen_param(pidx.ddx));
|
||||||
|
spirv_operands.emplace_back(gen_param(pidx.ddy));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case ast::Intrinsic::kTextureSampleCompare: {
|
||||||
|
op = spv::Op::OpImageSampleDrefExplicitLod;
|
||||||
|
assert(pidx.depth_ref != kNotUsed);
|
||||||
|
spirv_params.emplace_back(gen_param(pidx.depth_ref));
|
||||||
|
|
||||||
|
spirv_operand_mask |= SpvImageOperandsLodMask;
|
||||||
|
ast::type::F32Type f32;
|
||||||
|
ast::FloatLiteral float_0(&f32, 0.0);
|
||||||
|
spirv_operands.emplace_back(
|
||||||
|
Operand::Int(GenerateLiteralIfNeeded(nullptr, &float_0)));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break; // unreachable
|
||||||
}
|
}
|
||||||
push_function_inst(op, spirv_params);
|
|
||||||
return result_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
spv::Op op = spv::Op::OpNop;
|
if (pidx.offset != kNotUsed) {
|
||||||
OperandList spirv_params = {
|
spirv_operand_mask |= SpvImageOperandsOffsetMask;
|
||||||
wgsl_params[0], std::move(wgsl_params[1]),
|
spirv_operands.emplace_back(gen_param(pidx.offset));
|
||||||
Operand::Int(GenerateSampledImage(texture_type, std::move(wgsl_params[2]),
|
|
||||||
std::move(wgsl_params[3]))),
|
|
||||||
std::move(wgsl_params[4])};
|
|
||||||
|
|
||||||
if (ident->intrinsic() == ast::Intrinsic::kTextureSample) {
|
|
||||||
op = spv::Op::OpImageSampleImplicitLod;
|
|
||||||
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleLevel) {
|
|
||||||
op = spv::Op::OpImageSampleExplicitLod;
|
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsLodMask));
|
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
|
||||||
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleBias) {
|
|
||||||
op = spv::Op::OpImageSampleImplicitLod;
|
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsBiasMask));
|
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
|
||||||
} else if (ident->intrinsic() == ast::Intrinsic::kTextureSampleCompare) {
|
|
||||||
op = spv::Op::OpImageSampleDrefExplicitLod;
|
|
||||||
spirv_params.push_back(std::move(wgsl_params[5]));
|
|
||||||
|
|
||||||
spirv_params.push_back(Operand::Int(SpvImageOperandsLodMask));
|
|
||||||
ast::type::F32Type f32;
|
|
||||||
ast::FloatLiteral float_0(&f32, 0.0);
|
|
||||||
spirv_params.push_back(
|
|
||||||
Operand::Int(GenerateLiteralIfNeeded(nullptr, &float_0)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spirv_operand_mask != 0) {
|
||||||
|
// Note: Order of operands is based on SpvImageXXXOperands value -
|
||||||
|
// smaller-numbered SpvImageXXXOperands bits appear first.
|
||||||
|
spirv_params.emplace_back(Operand::Int(spirv_operand_mask));
|
||||||
|
spirv_params.insert(std::end(spirv_params), std::begin(spirv_operands),
|
||||||
|
std::end(spirv_operands));
|
||||||
|
}
|
||||||
|
|
||||||
if (op == spv::Op::OpNop) {
|
if (op == spv::Op::OpNop) {
|
||||||
error_ = "unable to determine operator for: " + ident->name();
|
error_ = "unable to determine operator for: " + ident->name();
|
||||||
return 0;
|
return;
|
||||||
}
|
}
|
||||||
push_function_inst(op, spirv_params);
|
|
||||||
|
|
||||||
return result_id;
|
push_function_inst(op, spirv_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t Builder::GenerateSampledImage(ast::type::Type* texture_type,
|
uint32_t Builder::GenerateSampledImage(ast::type::Type* texture_type,
|
||||||
|
|
|
@ -231,7 +231,7 @@ class Builder {
|
||||||
bool GenerateExecutionModes(ast::Function* func, uint32_t id);
|
bool GenerateExecutionModes(ast::Function* func, uint32_t id);
|
||||||
/// Generates an expression
|
/// Generates an expression
|
||||||
/// @param expr the expression to generate
|
/// @param expr the expression to generate
|
||||||
/// @returns the resulting ID of the exp = {};ression or 0 on error
|
/// @returns the resulting ID of the expression or 0 on error
|
||||||
uint32_t GenerateExpression(ast::Expression* expr);
|
uint32_t GenerateExpression(ast::Expression* expr);
|
||||||
/// Generates the instructions for a function
|
/// Generates the instructions for a function
|
||||||
/// @param func the function to generate
|
/// @param func the function to generate
|
||||||
|
@ -335,14 +335,13 @@ class Builder {
|
||||||
/// Generates a texture intrinsic call
|
/// Generates a texture intrinsic call
|
||||||
/// @param ident the texture intrinsic
|
/// @param ident the texture intrinsic
|
||||||
/// @param call the call expression
|
/// @param call the call expression
|
||||||
/// @param result_id result ID of the texture instruction
|
/// @param result_type result type operand of the texture instruction
|
||||||
/// @param wgsl_params SPIR-V arguments for WGSL-specific intrinsic's call
|
/// @param result_id result identifier operand of the texture instruction
|
||||||
/// parameters
|
/// parameters
|
||||||
/// @returns the expression ID on success or 0 otherwise
|
void GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
||||||
uint32_t GenerateTextureIntrinsic(ast::IdentifierExpression* ident,
|
ast::CallExpression* call,
|
||||||
ast::CallExpression* call,
|
spirv::Operand result_type,
|
||||||
uint32_t result_id,
|
spirv::Operand result_id);
|
||||||
OperandList wgsl_params);
|
|
||||||
/// Generates a sampled image
|
/// Generates a sampled image
|
||||||
/// @param texture_type the texture type
|
/// @param texture_type the texture type
|
||||||
/// @param texture_operand the texture operand
|
/// @param texture_operand the texture operand
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue