Merge pull request #7328 from aws-lumberyard-dev/Atom/santorac/ShaderOptionValueUtils

Minor cleanup of some shader option related unit tests.
monroegm-disable-blank-issue-2
santorac 4 years ago committed by GitHub
commit 7cbcd5e145
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -14,6 +14,7 @@
#include <Atom/RHI.Reflect/NameIdReflectionMap.h>
#include <AzCore/std/smart_ptr/intrusive_base.h>
#include <AzCore/std/containers/span.h>
#include <AzCore/Memory/PoolAllocator.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Utils/TypeHash.h>
@ -44,6 +45,12 @@ namespace AZ
bool m_bakeEmptyAsDefault = false;
};
//! Creates a list of shader option values that can be used to construct a ShaderOptionDescriptor.
ShaderOptionValues CreateEnumShaderOptionValues(AZStd::span<const AZStd::string_view> enumNames);
ShaderOptionValues CreateEnumShaderOptionValues(AZStd::initializer_list<AZStd::string_view> enumNames);
ShaderOptionValues CreateBoolShaderOptionValues();
ShaderOptionValues CreateIntRangeShaderOptionValues(uint32_t min, uint32_t max);
//! Describes a shader option to the ShaderOptionGroupLayout class. Maps a shader option
//! to a set of bits in a mask in order to facilitate packing values into a mask to
//! form a ShaderKey.
@ -62,15 +69,16 @@ namespace AZ
//! @param optionType Type hint for the option - bool, enum, integer range, etc.
//! @param bitOffset Bit offset must match the ShaderOptionGroupLayout where this Option will be added
//! @param order The order (rank) of the shader option. Must be unique within a group. Lower order is higher priority.
//! @param nameIndexList List of valid (valueName, value) pairs for this Option
//! @param nameIndexList List of valid (valueName, value) pairs for this Option. See "Create*ShaderOptionValues" utility functions above.
//! @param defaultValue Default value name, which must also be in the nameIndexList. In the cases where the list
//! defines a range (IntegerRange for instance) defaultValue must be within the range instead.
//! If omitted, the first entry in @nameIndexList will be used.
ShaderOptionDescriptor(const Name& name,
const ShaderOptionType& optionType,
uint32_t bitOffset,
uint32_t order,
const AZStd::vector<RPI::ShaderOptionValuePair>& nameIndexList,
const Name& defaultValue);
const ShaderOptionValues& nameIndexList,
const Name& defaultValue = {});
AZ_DEFAULT_COPY_MOVE(ShaderOptionDescriptor);

@ -18,6 +18,7 @@ namespace AZ
using ShaderOptionIndex = RHI::Handle<uint32_t, class ShaderOptionIndexNamespace>; //!< ShaderOption index in the group layout
using ShaderOptionValue = RHI::Handle<uint32_t, class ShaderOptionValueNamespace>; //!< Numerical representation for a single value in the ShaderOption
using ShaderOptionValuePair = AZStd::pair<Name/*valueName*/, ShaderOptionValue>; //!< Provides a string representation for a ShaderOptionValue
using ShaderOptionValues = AZStd::vector<ShaderOptionValuePair>; //!< List of possible values for a shader option
enum class ShaderOptionType : uint32_t
{

@ -36,6 +36,35 @@ namespace AZ
}
}
ShaderOptionValues CreateEnumShaderOptionValues(AZStd::span<const AZStd::string_view> enumNames)
{
ShaderOptionValues values;
values.reserve(enumNames.size());
for (size_t i = 0; i < enumNames.size(); ++i)
{
values.emplace_back(Name{enumNames[i]}, i);
}
return values;
}
ShaderOptionValues CreateEnumShaderOptionValues(AZStd::initializer_list<AZStd::string_view> enumNames)
{
return CreateEnumShaderOptionValues(AZStd::span(enumNames.begin(), enumNames.end()));
}
ShaderOptionValues CreateBoolShaderOptionValues()
{
return CreateEnumShaderOptionValues({"False", "True"});
}
ShaderOptionValues CreateIntRangeShaderOptionValues(uint32_t min, uint32_t max)
{
AZStd::vector<RPI::ShaderOptionValuePair> intOptionRange;
intOptionRange.push_back({Name{AZStd::string::format("%u", min)}, RPI::ShaderOptionValue{min}});
intOptionRange.push_back({Name{AZStd::string::format("%u", max)}, RPI::ShaderOptionValue{max}});
return intOptionRange;
}
void ShaderOptionGroupHints::Reflect(ReflectContext* context)
{
if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
@ -90,7 +119,7 @@ namespace AZ
const ShaderOptionType& optionType,
uint32_t bitOffset,
uint32_t order,
const AZStd::vector<RPI::ShaderOptionValuePair>& nameIndexList,
const ShaderOptionValues& nameIndexList,
const Name& defaultValue)
: m_name{name}
@ -102,6 +131,11 @@ namespace AZ
for (auto pair : nameIndexList)
{ // Registers the pair in the lookup table
AddValue(pair.first, pair.second);
if (m_defaultValue.IsEmpty())
{
m_defaultValue = pair.first;
}
}
uint32_t numValues = (m_type == ShaderOptionType::IntegerRange) ? (m_maxValue.GetIndex() - m_minValue.GetIndex() + 1) : (uint32_t) nameIndexList.size();

