blob: 5c2bc4e1cbe043110cf83143ca83d152a7f52e88 [file] [log] [blame]
/*
* 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 "WHLSLIntrinsics.h"
#if ENABLE(WEBGPU)
#include "WHLSLConstantExpression.h"
#include "WHLSLTypeArgument.h"
#include "WHLSLTypeReference.h"
#include <algorithm>
#include <cstring>
namespace WebCore {
namespace WHLSL {
constexpr const char* Intrinsics::m_textureTypeNames[];
constexpr const char* Intrinsics::m_textureInnerTypeNames[];
constexpr const char* Intrinsics::m_depthTextureInnerTypes[];
Intrinsics::Intrinsics()
{
}
void Intrinsics::add(AST::NativeFunctionDeclaration& nativeFunctionDeclaration)
{
if (nativeFunctionDeclaration.name() == "ddx")
m_ddx = &nativeFunctionDeclaration;
else if (nativeFunctionDeclaration.name() == "ddy")
m_ddy = &nativeFunctionDeclaration;
else if (nativeFunctionDeclaration.name() == "AllMemoryBarrierWithGroupSync")
m_allMemoryBarrier = &nativeFunctionDeclaration;
else if (nativeFunctionDeclaration.name() == "DeviceMemoryBarrierWithGroupSync")
m_deviceMemoryBarrier = &nativeFunctionDeclaration;
else if (nativeFunctionDeclaration.name() == "GroupMemoryBarrierWithGroupSync")
m_groupMemoryBarrier = &nativeFunctionDeclaration;
}
bool Intrinsics::addPrimitive(AST::NativeTypeDeclaration& nativeTypeDeclaration)
{
if (nativeTypeDeclaration.typeArguments().size())
return false;
if (nativeTypeDeclaration.name() == "void")
m_voidType = &nativeTypeDeclaration;
else if (nativeTypeDeclaration.name() == "bool")
m_boolType = &nativeTypeDeclaration;
else if (nativeTypeDeclaration.name() == "uint") {
nativeTypeDeclaration.setIsInt();
nativeTypeDeclaration.setIsNumber();
nativeTypeDeclaration.setCanRepresentInteger([](int x) {
return x >= 0;
});
nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned) {
return true;
});
nativeTypeDeclaration.setCanRepresentFloat([](float x) {
return static_cast<float>(static_cast<uint32_t>(x)) == x;
});
nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
return static_cast<uint32_t>(x + 1);
});
nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
return static_cast<uint32_t>(x);
});
nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
return static_cast<uint32_t>(x);
});
nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
for (int64_t i = 0; i < 0x100000000; ++i) {
if (callback(i))
break;
}
});
m_uintType = &nativeTypeDeclaration;
} else if (nativeTypeDeclaration.name() == "int") {
nativeTypeDeclaration.setIsInt();
nativeTypeDeclaration.setIsNumber();
nativeTypeDeclaration.setIsSigned();
nativeTypeDeclaration.setCanRepresentInteger([](int) {
return true;
});
nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned x) {
return x <= 2147483647;
});
nativeTypeDeclaration.setCanRepresentFloat([](float x) {
return static_cast<float>(static_cast<int32_t>(x)) == x;
});
nativeTypeDeclaration.setSuccessor([](int64_t x) -> int64_t {
return static_cast<int32_t>(x + 1);
});
nativeTypeDeclaration.setFormatValueFromInteger([](int x) -> int64_t {
return static_cast<int32_t>(x);
});
nativeTypeDeclaration.setFormatValueFromUnsignedInteger([](unsigned x) -> int64_t {
return static_cast<int32_t>(x);
});
nativeTypeDeclaration.setIterateAllValues([](const std::function<bool(int64_t)>& callback) {
for (int64_t i = -2147483647; i < 2147483648; ++i) {
if (callback(i))
break;
}
});
m_intType = &nativeTypeDeclaration;
} else if (nativeTypeDeclaration.name() == "float") {
nativeTypeDeclaration.setIsNumber();
nativeTypeDeclaration.setIsFloating();
nativeTypeDeclaration.setCanRepresentInteger([](int) {
return true;
});
nativeTypeDeclaration.setCanRepresentUnsignedInteger([](unsigned) {
return true;
});
nativeTypeDeclaration.setCanRepresentFloat([](float) {
return true;
});
m_floatType = &nativeTypeDeclaration;
} else if (nativeTypeDeclaration.name() == "atomic_int") {
nativeTypeDeclaration.setIsAtomic();
m_atomicIntType = &nativeTypeDeclaration;
} else if (nativeTypeDeclaration.name() == "atomic_uint") {
nativeTypeDeclaration.setIsAtomic();
m_atomicUintType = &nativeTypeDeclaration;
} else if (nativeTypeDeclaration.name() == "sampler") {
m_samplerType = &nativeTypeDeclaration;
nativeTypeDeclaration.setIsOpaqueType();
} else
ASSERT_NOT_REACHED();
return true;
}
bool Intrinsics::addVector(AST::NativeTypeDeclaration& nativeTypeDeclaration)
{
if (nativeTypeDeclaration.name() != "vector")
return false;
ASSERT(nativeTypeDeclaration.typeArguments().size() == 2);
ASSERT(WTF::holds_alternative<Ref<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]));
auto& innerType = static_cast<AST::TypeReference&>(WTF::get<Ref<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
auto& lengthExpression = WTF::get<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]);
ASSERT(!innerType.typeArguments().size());
AST::NativeTypeDeclaration** array;
if (innerType.name() == "bool")
array = m_vectorBool;
else if (innerType.name() == "uint")
array = m_vectorUint;
else if (innerType.name() == "int")
array = m_vectorInt;
else {
ASSERT(innerType.name() == "float");
array = m_vectorFloat;
}
int length = lengthExpression.integerLiteral().value();
ASSERT(length >= 2 && length <= 4);
nativeTypeDeclaration.setIsVector();
array[length - 2] = &nativeTypeDeclaration;
return true;
}
bool Intrinsics::addMatrix(AST::NativeTypeDeclaration& nativeTypeDeclaration)
{
if (nativeTypeDeclaration.name() != "matrix")
return false;
nativeTypeDeclaration.setIsMatrix();
ASSERT(nativeTypeDeclaration.typeArguments().size() == 3);
ASSERT(WTF::holds_alternative<Ref<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[1]));
ASSERT(WTF::holds_alternative<AST::ConstantExpression>(nativeTypeDeclaration.typeArguments()[2]));
return true;
}
bool Intrinsics::addFullTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration, AST::TypeReference& innerType)
{
auto textureTypeIndex = std::find(m_textureTypeNames, m_textureTypeNames + WTF_ARRAY_LENGTH(m_textureTypeNames), nativeTypeDeclaration.name()) - m_textureTypeNames;
if (textureTypeIndex == WTF_ARRAY_LENGTH(m_textureTypeNames))
return false;
unsigned innerTypeIndex = WTF_ARRAY_LENGTH(m_textureInnerTypeNames);
unsigned vectorLength;
for (unsigned i = 0; i < WTF_ARRAY_LENGTH(m_textureInnerTypeNames); ++i) {
if (innerType.name().startsWith(m_textureInnerTypeNames[i])) {
innerTypeIndex = i;
if (innerType.name() == m_textureInnerTypeNames[i])
vectorLength = 1;
else {
ASSERT(innerType.name().length() == strlen(m_textureInnerTypeNames[i]) + 1);
ASSERT(innerType.name()[innerType.name().length() - 1] == '2'
|| innerType.name()[innerType.name().length() - 1] == '3'
|| innerType.name()[innerType.name().length() - 1] == '4');
vectorLength = innerType.name()[innerType.name().length() - 1] - '0';
}
}
}
ASSERT(innerTypeIndex != WTF_ARRAY_LENGTH(m_textureInnerTypeNames));
nativeTypeDeclaration.setIsTexture();
nativeTypeDeclaration.setIsOpaqueType();
if (nativeTypeDeclaration.name() == "Texture1DArray" || nativeTypeDeclaration.name() == "RWTexture1DArray" || nativeTypeDeclaration.name() == "Texture2DArray" || nativeTypeDeclaration.name() == "RWTexture2DArray")
nativeTypeDeclaration.setIsTextureArray();
if (nativeTypeDeclaration.name() == "RWTexture1D" || nativeTypeDeclaration.name() == "RWTexture2D" || nativeTypeDeclaration.name() == "RWTexture3D" || nativeTypeDeclaration.name() == "RWTexture1DArray" || nativeTypeDeclaration.name() == "RWTexture2DArray")
nativeTypeDeclaration.setIsWritableTexture();
if (nativeTypeDeclaration.name() == "Texture1D" || nativeTypeDeclaration.name() == "RWTexture1D" || nativeTypeDeclaration.name() == "Texture1DArray" || nativeTypeDeclaration.name() == "RWTexture1DArray")
nativeTypeDeclaration.setTextureDimension(1);
if (nativeTypeDeclaration.name() == "Texture2D" || nativeTypeDeclaration.name() == "RWTexture2D" || nativeTypeDeclaration.name() == "TextureCube" || nativeTypeDeclaration.name() == "Texture2DArray" || nativeTypeDeclaration.name() == "RWTexture2DArray")
nativeTypeDeclaration.setTextureDimension(2);
if (nativeTypeDeclaration.name() == "Texture3D" || nativeTypeDeclaration.name() == "RWTexture3D")
nativeTypeDeclaration.setTextureDimension(3);
if (nativeTypeDeclaration.name() == "TextureCube")
nativeTypeDeclaration.setIsCubeTexture();
m_fullTextures[textureTypeIndex][innerTypeIndex][vectorLength - 1] = &nativeTypeDeclaration;
return true;
}
void Intrinsics::addDepthTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration, AST::TypeReference& innerType)
{
AST::NativeTypeDeclaration** texture = nullptr;
if (nativeTypeDeclaration.name() == "TextureDepth2D")
texture = m_textureDepth2D;
else if (nativeTypeDeclaration.name() == "TextureDepth2DArray")
texture = m_textureDepth2DArray;
else {
ASSERT(nativeTypeDeclaration.name() == "TextureDepthCube");
texture = m_textureDepthCube;
}
auto innerTypeIndex = std::find(m_depthTextureInnerTypes, m_depthTextureInnerTypes + WTF_ARRAY_LENGTH(m_depthTextureInnerTypes), innerType.name()) - m_depthTextureInnerTypes;
ASSERT(innerTypeIndex != WTF_ARRAY_LENGTH(m_depthTextureInnerTypes));
nativeTypeDeclaration.setIsTexture();
nativeTypeDeclaration.setIsOpaqueType();
if (texture == m_textureDepth2DArray)
nativeTypeDeclaration.setIsTextureArray();
if (texture == m_textureDepthCube)
nativeTypeDeclaration.setIsCubeTexture();
nativeTypeDeclaration.setTextureDimension(2);
nativeTypeDeclaration.setIsDepthTexture();
texture[innerTypeIndex] = &nativeTypeDeclaration;
}
void Intrinsics::addTexture(AST::NativeTypeDeclaration& nativeTypeDeclaration)
{
ASSERT(nativeTypeDeclaration.typeArguments().size() == 1);
ASSERT(WTF::holds_alternative<Ref<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
auto& innerType = static_cast<AST::TypeReference&>(WTF::get<Ref<AST::TypeReference>>(nativeTypeDeclaration.typeArguments()[0]));
ASSERT(!innerType.typeArguments().size());
if (addFullTexture(nativeTypeDeclaration, innerType)) {
m_textureSet.add(&nativeTypeDeclaration);
return;
}
addDepthTexture(nativeTypeDeclaration, innerType);
m_textureSet.add(&nativeTypeDeclaration);
}
void Intrinsics::add(AST::NativeTypeDeclaration& nativeTypeDeclaration)
{
if (addPrimitive(nativeTypeDeclaration))
return;
if (addVector(nativeTypeDeclaration))
return;
if (addMatrix(nativeTypeDeclaration))
return;
addTexture(nativeTypeDeclaration);
}
} // namespace WHLSL
} // namespace WebCore
#endif // ENABLE(WEBGPU)