diff --git a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp index 99cc75b1c6..8dd0b60b07 100644 --- a/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp +++ b/src/gpu/effects/generated/GrColorMatrixFragmentProcessor.cpp @@ -77,6 +77,7 @@ private: const SkM44& mValue = _outer.m; if (mPrev != (mValue)) { mPrev = mValue; + static_assert(1 == 1); pdman.setSkM44(mVar, mValue); } const SkV4& vValue = _outer.v; diff --git a/src/sksl/SkSLCPPCodeGenerator.cpp b/src/sksl/SkSLCPPCodeGenerator.cpp index 478f0f5e82..da8e3eb067 100644 --- a/src/sksl/SkSLCPPCodeGenerator.cpp +++ b/src/sksl/SkSLCPPCodeGenerator.cpp @@ -148,6 +148,18 @@ String CPPCodeGenerator::formatRuntimeValue(const Type& type, const Layout& layout, const String& cppCode, std::vector* formatArgs) { + if (type.kind() == Type::kArray_Kind) { + String result("["); + const char* separator = ""; + for (int i = 0; i < type.columns(); i++) { + result += separator + this->formatRuntimeValue(type.componentType(), layout, + "(" + cppCode + ")[" + to_string(i) + + "]", formatArgs); + separator = ","; + } + result += "]"; + return result; + } if (type.isFloat()) { formatArgs->push_back(cppCode); return "%f"; @@ -652,11 +664,21 @@ void CPPCodeGenerator::addUniform(const Variable& var) { if (var.fModifiers.fLayout.fWhen.fLength) { this->writef(" if (%s) {\n ", String(var.fModifiers.fLayout.fWhen).c_str()); } - const char* type = glsltype_string(fContext, var.fType); String name(var.fName); - this->writef(" %sVar = args.fUniformHandler->addUniform(&_outer, kFragment_GrShaderFlag," - " %s, \"%s\");\n", HCodeGenerator::FieldName(name.c_str()).c_str(), type, - name.c_str()); + if (var.fType.kind() != Type::kArray_Kind) { + this->writef(" %sVar = args.fUniformHandler->addUniform(&_outer, " + "kFragment_GrShaderFlag, %s, \"%s\");\n", + HCodeGenerator::FieldName(name.c_str()).c_str(), + glsltype_string(fContext, var.fType), + name.c_str()); + } else { + this->writef(" %sVar = args.fUniformHandler->addUniformArray(&_outer, " + "kFragment_GrShaderFlag, %s, \"%s\", %d);\n", + HCodeGenerator::FieldName(name.c_str()).c_str(), + glsltype_string(fContext, var.fType.componentType()), + name.c_str(), + var.fType.columns()); + } if (var.fModifiers.fLayout.fWhen.fLength) { this->write(" }\n"); } diff --git a/src/sksl/SkSLCPPUniformCTypes.cpp b/src/sksl/SkSLCPPUniformCTypes.cpp index b36ae1e29e..1abdaa6ffa 100644 --- a/src/sksl/SkSLCPPUniformCTypes.cpp +++ b/src/sksl/SkSLCPPUniformCTypes.cpp @@ -9,6 +9,8 @@ #include "src/sksl/SkSLHCodeGenerator.h" #include "src/sksl/SkSLStringStream.h" +#include +#include #include #if defined(SKSL_STANDALONE) || defined(GR_TEST_UTILS) @@ -109,38 +111,81 @@ String UniformCTypeMapper::saveState(const String& newVar, const String& oldVar) String UniformCTypeMapper::setUniform(const String& pdman, const String& uniform, const String& var) const { - std::vector tokens = { "pdman", "uniform", "var" }; - std::vector values = { &pdman, &uniform, &var }; - return eval_template(fUniformTemplate, tokens, values); + std::vector tokens = { "pdman", "uniform", "var", "count" }; + String count; + String finalVar; + const String* activeTemplate; + if (fArrayCount != -1) { + count = to_string(fArrayCount); + finalVar = var + "[0]"; + activeTemplate = &fUniformArrayTemplate; + } else { + count = "1"; + finalVar = std::move(var); + activeTemplate = &fUniformSingleTemplate; + } + std::vector values = { &pdman, &uniform, &finalVar, &count }; + return eval_template(*activeTemplate, tokens, values); } UniformCTypeMapper::UniformCTypeMapper( - Layout::CType ctype, const std::vector& skslTypes, const String& setUniformFormat, + Layout::CType ctype, const std::vector& skslTypes, + const String& setUniformSingleFormat, const String& setUniformArrayFormat, bool enableTracking, const String& defaultValue, const String& dirtyExpressionFormat, const String& saveStateFormat) : fCType(ctype) , fSKSLTypes(skslTypes) - , fUniformTemplate(setUniformFormat) - , fInlineValue(determine_inline_from_template(setUniformFormat)) + , fUniformSingleTemplate(setUniformSingleFormat) + , fUniformArrayTemplate(setUniformArrayFormat) + , fInlineValue(determine_inline_from_template(setUniformSingleFormat) && + determine_inline_from_template(setUniformArrayFormat)) , fSupportsTracking(enableTracking) , fDefaultValue(defaultValue) , fDirtyExpressionTemplate(dirtyExpressionFormat) - , fSaveStateTemplate(saveStateFormat) { } + , fSaveStateTemplate(saveStateFormat) {} -// NOTE: These would be macros, but C++ initialization lists for the sksl type names do not play -// well with macro parsing. +const UniformCTypeMapper* UniformCTypeMapper::arrayMapper(int count) const { + static std::mutex mutex; + std::lock_guard guard(mutex); + using Key = std::pair; + static std::map registered; + Key key(this, count); + auto result = registered.find(key); + if (result == registered.end()) { + auto [iter, didInsert] = registered.insert({key, *this}); + SkASSERT(didInsert); + UniformCTypeMapper* inserted = &iter->second; + inserted->fArrayCount = count; + return inserted; + } + return &result->second; +} -static UniformCTypeMapper REGISTER(Layout::CType ctype, const std::vector& skslTypes, - const char* uniformFormat, const char* defaultValue, - const char* dirtyExpression) { - return UniformCTypeMapper(ctype, skslTypes, uniformFormat, defaultValue, dirtyExpression, + +static UniformCTypeMapper register_array(Layout::CType ctype, const std::vector& skslTypes, + const char* singleSet, const char* arraySet, + const char* defaultValue, const char* dirtyExpression) { + return UniformCTypeMapper(ctype, skslTypes, singleSet, arraySet, defaultValue, dirtyExpression, "${oldVar} = ${newVar}"); } -static UniformCTypeMapper REGISTER(Layout::CType ctype, const std::vector& skslTypes, +static UniformCTypeMapper register_array(Layout::CType ctype, const std::vector& skslTypes, + const char* singleSet, const char* arraySet, + const char* defaultValue) { + return register_array(ctype, skslTypes, singleSet, arraySet, defaultValue, + "${oldVar} != ${newVar}"); +} + +static UniformCTypeMapper register_type(Layout::CType ctype, const std::vector& skslTypes, + const char* uniformFormat, const char* defaultValue, + const char* dirtyExpression) { + return register_array(ctype, skslTypes, uniformFormat, uniformFormat, defaultValue, + dirtyExpression); +} + +static UniformCTypeMapper register_type(Layout::CType ctype, const std::vector& skslTypes, const char* uniformFormat, const char* defaultValue) { - return REGISTER(ctype, skslTypes, uniformFormat, defaultValue, - "${oldVar} != ${newVar}"); + return register_array(ctype, skslTypes, uniformFormat, uniformFormat, defaultValue); } ////////////////////////////// @@ -149,49 +194,53 @@ static UniformCTypeMapper REGISTER(Layout::CType ctype, const std::vector& get_mappers() { static const std::vector registeredMappers = { - REGISTER(Layout::CType::kSkRect, { "half4", "float4", "double4" }, - "${pdman}.set4fv(${uniform}, 1, reinterpret_cast(&${var}))", // to gpu + register_type(Layout::CType::kSkRect, { "half4", "float4", "double4" }, + "${pdman}.set4fv(${uniform}, ${count}, reinterpret_cast(&${var}))", // to gpu "SkRect::MakeEmpty()", // default value "${oldVar}.isEmpty() || ${oldVar} != ${newVar}"), // dirty check - REGISTER(Layout::CType::kSkIRect, { "int4", "short4", "byte4" }, - "${pdman}.set4iv(${uniform}, 1, reinterpret_cast(&${var}))", // to gpu + register_type(Layout::CType::kSkIRect, { "int4", "short4", "byte4" }, + "${pdman}.set4iv(${uniform}, ${count}, reinterpret_cast(&${var}))", // to gpu "SkIRect::MakeEmpty()", // default value "${oldVar}.isEmpty() || ${oldVar} != ${newVar}"), // dirty check - REGISTER(Layout::CType::kSkPMColor4f, { "half4", "float4", "double4" }, - "${pdman}.set4fv(${uniform}, 1, ${var}.vec())", // to gpu + register_type(Layout::CType::kSkPMColor4f, { "half4", "float4", "double4" }, + "${pdman}.set4fv(${uniform}, ${count}, ${var}.vec())", // to gpu "{SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}"), // default value - REGISTER(Layout::CType::kSkV4, { "half4", "float4", "double4" }, - "${pdman}.set4fv(${uniform}, 1, ${var}.ptr())", // to gpu + register_type(Layout::CType::kSkV4, { "half4", "float4", "double4" }, + "${pdman}.set4fv(${uniform}, ${count}, ${var}.ptr())", // to gpu "SkV4{SK_FloatNaN, SK_FloatNaN, SK_FloatNaN, SK_FloatNaN}", // default value "${oldVar} != (${newVar})"), // dirty check - REGISTER(Layout::CType::kSkPoint, { "half2", "float2", "double2" } , - "${pdman}.set2f(${uniform}, ${var}.fX, ${var}.fY)", // to gpu + register_array(Layout::CType::kSkPoint, { "half2", "float2", "double2" } , + "${pdman}.set2f(${uniform}, ${var}.fX, ${var}.fY)", // single + "${pdman}.set2fv(${uniform}, ${count}, &${var}.fX)", // array "SkPoint::Make(SK_FloatNaN, SK_FloatNaN)"), // default value - REGISTER(Layout::CType::kSkIPoint, { "int2", "short2", "byte2" }, - "${pdman}.set2i(${uniform}, ${var}.fX, ${var}.fY)", // to gpu + register_array(Layout::CType::kSkIPoint, { "int2", "short2", "byte2" }, + "${pdman}.set2i(${uniform}, ${var}.fX, ${var}.fY)", // single + "${pdman}.set2iv(${uniform}, ${count}, ${var}.fX, ${var}.fY)", // array "SkIPoint::Make(SK_NaN32, SK_NaN32)"), // default value - REGISTER(Layout::CType::kSkMatrix, { "half3x3", "float3x3", "double3x3" }, - "${pdman}.setSkMatrix(${uniform}, ${var})", // to gpu + register_type(Layout::CType::kSkMatrix, { "half3x3", "float3x3", "double3x3" }, + "static_assert(${count} == 1); ${pdman}.setSkMatrix(${uniform}, ${var})", // to gpu "SkMatrix::Scale(SK_FloatNaN, SK_FloatNaN)", // default value "!${oldVar}.cheapEqualTo(${newVar})"), // dirty check - REGISTER(Layout::CType::kSkM44, { "half4x4", "float4x4", "double4x4" }, - "${pdman}.setSkM44(${uniform}, ${var})", // to gpu + register_type(Layout::CType::kSkM44, { "half4x4", "float4x4", "double4x4" }, + "static_assert(${count} == 1); ${pdman}.setSkM44(${uniform}, ${var})", // to gpu "SkM44(SkM44::kNaN_Constructor)", // default value "${oldVar} != (${newVar})"), // dirty check - REGISTER(Layout::CType::kFloat, { "half", "float", "double" }, - "${pdman}.set1f(${uniform}, ${var})", // to gpu + register_array(Layout::CType::kFloat, { "half", "float", "double" }, + "${pdman}.set1f(${uniform}, ${var})", // single + "${pdman}.set1fv(${uniform}, ${count}, &${var})", // array "SK_FloatNaN"), // default value - REGISTER(Layout::CType::kInt32, { "int", "short", "byte" }, - "${pdman}.set1i(${uniform}, ${var})", // to gpu + register_array(Layout::CType::kInt32, { "int", "short", "byte" }, + "${pdman}.set1i(${uniform}, ${var})", // single + "${pdman}.set1iv(${uniform}, ${count}, &${var})", // array "SK_NaN32"), // default value }; @@ -204,6 +253,10 @@ static const std::vector& get_mappers() { // ctype and supports the sksl type of the variable. const UniformCTypeMapper* UniformCTypeMapper::Get(const Context& context, const Type& type, const Layout& layout) { + if (type.kind() == Type::kArray_Kind) { + const UniformCTypeMapper* base = Get(context, type.componentType(), layout); + return base ? base->arrayMapper(type.columns()) : nullptr; + } const std::vector& registeredMappers = get_mappers(); Layout::CType ctype = layout.fCType; diff --git a/src/sksl/SkSLCPPUniformCTypes.h b/src/sksl/SkSLCPPUniformCTypes.h index 076dda31f4..c6d3686aa5 100644 --- a/src/sksl/SkSLCPPUniformCTypes.h +++ b/src/sksl/SkSLCPPUniformCTypes.h @@ -34,17 +34,11 @@ namespace SkSL { // semicolons or newlines, which will be handled by the code generation itself. class UniformCTypeMapper { public: - // Create a templated mapper that does not support state tracking UniformCTypeMapper(Layout::CType ctype, const std::vector& skslTypes, - const char* setUniformFormat) - : UniformCTypeMapper(ctype, skslTypes, setUniformFormat, false, "", "", "") { } - - // Create a templated mapper that provides extra patterns for the state - // tracking expressions. - UniformCTypeMapper(Layout::CType ctype, const std::vector& skslTypes, - const String& setUniformFormat, const String& defaultValue, - const String& dirtyExpressionFormat, const String& saveStateFormat) - : UniformCTypeMapper(ctype, skslTypes, setUniformFormat, + const String& setUniformSingleFormat, const String& setUniformArrayFormat, + const String& defaultValue = "", const String& dirtyExpressionFormat = "", + const String& saveStateFormat = "") + : UniformCTypeMapper(ctype, skslTypes, setUniformSingleFormat, setUniformArrayFormat, true, defaultValue, dirtyExpressionFormat, saveStateFormat) { } // Returns nullptr if the type and layout are not supported; the returned pointer's ownership @@ -116,12 +110,17 @@ public: private: UniformCTypeMapper(Layout::CType ctype, const std::vector& skslTypes, - const String& setUniformFormat, bool enableTracking, const String& defaultValue, - const String& dirtyExpressionFormat, const String& saveStateFormat); + const String& setUniformSingleFormat, const String& setUniformArrayFormat, + bool enableTracking, const String& defaultValue, const String& dirtyExpressionFormat, + const String& saveStateFormat); + + const UniformCTypeMapper* arrayMapper(int arrayCount) const; Layout::CType fCType; + int fArrayCount = -1; std::vector fSKSLTypes; - String fUniformTemplate; + String fUniformSingleTemplate; + String fUniformArrayTemplate; bool fInlineValue; // Cached value calculated from fUniformTemplate bool fSupportsTracking; diff --git a/src/sksl/SkSLHCodeGenerator.cpp b/src/sksl/SkSLHCodeGenerator.cpp index 012b302481..40b6c6984f 100644 --- a/src/sksl/SkSLHCodeGenerator.cpp +++ b/src/sksl/SkSLHCodeGenerator.cpp @@ -33,6 +33,10 @@ HCodeGenerator::HCodeGenerator(const Context* context, const Program* program, String HCodeGenerator::ParameterType(const Context& context, const Type& type, const Layout& layout) { + if (type.kind() == Type::kArray_Kind) { + return String::printf("std::array<%s>", ParameterType(context, type.componentType(), + layout).c_str()); + } Layout::CType ctype = ParameterCType(context, type, layout); if (ctype != Layout::CType::kDefault) { return Layout::CTypeToStr(ctype); @@ -42,6 +46,7 @@ String HCodeGenerator::ParameterType(const Context& context, const Type& type, Layout::CType HCodeGenerator::ParameterCType(const Context& context, const Type& type, const Layout& layout) { + SkASSERT(type.kind() != Type::kArray_Kind); if (layout.fCType != Layout::CType::kDefault) { return layout.fCType; } diff --git a/src/sksl/SkSLIRGenerator.cpp b/src/sksl/SkSLIRGenerator.cpp index b3e206d84b..fe674f8455 100644 --- a/src/sksl/SkSLIRGenerator.cpp +++ b/src/sksl/SkSLIRGenerator.cpp @@ -401,9 +401,6 @@ std::unique_ptr IRGenerator::convertVarDeclarations(const ASTNo const Type* type = baseType; std::vector> sizes; auto iter = varDecl.begin(); - if (varData.fSizeCount > 0 && (modifiers.fFlags & Modifiers::kIn_Flag)) { - fErrors.error(varDecl.fOffset, "'in' variables may not have array type"); - } for (size_t i = 0; i < varData.fSizeCount; ++i, ++iter) { const ASTNode& rawSize = *iter; if (rawSize) { diff --git a/tests/SkSLFPTest.cpp b/tests/SkSLFPTest.cpp index 912c34ddd5..3a700758f9 100644 --- a/tests/SkSLFPTest.cpp +++ b/tests/SkSLFPTest.cpp @@ -1437,3 +1437,46 @@ R"SkSL( )__Cpp__" }); } + +DEF_TEST(SkSLUniformArrays, r) { + test(r, + *SkSL::ShaderCapsFactory::Default(), + R"__SkSL__( + uniform half scalarArray[4]; + uniform half2 pointArray[2]; + void main() { + sk_OutColor = half4(scalarArray[0] * pointArray[0].x + + scalarArray[1] * pointArray[0].y + + scalarArray[2] * pointArray[1].x + + scalarArray[3] * pointArray[1].y); + } + )__SkSL__", + /*expectedH=*/{ + "Make()", + }, + /*expectedCPP=*/{ + "void onSetData(const GrGLSLProgramDataManager& pdman, " + "const GrFragmentProcessor& _proc) override {\n }" + }); + test(r, + *SkSL::ShaderCapsFactory::Default(), + R"__SkSL__( + in uniform half scalarArray[4]; + in uniform half2 pointArray[2]; + void main() { + sk_OutColor = half4(scalarArray[0] * pointArray[0].x + + scalarArray[1] * pointArray[0].y + + scalarArray[2] * pointArray[1].x + + scalarArray[3] * pointArray[1].y); + } + )__SkSL__", + /*expectedH=*/{ + "Make(std::array scalarArray, std::array pointArray)", + "std::array scalarArray;", + "std::array pointArray;", + }, + /*expectedCPP=*/{ + "pdman.set1fv(scalarArrayVar, 4, &(_outer.scalarArray)[0]);", + "pdman.set2fv(pointArrayVar, 2, &pointArrayValue[0].fX);", + }); +}