@ -70,18 +70,9 @@ namespace UnitTest
AZ::RPI::Ptr<AZ::RPI::ShaderOptionGroupLayout> CreateCommonTestShaderOptionsLayout()
{
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)});
boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)});
AZStd::vector<RPI::ShaderOptionValuePair> intRangeOptionValues;
intRangeOptionValues.push_back({Name("0"), RPI::ShaderOptionValue(0)});
intRangeOptionValues.push_back({Name("15"), RPI::ShaderOptionValue(15)});
AZStd::vector<RPI::ShaderOptionValuePair> qualityOptionValues;
qualityOptionValues.push_back({Name("Quality::Low"), RPI::ShaderOptionValue(0)});
qualityOptionValues.push_back({Name("Quality::Medium"), RPI::ShaderOptionValue(1)});
qualityOptionValues.push_back({Name("Quality::High"), RPI::ShaderOptionValue(2)});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
AZStd::vector<RPI::ShaderOptionValuePair> intRangeOptionValues = CreateIntRangeShaderOptionValues(0, 15);
AZStd::vector<RPI::ShaderOptionValuePair> qualityOptionValues = CreateEnumShaderOptionValues({"Quality::Low", "Quality::Medium", "Quality::High"});
AZ::RPI::Ptr<AZ::RPI::ShaderOptionGroupLayout> shaderOptions = RPI::ShaderOptionGroupLayout::Create();
shaderOptions->AddShaderOption(ShaderOptionDescriptor{Name{"o_bool"}, ShaderOptionType::Boolean, 0, 0, boolOptionValues, Name{"False"}});

@ -127,9 +127,7 @@ namespace UnitTest
{
using namespace AZ::RPI;
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)});
boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
AZ::RPI::Ptr<AZ::RPI::ShaderOptionGroupLayout> shaderOptions = RPI::ShaderOptionGroupLayout::Create();
shaderOptions->AddShaderOption(ShaderOptionDescriptor{Name{"o_optionA"}, ShaderOptionType::Boolean, 0, 0, boolOptionValues, Name{"False"}});
@ -138,7 +136,6 @@ namespace UnitTest
shaderOptions->Finalize();
Data::Asset<MaterialTypeAsset> materialTypeAsset;
//Data::Asset<MaterialAsset> materialAsset;
// Note we don't actually need any properties or functors in the material type. We just need to set up some sample data
// structures that we can pass to the functors below, especially the shader with shader options.

