| /* |
| * Copyright (C) 2019 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
| * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
| * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
| * THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "WHLSLNativeFunctionWriter.h" |
| |
| #if ENABLE(WEBGPU) |
| |
| #include "NotImplemented.h" |
| #include "WHLSLAddressSpace.h" |
| #include "WHLSLArrayType.h" |
| #include "WHLSLEnumerationDefinition.h" |
| #include "WHLSLInferTypes.h" |
| #include "WHLSLIntrinsics.h" |
| #include "WHLSLNamedType.h" |
| #include "WHLSLNativeFunctionDeclaration.h" |
| #include "WHLSLNativeTypeDeclaration.h" |
| #include "WHLSLPointerType.h" |
| #include "WHLSLStructureDefinition.h" |
| #include "WHLSLTypeDefinition.h" |
| #include "WHLSLTypeNamer.h" |
| #include "WHLSLUnnamedType.h" |
| #include "WHLSLVariableDeclaration.h" |
| #include <wtf/text/StringBuilder.h> |
| |
| namespace WebCore { |
| |
| namespace WHLSL { |
| |
| namespace Metal { |
| |
| static String mapFunctionName(String& functionName) |
| { |
| if (functionName == "ddx") |
| return "dfdx"_str; |
| if (functionName == "ddy") |
| return "dfdy"_str; |
| if (functionName == "asint") |
| return "as_type<int32_t>"_str; |
| if (functionName == "asuint") |
| return "as_type<uint32_t>"_str; |
| if (functionName == "asfloat") |
| return "as_type<float>"_str; |
| return functionName; |
| } |
| |
| static String atomicName(String input) |
| { |
| if (input == "Add") |
| return "fetch_add"_str; |
| if (input == "And") |
| return "fetch_and"_str; |
| if (input == "Exchange") |
| return "exchange"_str; |
| if (input == "Max") |
| return "fetch_max"_str; |
| if (input == "Min") |
| return "fetch_min"_str; |
| if (input == "Or") |
| return "fetch_or"_str; |
| ASSERT(input == "Xor"); |
| return "fetch_xor"_str; |
| } |
| |
| static int vectorLength(AST::NativeTypeDeclaration& nativeTypeDeclaration) |
| { |
| int vectorLength = 1; |
| if (!nativeTypeDeclaration.typeArguments().isEmpty()) { |
| ASSERT(nativeTypeDeclaration.typeArguments().size() == 2); |
| ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1])); |
| vectorLength = WTF::get<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]).integerLiteral().value(); |
| } |
| return vectorLength; |
| } |
| |
| static const char* vectorSuffix(int vectorLength) |
| { |
| switch (vectorLength) { |
| case 1: |
| return ""; |
| case 2: |
| return "2"; |
| case 3: |
| return "3"; |
| default: |
| ASSERT(vectorLength == 4); |
| return "4"; |
| } |
| } |
| |
| enum class SampleType { |
| Sample, |
| SampleLevel, |
| SampleBias, |
| SampleGrad |
| }; |
| |
| static Optional<SampleType> sampleType(const String& functionName) |
| { |
| if (functionName == "Sample") |
| return SampleType::Sample; |
| if (functionName == "SampleLevel") |
| return SampleType::SampleLevel; |
| if (functionName == "SampleBias") |
| return SampleType::SampleBias; |
| if (functionName == "SampleGrad") |
| return SampleType::SampleGrad; |
| return WTF::nullopt; |
| } |
| |
| void inlineNativeFunction(StringBuilder& stringBuilder, AST::NativeFunctionDeclaration& nativeFunctionDeclaration, const Vector<MangledVariableName>& args, MangledVariableName resultName, TypeNamer& typeNamer) |
| { |
| auto asMatrixType = [&] (AST::UnnamedType& unnamedType) -> AST::NativeTypeDeclaration* { |
| auto& realType = unnamedType.unifyNode(); |
| if (!realType.isNativeTypeDeclaration()) |
| return nullptr; |
| |
| auto& maybeMatrixType = downcast<AST::NativeTypeDeclaration>(realType); |
| if (maybeMatrixType.isMatrix()) |
| return &maybeMatrixType; |
| |
| return nullptr; |
| }; |
| |
| if (nativeFunctionDeclaration.isCast()) { |
| auto& returnType = nativeFunctionDeclaration.type(); |
| auto metalReturnTypeName = typeNamer.mangledNameForType(returnType); |
| |
| if (!nativeFunctionDeclaration.parameters().size()) { |
| stringBuilder.append(metalReturnTypeName, " { }"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.parameters().size() == 1) { |
| auto& parameterType = *nativeFunctionDeclaration.parameters()[0]->type(); |
| |
| auto isEnumerationDefinition = [] (auto& type) { |
| return is<AST::NamedType>(type) && is<AST::EnumerationDefinition>(downcast<AST::NamedType>(type)); |
| }; |
| auto& unifiedReturnType = returnType.unifyNode(); |
| if (isEnumerationDefinition(unifiedReturnType) && !isEnumerationDefinition(parameterType.unifyNode())) { |
| auto& enumerationDefinition = downcast<AST::EnumerationDefinition>(downcast<AST::NamedType>(unifiedReturnType)); |
| stringBuilder.append("static_cast<", metalReturnTypeName, ">(("); |
| bool loopedOnce = false; |
| bool hasZeroCase = false; |
| for (auto& member : enumerationDefinition.enumerationMembers()) { |
| if (loopedOnce) |
| stringBuilder.append(" || "); |
| hasZeroCase |= !member.get().value(); |
| stringBuilder.append(args[0], " == ", member.get().value()); |
| loopedOnce = true; |
| } |
| ASSERT_UNUSED(hasZeroCase, hasZeroCase); |
| |
| stringBuilder.append(") ? ", args[0], " : 0)"); |
| } else |
| stringBuilder.append("static_cast<", metalReturnTypeName, ">(", args[0], ")"); |
| |
| return; |
| } |
| |
| if (auto* matrixType = asMatrixType(returnType)) { |
| // We're either constructing with all individual elements, or with |
| // vectors for each column. |
| |
| stringBuilder.append('('); |
| if (args.size() == matrixType->numberOfMatrixColumns()) { |
| // Constructing with vectors for each column. |
| for (size_t i = 0; i < args.size(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, ".columns[", i, "] = ", args[i]); |
| } |
| } else { |
| // Constructing with all elements. |
| RELEASE_ASSERT(args.size() == matrixType->numberOfMatrixColumns() * matrixType->numberOfMatrixRows()); |
| |
| size_t argNumber = 0; |
| for (size_t i = 0; i < matrixType->numberOfMatrixColumns(); ++i) { |
| for (size_t j = 0; j < matrixType->numberOfMatrixRows(); ++j) { |
| if (argNumber) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, ".columns[", i, "][", j, "] = ", args[argNumber]); |
| ++argNumber; |
| } |
| } |
| } |
| |
| stringBuilder.append(", ", resultName, ')'); |
| return; |
| } |
| |
| stringBuilder.append(metalReturnTypeName, '('); |
| for (unsigned i = 0; i < nativeFunctionDeclaration.parameters().size(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(args[i]); |
| } |
| stringBuilder.append(')'); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.isOperator()) { |
| auto operatorName = nativeFunctionDeclaration.name().substring("operator"_str.length()); |
| |
| if (nativeFunctionDeclaration.parameters().size() == 1) { |
| // This is ok to do since the args to this function are all temps. |
| // So things like ++ and -- are ok to do. |
| |
| if (auto* matrixType = asMatrixType(nativeFunctionDeclaration.type())) { |
| stringBuilder.append('('); |
| for (unsigned i = 0; i < matrixType->numberOfMatrixColumns(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, '[', i, "] = ", operatorName, args[0], '[', i, ']'); |
| } |
| stringBuilder.append(", ", resultName, ')'); |
| } else |
| stringBuilder.append(operatorName, args[0]); |
| return; |
| } |
| |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 2); |
| if (auto* leftMatrix = asMatrixType(*nativeFunctionDeclaration.parameters()[0]->type())) { |
| if (auto* rightMatrix = asMatrixType(*nativeFunctionDeclaration.parameters()[1]->type())) { |
| // matrix <op> matrix |
| stringBuilder.append('('); |
| for (unsigned i = 0; i < leftMatrix->numberOfMatrixColumns(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, '[', i, "] = ", args[0], '[', i, "] ", operatorName, ' ', args[1], '[', i, ']'); |
| } |
| stringBuilder.append(", ", resultName, ')'); |
| } else { |
| // matrix <op> scalar |
| stringBuilder.append('('); |
| for (unsigned i = 0; i < leftMatrix->numberOfMatrixColumns(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, '[', i, "] = ", args[0], '[', i, "] ", operatorName, ' ', args[1]); |
| } |
| stringBuilder.append(", ", resultName, ')'); |
| } |
| } else if (auto* rightMatrix = asMatrixType(*nativeFunctionDeclaration.parameters()[1]->type())) { |
| ASSERT(!asMatrixType(*nativeFunctionDeclaration.parameters()[0]->type())); |
| // scalar <op> matrix |
| stringBuilder.append('('); |
| for (unsigned i = 0; i < rightMatrix->numberOfMatrixColumns(); ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append(resultName, '[', i, "] = ", args[0], ' ', operatorName, ' ', args[1], '[', i, ']'); |
| } |
| stringBuilder.append(", ", resultName, ')'); |
| } else { |
| // scalar <op> scalar |
| // vector <op> vector |
| // vector <op> scalar |
| // scalar <op> vector |
| stringBuilder.append( |
| '(', args[0], ' ', operatorName, ' ', args[1], ')'); |
| } |
| |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "cos" |
| || nativeFunctionDeclaration.name() == "sin" |
| || nativeFunctionDeclaration.name() == "tan" |
| || nativeFunctionDeclaration.name() == "acos" |
| || nativeFunctionDeclaration.name() == "asin" |
| || nativeFunctionDeclaration.name() == "atan" |
| || nativeFunctionDeclaration.name() == "cosh" |
| || nativeFunctionDeclaration.name() == "sinh" |
| || nativeFunctionDeclaration.name() == "tanh" |
| || nativeFunctionDeclaration.name() == "ceil" |
| || nativeFunctionDeclaration.name() == "exp" |
| || nativeFunctionDeclaration.name() == "floor" |
| || nativeFunctionDeclaration.name() == "log" |
| || nativeFunctionDeclaration.name() == "round" |
| || nativeFunctionDeclaration.name() == "trunc" |
| || nativeFunctionDeclaration.name() == "ddx" |
| || nativeFunctionDeclaration.name() == "ddy" |
| || nativeFunctionDeclaration.name() == "isnormal" |
| || nativeFunctionDeclaration.name() == "isfinite" |
| || nativeFunctionDeclaration.name() == "isinf" |
| || nativeFunctionDeclaration.name() == "isnan" |
| || nativeFunctionDeclaration.name() == "asint" |
| || nativeFunctionDeclaration.name() == "asuint" |
| || nativeFunctionDeclaration.name() == "asfloat" |
| || nativeFunctionDeclaration.name() == "length") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 1); |
| stringBuilder.append( |
| mapFunctionName(nativeFunctionDeclaration.name()), '(', args[0], ')'); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "pow" || nativeFunctionDeclaration.name() == "atan2") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 2); |
| stringBuilder.append( |
| nativeFunctionDeclaration.name(), '(', args[0], ", ", args[1], ')'); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "clamp") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 3); |
| |
| if (auto* matrixType = asMatrixType(nativeFunctionDeclaration.type())) { |
| stringBuilder.append('('); |
| bool ranOnce = false; |
| for (unsigned i = 0; i < matrixType->numberOfMatrixColumns(); ++i) { |
| for (unsigned j = 0; j < matrixType->numberOfMatrixRows(); ++j) { |
| if (ranOnce) |
| stringBuilder.append(", "); |
| ranOnce = true; |
| stringBuilder.append( |
| resultName, '[', i, "][", j, "] = clamp(", args[0], '[', i, "][", j, "], ", args[1], '[', i, "][", j, "], ", args[2], '[', i, "][", j, "])"); |
| } |
| } |
| stringBuilder.append(", ", resultName, ")"); |
| } else { |
| stringBuilder.append( |
| "clamp(", args[0], ", ", args[1], ", ", args[2], ')'); |
| } |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "AllMemoryBarrierWithGroupSync") { |
| ASSERT(!nativeFunctionDeclaration.parameters().size()); |
| stringBuilder.append( |
| "(threadgroup_barrier(mem_flags::mem_device), threadgroup_barrier(mem_flags::mem_threadgroup), threadgroup_barrier(mem_flags::mem_texture))"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "DeviceMemoryBarrierWithGroupSync") { |
| ASSERT(!nativeFunctionDeclaration.parameters().size()); |
| stringBuilder.append( |
| "threadgroup_barrier(mem_flags::mem_device)"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GroupMemoryBarrierWithGroupSync") { |
| ASSERT(!nativeFunctionDeclaration.parameters().size()); |
| stringBuilder.append( |
| "threadgroup_barrier(mem_flags::mem_threadgroup)"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name().startsWith("Interlocked"_str)) { |
| if (nativeFunctionDeclaration.name() == "InterlockedCompareExchange") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 4); |
| stringBuilder.append( |
| "(atomic_compare_exchange_weak_explicit(", args[0], ", &", args[1], ", ", args[2], ", memory_order_relaxed, memory_order_relaxed), ", |
| '*', args[3], " = ", args[1], ')'); |
| return; |
| } |
| |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 3); |
| auto name = atomicName(nativeFunctionDeclaration.name().substring("Interlocked"_str.length())); |
| stringBuilder.append( |
| '*', args[2], " = atomic_", name, "_explicit(", args[0], ", ", args[1], ", memory_order_relaxed)"); |
| return; |
| } |
| |
| if (auto sampleType = WHLSL::Metal::sampleType(nativeFunctionDeclaration.name())) { |
| size_t baseArgumentCount = 0; |
| switch (*sampleType) { |
| case SampleType::Sample: |
| baseArgumentCount = 3; |
| break; |
| case SampleType::SampleLevel: |
| case SampleType::SampleBias: |
| baseArgumentCount = 4; |
| break; |
| case SampleType::SampleGrad: |
| baseArgumentCount = 5; |
| break; |
| } |
| ASSERT(nativeFunctionDeclaration.parameters().size() == baseArgumentCount || nativeFunctionDeclaration.parameters().size() == baseArgumentCount + 1); |
| |
| auto& textureType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.parameters()[0]->type()->unifyNode())); |
| auto& locationType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.parameters()[2]->type()->unifyNode())); |
| auto locationVectorLength = vectorLength(locationType); |
| auto& returnType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.type().unifyNode())); |
| auto returnVectorLength = vectorLength(returnType); |
| |
| int argumentIndex = 0; |
| stringBuilder.append(args[argumentIndex], ".sample(", args[argumentIndex + 1], ", "); |
| argumentIndex += 2; |
| |
| if (textureType.isTextureArray()) { |
| ASSERT(locationVectorLength > 1); |
| stringBuilder.append(args[argumentIndex], '.', "xyzw"_str.substring(0, locationVectorLength - 1), ", ", args[argumentIndex], '.', "xyzw"_str.substring(locationVectorLength - 1, 1)); |
| ++argumentIndex; |
| } else |
| stringBuilder.append(args[argumentIndex++]); |
| |
| switch (*sampleType) { |
| case SampleType::Sample: |
| break; |
| case SampleType::SampleLevel: |
| stringBuilder.append(", level(", args[argumentIndex++], ")"); |
| break; |
| case SampleType::SampleBias: |
| stringBuilder.append(", bias(", args[argumentIndex++], ")"); |
| break; |
| case SampleType::SampleGrad: |
| if (textureType.isCubeTexture()) |
| stringBuilder.append(", gradientcube(", args[argumentIndex], ", ", args[argumentIndex + 1], ")"); |
| else |
| stringBuilder.append(", gradient2d(", args[argumentIndex], ", ", args[argumentIndex + 1], ")"); |
| argumentIndex += 2; |
| break; |
| } |
| |
| if (nativeFunctionDeclaration.parameters().size() == baseArgumentCount + 1) |
| stringBuilder.append(", ", args[argumentIndex++]); |
| stringBuilder.append(")"); |
| if (!textureType.isDepthTexture()) |
| stringBuilder.append(".", "xyzw"_str.substring(0, returnVectorLength)); |
| |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "Load") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 2); |
| |
| auto& textureType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.parameters()[0]->type()->unifyNode())); |
| auto& locationType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.parameters()[1]->type()->unifyNode())); |
| auto locationVectorLength = vectorLength(locationType); |
| auto& returnType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.type().unifyNode())); |
| auto returnVectorLength = vectorLength(returnType); |
| auto locationTypeName = typeNamer.mangledNameForType(locationType); |
| |
| stringBuilder.append('(', args[1], " = "); |
| if (textureType.isTextureArray()) { |
| ASSERT(locationVectorLength > 1); |
| stringBuilder.append("clamp(", args[1], ", ", locationTypeName, '('); |
| for (int i = 0; i < locationVectorLength; ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append('0'); |
| } |
| stringBuilder.append("), ", locationTypeName, '('); |
| |
| String dimensions[] = { "width"_str, "height"_str, "depth"_str }; |
| for (int i = 0; i < locationVectorLength - 1; ++i) { |
| if (i) |
| stringBuilder.append(", "); |
| stringBuilder.append( |
| args[0], ".get_", dimensions[i], "() - 1"); |
| } |
| stringBuilder.append( |
| args[0], ".get_array_size() - 1))"); |
| } else { |
| if (locationVectorLength == 1) |
| stringBuilder.append("clamp(", args[1], ", 0, ", args[0], ".get_width() - 1)"); |
| else { |
| stringBuilder.append("clamp(", args[1], ", ", locationTypeName, "(0, 0"); |
| if (locationVectorLength >= 3) |
| stringBuilder.append(", 0"); |
| stringBuilder.append("), ", locationTypeName, '(', args[0], ".get_width() - 1, ", args[0], ".get_height() - 1"); |
| if (locationVectorLength >= 3) |
| stringBuilder.append(", ", args[0], ".get_depth() - 1"); |
| stringBuilder.append("))"); |
| } |
| } |
| |
| stringBuilder.append(", ", args[0], ".read("); |
| |
| if (textureType.isTextureArray()) { |
| ASSERT(locationVectorLength > 1); |
| stringBuilder.append("uint", vectorSuffix(locationVectorLength - 1), '(', args[1], '.', "xyzw"_str.substring(0, locationVectorLength - 1), "), uint(", args[1], '.', "xyzw"_str.substring(locationVectorLength - 1, 1), ')'); |
| } else |
| stringBuilder.append("uint", vectorSuffix(locationVectorLength), '(', args[1], ')'); |
| stringBuilder.append(')'); |
| if (!textureType.isDepthTexture()) |
| stringBuilder.append('.', "xyzw"_str.substring(0, returnVectorLength)); |
| |
| stringBuilder.append(')'); |
| |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "load") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 1); |
| stringBuilder.append( |
| "atomic_load_explicit(", args[0], ", memory_order_relaxed)"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "store") { |
| ASSERT(nativeFunctionDeclaration.parameters().size() == 2); |
| stringBuilder.append( |
| "atomic_store_explicit(", args[0], ", ", args[1], ", memory_order_relaxed)"); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GetDimensions") { |
| stringBuilder.append('('); |
| |
| auto& textureType = downcast<AST::NativeTypeDeclaration>(downcast<AST::NamedType>(nativeFunctionDeclaration.parameters()[0]->type()->unifyNode())); |
| |
| size_t index = 1; |
| bool hasMipLevel = !textureType.isWritableTexture() && textureType.textureDimension() != 1; |
| if (hasMipLevel) |
| ++index; |
| const MangledVariableName& widthName = args[index]; |
| ++index; |
| Optional<MangledVariableName> heightName; |
| if (textureType.textureDimension() >= 2) { |
| heightName = args[index]; |
| ++index; |
| } |
| Optional<MangledVariableName> depthName; |
| if (textureType.textureDimension() >= 3) { |
| depthName = args[index]; |
| ++index; |
| } |
| Optional<MangledVariableName> elementsName; |
| if (textureType.isTextureArray()) { |
| elementsName = args[index]; |
| ++index; |
| } |
| Optional<MangledVariableName> numberOfLevelsName; |
| if (!textureType.isWritableTexture() && textureType.textureDimension() != 1) { |
| numberOfLevelsName = args[index]; |
| ++index; |
| } |
| ASSERT(index == nativeFunctionDeclaration.parameters().size()); |
| |
| stringBuilder.append( |
| '*', widthName, " = ", args[0], ".get_width("); |
| if (hasMipLevel) |
| stringBuilder.append(args[1]); |
| stringBuilder.append(')'); |
| |
| if (heightName) { |
| stringBuilder.append( |
| ", *", *heightName, " = ", args[0], ".get_height("); |
| if (hasMipLevel) |
| stringBuilder.append(args[1]); |
| stringBuilder.append(')'); |
| } |
| if (depthName) { |
| stringBuilder.append( |
| ", *", *depthName, " = ", args[0], ".get_depth("); |
| if (hasMipLevel) |
| stringBuilder.append(args[1]); |
| stringBuilder.append(')'); |
| } |
| if (elementsName) { |
| stringBuilder.append( |
| ", *", *elementsName, " = ", args[0], ".get_array_size()"); |
| } |
| if (numberOfLevelsName) { |
| stringBuilder.append( |
| ", *", *numberOfLevelsName, " = ", args[0], ".get_num_mip_levels()"); |
| } |
| |
| stringBuilder.append(')'); |
| return; |
| } |
| |
| if (nativeFunctionDeclaration.name() == "Gather") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherRed") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "SampleCmp") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "SampleCmpLevelZero") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "Store") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherAlpha") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherBlue") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherCmp") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherCmpRed") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| if (nativeFunctionDeclaration.name() == "GatherGreen") { |
| // FIXME: https://bugs.webkit.org/show_bug.cgi?id=195813 Implement this |
| notImplemented(); |
| } |
| |
| ASSERT_NOT_REACHED(); |
| } |
| |
| } // namespace Metal |
| |
| } // namespace WHLSL |
| |
| } // namespace WebCore |
| |
| #endif |