Skip to content

Commit

Permalink
Add DEVICE_PROPERTY support (#1034)
Browse files Browse the repository at this point in the history
For certain cases device properties need to be checked same way as device features.

For example VK_KHR_shader_float_controls extension have a set of fields (DenormPreserve) that are available in VkPhysicalDeviceFloatControlsProperties.
  • Loading branch information
archimedus authored May 13, 2024
1 parent 8dec25a commit 0f003c2
Show file tree
Hide file tree
Showing 16 changed files with 285 additions and 4 deletions.
12 changes: 12 additions & 0 deletions include/amber/amber_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,18 @@ struct VulkanEngineConfig : public EngineConfig {
/// the extension is not enabled, |available_features| will be used.
VkPhysicalDeviceFeatures2KHR available_features2;

/// Physical device properties available for |physical_device|. The
/// |available_properties| will be ignored if
/// VK_KHR_get_physical_device_properties2 is enabled, |available_properties2|
/// will be used in that case.
VkPhysicalDeviceProperties available_properties;

/// Physical device properties for |physical_device|.The
/// |available_properties2| will only be used if
/// VK_KHR_get_physical_device_properties2 is enabled. If the extension is not
/// enabled, |available_properties| will be used.
VkPhysicalDeviceProperties2KHR available_properties2;

/// Instance extensions available.
std::vector<std::string> available_instance_extensions;

Expand Down
6 changes: 6 additions & 0 deletions include/amber/recipe.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ class RecipeImpl {
/// Returns required features in the given recipe.
virtual std::vector<std::string> GetRequiredFeatures() const = 0;

/// Returns required features in the given recipe.
virtual std::vector<std::string> GetRequiredProperties() const = 0;

/// Returns required device extensions in the given recipe.
virtual std::vector<std::string> GetRequiredDeviceExtensions() const = 0;

Expand Down Expand Up @@ -67,6 +70,9 @@ class Recipe {
/// Returns required features in the given recipe.
std::vector<std::string> GetRequiredFeatures() const;

/// Returns required properties in the given recipe.
std::vector<std::string> GetRequiredProperties() const;

/// Returns required device extensions in the given recipe.
std::vector<std::string> GetRequiredDeviceExtensions() const;

Expand Down
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ if (${AMBER_ENABLE_TESTS})
amberscript/parser_copy_test.cc
amberscript/parser_depth_test.cc
amberscript/parser_device_feature_test.cc
amberscript/parser_device_property_test.cc
amberscript/parser_expect_test.cc
amberscript/parser_extension_test.cc
amberscript/parser_framebuffer_test.cc
Expand Down
1 change: 1 addition & 0 deletions src/amber.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ Result CreateEngineAndCheckRequirements(const Recipe* recipe,
// much else. Refactor this if they end up doing to much here.
Result r =
engine->Initialize(opts->config, delegate, script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());
if (!r.IsSuccess())
Expand Down
16 changes: 16 additions & 0 deletions src/amberscript/parser.cc
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,8 @@ Result Parser::Parse(const std::string& data) {
r = ParseDeviceFeature();
} else if (tok == "DEVICE_EXTENSION") {
r = ParseDeviceExtension();
} else if (tok == "DEVICE_PROPERTY") {
r = ParseDeviceProperty();
} else if (tok == "IMAGE") {
r = ParseImage();
} else if (tok == "INSTANCE_EXTENSION") {
Expand Down Expand Up @@ -3421,6 +3423,20 @@ Result Parser::ParseDeviceFeature() {
return ValidateEndOfStatement("DEVICE_FEATURE command");
}

Result Parser::ParseDeviceProperty() {
auto token = tokenizer_->NextToken();
if (token->IsEOS() || token->IsEOL())
return Result("missing property name for DEVICE_PROPERTY command");
if (!token->IsIdentifier())
return Result("invalid property name for DEVICE_PROPERTY command");
if (!script_->IsKnownProperty(token->AsString()))
return Result("unknown property name for DEVICE_PROPERTY command");

script_->AddRequiredProperty(token->AsString());

return ValidateEndOfStatement("DEVICE_PROPERTY command");
}

Result Parser::ParseRepeat() {
auto token = tokenizer_->NextToken();
if (token->IsEOL() || token->IsEOL())
Expand Down
1 change: 1 addition & 0 deletions src/amberscript/parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class Parser : public amber::Parser {
Result ParseCopy();
Result ParseDeviceFeature();
Result ParseDeviceExtension();
Result ParseDeviceProperty();
Result ParseInstanceExtension();
Result ParseRepeat();
Result ParseSet();
Expand Down
120 changes: 120 additions & 0 deletions src/amberscript/parser_device_property_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
// Copyright 2024 The Amber 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 parseried.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "gtest/gtest.h"
#include "src/amberscript/parser.h"

namespace amber {
namespace amberscript {

using AmberScriptParserTest = testing::Test;

TEST_F(AmberScriptParserTest, DeviceProperty) {
std::string in = R"(
DEVICE_PROPERTY FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat16
DEVICE_PROPERTY FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat32
DEVICE_PROPERTY FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat64
DEVICE_PROPERTY FloatControlsProperties.shaderDenormPreserveFloat16
DEVICE_PROPERTY FloatControlsProperties.shaderDenormPreserveFloat32
DEVICE_PROPERTY FloatControlsProperties.shaderDenormPreserveFloat64
DEVICE_PROPERTY FloatControlsProperties.shaderDenormFlushToZeroFloat16
DEVICE_PROPERTY FloatControlsProperties.shaderDenormFlushToZeroFloat32
DEVICE_PROPERTY FloatControlsProperties.shaderDenormFlushToZeroFloat64
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTEFloat16
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTEFloat32
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTEFloat64
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTZFloat16
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTZFloat32
DEVICE_PROPERTY FloatControlsProperties.shaderRoundingModeRTZFloat64)";

Parser parser;
Result r = parser.Parse(in);
ASSERT_TRUE(r.IsSuccess()) << r.Error();

auto script = parser.GetScript();
const auto& properties = script->GetRequiredProperties();
ASSERT_EQ(15U, properties.size());
EXPECT_EQ("FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat16",
properties[0]);
EXPECT_EQ("FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat32",
properties[1]);
EXPECT_EQ("FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat64",
properties[2]);
EXPECT_EQ("FloatControlsProperties.shaderDenormPreserveFloat16",
properties[3]);
EXPECT_EQ("FloatControlsProperties.shaderDenormPreserveFloat32",
properties[4]);
EXPECT_EQ("FloatControlsProperties.shaderDenormPreserveFloat64",
properties[5]);
EXPECT_EQ("FloatControlsProperties.shaderDenormFlushToZeroFloat16",
properties[6]);
EXPECT_EQ("FloatControlsProperties.shaderDenormFlushToZeroFloat32",
properties[7]);
EXPECT_EQ("FloatControlsProperties.shaderDenormFlushToZeroFloat64",
properties[8]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTEFloat16",
properties[9]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTEFloat32",
properties[10]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTEFloat64",
properties[11]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTZFloat16",
properties[12]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTZFloat32",
properties[13]);
EXPECT_EQ("FloatControlsProperties.shaderRoundingModeRTZFloat64",
properties[14]);
}

TEST_F(AmberScriptParserTest, DevicePropertyMissingProperty) {
std::string in = "DEVICE_PROPERTY";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("1: missing property name for DEVICE_PROPERTY command", r.Error());
}

TEST_F(AmberScriptParserTest, DevicePropertyUnknown) {
std::string in = "DEVICE_PROPERTY unknown";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("1: unknown property name for DEVICE_PROPERTY command", r.Error());
}

TEST_F(AmberScriptParserTest, DevicePropertyInvalid) {
std::string in = "DEVICE_PROPERTY 12345";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("1: invalid property name for DEVICE_PROPERTY command", r.Error());
}

TEST_F(AmberScriptParserTest, DevicePropertyExtraParams) {
std::string in =
"DEVICE_PROPERTY FloatControlsProperties.shaderDenormPreserveFloat16 "
"EXTRA";

Parser parser;
Result r = parser.Parse(in);
ASSERT_FALSE(r.IsSuccess());
EXPECT_EQ("1: extra parameters after DEVICE_PROPERTY command: EXTRA",
r.Error());
}

} // namespace amberscript
} // namespace amber
1 change: 1 addition & 0 deletions src/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ class Engine {
EngineConfig* config,
Delegate* delegate,
const std::vector<std::string>& features,
const std::vector<std::string>& properties,
const std::vector<std::string>& instance_extensions,
const std::vector<std::string>& device_extensions) = 0;

Expand Down
13 changes: 11 additions & 2 deletions src/executor_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,11 @@ class EngineStub : public Engine {
Result Initialize(EngineConfig*,
Delegate*,
const std::vector<std::string>& features,
const std::vector<std::string>& properties,
const std::vector<std::string>& instance_exts,
const std::vector<std::string>& device_exts) override {
features_ = features;
properties_ = properties;
instance_extensions_ = instance_exts;
device_extensions_ = device_exts;
return {};
Expand Down Expand Up @@ -193,6 +195,7 @@ class EngineStub : public Engine {
bool did_buffer_command_ = false;

std::vector<std::string> features_;
std::vector<std::string> properties_;
std::vector<std::string> instance_extensions_;
std::vector<std::string> device_extensions_;

Expand All @@ -207,11 +210,12 @@ class VkScriptExecutorTest : public testing::Test {
std::unique_ptr<Engine> MakeEngine() { return MakeUnique<EngineStub>(); }
std::unique_ptr<Engine> MakeAndInitializeEngine(
const std::vector<std::string>& features,
const std::vector<std::string>& properties,
const std::vector<std::string>& instance_extensions,
const std::vector<std::string>& device_extensions) {
std::unique_ptr<Engine> engine = MakeUnique<EngineStub>();
engine->Initialize(nullptr, nullptr, features, instance_extensions,
device_extensions);
engine->Initialize(nullptr, nullptr, features, properties,
instance_extensions, device_extensions);
return engine;
}
EngineStub* ToStub(Engine* engine) {
Expand All @@ -233,6 +237,7 @@ logicOp)";

auto script = parser.GetScript();
auto engine = MakeAndInitializeEngine(script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());

Expand Down Expand Up @@ -263,6 +268,7 @@ VK_KHR_variable_pointers)";

auto script = parser.GetScript();
auto engine = MakeAndInitializeEngine(script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());

Expand Down Expand Up @@ -293,6 +299,7 @@ depthstencil D24_UNORM_S8_UINT)";

auto script = parser.GetScript();
auto engine = MakeAndInitializeEngine(script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());

Expand Down Expand Up @@ -320,6 +327,7 @@ fence_timeout 12345)";

auto script = parser.GetScript();
auto engine = MakeAndInitializeEngine(script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());

Expand Down Expand Up @@ -355,6 +363,7 @@ fence_timeout 12345)";

auto script = parser.GetScript();
auto engine = MakeAndInitializeEngine(script->GetRequiredFeatures(),
script->GetRequiredProperties(),
script->GetRequiredInstanceExtensions(),
script->GetRequiredDeviceExtensions());

Expand Down
4 changes: 4 additions & 0 deletions src/recipe.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ std::vector<std::string> Recipe::GetRequiredFeatures() const {
return impl_ ? impl_->GetRequiredFeatures() : std::vector<std::string>();
}

std::vector<std::string> Recipe::GetRequiredProperties() const {
return impl_ ? impl_->GetRequiredProperties() : std::vector<std::string>();
}

std::vector<std::string> Recipe::GetRequiredDeviceExtensions() const {
return impl_ ? impl_->GetRequiredDeviceExtensions()
: std::vector<std::string>();
Expand Down
21 changes: 21 additions & 0 deletions src/script.cc
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,27 @@ bool Script::IsKnownFeature(const std::string& name) const {
"ShaderSubgroupExtendedTypesFeatures.shaderSubgroupExtendedTypes";
}

bool Script::IsKnownProperty(const std::string& name) const {
return name ==
"FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat16" ||
name ==
"FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat32" ||
name ==
"FloatControlsProperties.shaderSignedZeroInfNanPreserveFloat64" ||
name == "FloatControlsProperties.shaderDenormPreserveFloat16" ||
name == "FloatControlsProperties.shaderDenormPreserveFloat32" ||
name == "FloatControlsProperties.shaderDenormPreserveFloat64" ||
name == "FloatControlsProperties.shaderDenormFlushToZeroFloat16" ||
name == "FloatControlsProperties.shaderDenormFlushToZeroFloat32" ||
name == "FloatControlsProperties.shaderDenormFlushToZeroFloat64" ||
name == "FloatControlsProperties.shaderRoundingModeRTEFloat16" ||
name == "FloatControlsProperties.shaderRoundingModeRTEFloat32" ||
name == "FloatControlsProperties.shaderRoundingModeRTEFloat64" ||
name == "FloatControlsProperties.shaderRoundingModeRTZFloat16" ||
name == "FloatControlsProperties.shaderRoundingModeRTZFloat32" ||
name == "FloatControlsProperties.shaderRoundingModeRTZFloat64";
}

type::Type* Script::ParseType(const std::string& str) {
auto type = GetType(str);
if (type)
Expand Down
19 changes: 19 additions & 0 deletions src/script.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class Script : public RecipeImpl {
~Script() override;

bool IsKnownFeature(const std::string& name) const;
bool IsKnownProperty(const std::string& name) const;

/// Retrieves information on the shaders in the given script.
std::vector<ShaderInfo> GetShaderInfo() const override;
Expand All @@ -52,6 +53,10 @@ class Script : public RecipeImpl {
return engine_info_.required_features;
}

std::vector<std::string> GetRequiredProperties() const override {
return engine_info_.required_properties;
}

/// Returns required device extensions in the given recipe.
std::vector<std::string> GetRequiredDeviceExtensions() const override {
return engine_info_.required_device_extensions;
Expand Down Expand Up @@ -166,13 +171,26 @@ class Script : public RecipeImpl {
engine_info_.required_features.push_back(feature);
}

/// Adds |prop| to the list of properties that must be supported by the
/// engine.
void AddRequiredProperty(const std::string& prop) {
engine_info_.required_properties.push_back(prop);
}

/// Checks if |feature| is in required features
bool IsRequiredFeature(const std::string& feature) const {
return std::find(engine_info_.required_features.begin(),
engine_info_.required_features.end(),
feature) != engine_info_.required_features.end();
}

/// Checks if |prop| is in required features
bool IsRequiredProperty(const std::string& prop) const {
return std::find(engine_info_.required_properties.begin(),
engine_info_.required_properties.end(),
prop) != engine_info_.required_properties.end();
}

/// Adds |ext| to the list of device extensions that must be supported.
void AddRequiredDeviceExtension(const std::string& ext) {
engine_info_.required_device_extensions.push_back(ext);
Expand Down Expand Up @@ -257,6 +275,7 @@ class Script : public RecipeImpl {
private:
struct {
std::vector<std::string> required_features;
std::vector<std::string> required_properties;
std::vector<std::string> required_device_extensions;
std::vector<std::string> required_instance_extensions;
} engine_info_;
Expand Down
Loading

0 comments on commit 0f003c2

Please sign in to comment.