@ -389,18 +389,9 @@ namespace UnitTest
Ptr<ShaderOptionGroupLayout> CreateTestOptionsLayout()
{
AZStd::vector<RPI::ShaderOptionValuePair> enumOptionValues;
enumOptionValues.push_back({Name("Low"), RPI::ShaderOptionValue(0)});
enumOptionValues.push_back({Name("Med"), RPI::ShaderOptionValue(1)});
enumOptionValues.push_back({Name("High"), RPI::ShaderOptionValue(2)});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)});
boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)});
AZStd::vector<RPI::ShaderOptionValuePair> rangeOptionValues;
rangeOptionValues.push_back({Name("1"), RPI::ShaderOptionValue(1)});
rangeOptionValues.push_back({Name("10"), RPI::ShaderOptionValue(10)});
AZStd::vector<RPI::ShaderOptionValuePair> enumOptionValues = CreateEnumShaderOptionValues({"Low", "Med", "High"});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
AZStd::vector<RPI::ShaderOptionValuePair> rangeOptionValues = CreateIntRangeShaderOptionValues(1, 10);
Ptr<ShaderOptionGroupLayout> shaderOptions = ShaderOptionGroupLayout::Create();
uint32_t order = 0;

@ -103,18 +103,9 @@ namespace UnitTest
m_testMaterialSrgLayout = CreateCommonTestMaterialSrgLayout();
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name{"False"}, RPI::ShaderOptionValue{0}});
boolOptionValues.push_back({Name{"True"}, RPI::ShaderOptionValue{1}});
AZStd::vector<RPI::ShaderOptionValuePair> enumOptionValues;
enumOptionValues.push_back({Name{"Low"}, RPI::ShaderOptionValue{0}});
enumOptionValues.push_back({Name{"Med"}, RPI::ShaderOptionValue{1}});
enumOptionValues.push_back({Name{"High"}, RPI::ShaderOptionValue{2}});
AZStd::vector<RPI::ShaderOptionValuePair> intOptionRange;
intOptionRange.push_back({Name{"0"}, RPI::ShaderOptionValue{0}});
intOptionRange.push_back({Name{"8"}, RPI::ShaderOptionValue{8}});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
AZStd::vector<RPI::ShaderOptionValuePair> enumOptionValues = CreateEnumShaderOptionValues({"Low", "Med", "High"});
AZStd::vector<RPI::ShaderOptionValuePair> intOptionRange = CreateIntRangeShaderOptionValues(0, 8);
m_testShaderOptionsLayout = ShaderOptionGroupLayout::Create();
uint32_t order = 0;
@ -977,9 +968,7 @@ namespace UnitTest
{
// Create shaders...
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)});
boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
Ptr<ShaderOptionGroupLayout> optionsForShaderA = ShaderOptionGroupLayout::Create();
optionsForShaderA->AddShaderOption(ShaderOptionDescriptor{Name{"o_globalOption_inBothShaders"}, ShaderOptionType::Boolean, 0, 0, boolOptionValues, Name{"False"}});

@ -289,10 +289,7 @@ namespace UnitTest
m_testMaterialSrgLayout->AddShaderInput(RHI::ShaderInputImageDescriptor{ Name{ "m_image" }, RHI::ShaderInputImageAccess::Read, RHI::ShaderInputImageType::Image2D, 1, 1 });
EXPECT_TRUE(m_testMaterialSrgLayout->Finalize());
AZStd::vector<RPI::ShaderOptionValuePair> optionValues;
optionValues.push_back({Name("Low"), RPI::ShaderOptionValue(0)});
optionValues.push_back({Name("Med"), RPI::ShaderOptionValue(1)});
optionValues.push_back({Name("High"), RPI::ShaderOptionValue(2)});
AZStd::vector<RPI::ShaderOptionValuePair> optionValues = CreateEnumShaderOptionValues({"Low", "Med", "High"});
Ptr<ShaderOptionGroupLayout> shaderOptions = ShaderOptionGroupLayout::Create();
uint32_t order = 0;
@ -703,10 +700,7 @@ namespace UnitTest
{
// Set up the shaders...
AZStd::vector<RPI::ShaderOptionValuePair> optionValues;
optionValues.push_back({Name("Low"), RPI::ShaderOptionValue(0)});
optionValues.push_back({Name("Med"), RPI::ShaderOptionValue(1)});
optionValues.push_back({Name("High"), RPI::ShaderOptionValue(2)});
AZStd::vector<RPI::ShaderOptionValuePair> optionValues = CreateEnumShaderOptionValues({"Low", "Med", "High"});
Ptr<ShaderOptionGroupLayout> shaderOptions = ShaderOptionGroupLayout::Create();
uint32_t order = 0;
@ -1072,10 +1066,7 @@ namespace UnitTest
{
// Setup the shader...
AZStd::vector<RPI::ShaderOptionValuePair> optionValues;
optionValues.push_back({ Name("Low"), RPI::ShaderOptionValue(0) });
optionValues.push_back({ Name("Med"), RPI::ShaderOptionValue(1) });
optionValues.push_back({ Name("High"), RPI::ShaderOptionValue(2) });
AZStd::vector<RPI::ShaderOptionValuePair> optionValues = CreateEnumShaderOptionValues({"Low", "Med", "High"});
uint32_t order = 0;
@ -1402,9 +1393,7 @@ namespace UnitTest
layeredMaterialSrgLayout->AddShaderInput(RHI::ShaderInputConstantDescriptor{ Name{ "m_blendFactor" }, 4, 4, 0 });
layeredMaterialSrgLayout->Finalize();
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues;
boolOptionValues.push_back({Name("False"), RPI::ShaderOptionValue(0)});
boolOptionValues.push_back({Name("True"), RPI::ShaderOptionValue(1)});
AZStd::vector<RPI::ShaderOptionValuePair> boolOptionValues = CreateBoolShaderOptionValues();
Ptr<ShaderOptionGroupLayout> shaderOptionsLayout = ShaderOptionGroupLayout::Create();
uint32_t order = 0;
shaderOptionsLayout->AddShaderOption(ShaderOptionDescriptor{Name{"o_layer2_clearCoat_enable"}, ShaderOptionType::Boolean, 0, order++, boolOptionValues, Name{"False"}});

@ -793,16 +793,6 @@ namespace UnitTest
EXPECT_FALSE(success);
errorMessageFinder.CheckExpectedErrorsFound();
// Add shader option with an empty default value.
errorMessageFinder.Reset();
errorMessageFinder.AddExpectedErrorMessage("invalid default value");
AZStd::vector<RPI::ShaderOptionValuePair> list5;
list5.push_back({ Name("0"), RPI::ShaderOptionValue(0) }); // 1+ bit
list5.push_back({ Name("1"), RPI::ShaderOptionValue(1) }); // ...
success = shaderOptionGroupLayout->AddShaderOption(AZ::RPI::ShaderOptionDescriptor{ Name{"Invalid"}, intRangeType, 16, order++, list5, Name() });
EXPECT_FALSE(success);
errorMessageFinder.CheckExpectedErrorsFound();
// Add shader option with an invalid default int value.
errorMessageFinder.Reset();
errorMessageFinder.AddExpectedErrorMessage("invalid default value");
@ -887,6 +877,18 @@ namespace UnitTest
EXPECT_FALSE(shaderOptionGroupLayout->FindShaderOptionIndex(Name{ "Invalid" }).IsValid());
}
TEST_F(ShaderTests, ImplicitDefaultValue)
{
// Add shader option with no default value.
RPI::Ptr<RPI::ShaderOptionGroupLayout> shaderOptionGroupLayout = RPI::ShaderOptionGroupLayout::Create();
AZStd::vector<RPI::ShaderOptionValuePair> values = AZ::RPI::CreateEnumShaderOptionValues({"A", "B", "C"});
bool success = shaderOptionGroupLayout->AddShaderOption(AZ::RPI::ShaderOptionDescriptor{ Name{"NoDefaultSpecified"}, RPI::ShaderOptionType::Enumeration, 0, 0, values });
EXPECT_TRUE(success);
EXPECT_STREQ("A", shaderOptionGroupLayout->GetShaderOptions().back().GetDefaultValue().GetCStr());
}
TEST_F(ShaderTests, ShaderOptionGroupTest)
{
using namespace AZ;

Loading…
Cancel
Save