| // | |
| // Copyright 2018 The ANGLE Project Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| // | |
| // ShaderStorageBlockFunctionHLSL: Wrapper functions for RWByteAddressBuffer Load/Store functions. | |
| // | |
| #include "compiler/translator/ShaderStorageBlockFunctionHLSL.h" | |
| #include "common/utilities.h" | |
| #include "compiler/translator/UtilsHLSL.h" | |
| #include "compiler/translator/blocklayout.h" | |
| #include "compiler/translator/blocklayoutHLSL.h" | |
| #include "compiler/translator/util.h" | |
| namespace sh | |
| { | |
| // static | |
| void ShaderStorageBlockFunctionHLSL::OutputSSBOLoadFunctionBody( | |
| TInfoSinkBase &out, | |
| const ShaderStorageBlockFunction &ssboFunction) | |
| { | |
| const char *convertString; | |
| switch (ssboFunction.type.getBasicType()) | |
| { | |
| case EbtFloat: | |
| convertString = "asfloat("; | |
| break; | |
| case EbtInt: | |
| convertString = "asint("; | |
| break; | |
| case EbtUInt: | |
| convertString = "asuint("; | |
| break; | |
| case EbtBool: | |
| convertString = "asint("; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| return; | |
| } | |
| size_t bytesPerComponent = | |
| gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type))); | |
| out << " " << ssboFunction.typeString << " result"; | |
| if (ssboFunction.type.isScalar()) | |
| { | |
| size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent; | |
| out << " = " << convertString << "buffer.Load(loc + " << offset << "));\n "; | |
| } | |
| else if (ssboFunction.type.isVector()) | |
| { | |
| if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle) | |
| { | |
| size_t componentStride = bytesPerComponent; | |
| if (ssboFunction.rowMajor) | |
| { | |
| componentStride = ssboFunction.matrixStride; | |
| } | |
| out << " = {"; | |
| for (const int offset : ssboFunction.swizzleOffsets) | |
| { | |
| size_t offsetInBytes = offset * componentStride; | |
| out << convertString << "buffer.Load(loc + " << offsetInBytes << ")),"; | |
| } | |
| out << "};\n"; | |
| } | |
| else | |
| { | |
| out << " = " << convertString << "buffer.Load" << ssboFunction.type.getNominalSize() | |
| << "(loc));\n"; | |
| } | |
| } | |
| else if (ssboFunction.type.isMatrix()) | |
| { | |
| if (ssboFunction.rowMajor) | |
| { | |
| out << ";"; | |
| out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols() | |
| << " tmp_ = {"; | |
| for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) | |
| { | |
| out << "asfloat(buffer.Load" << ssboFunction.type.getCols() << "(loc + " | |
| << rowIndex * ssboFunction.matrixStride << ")), "; | |
| } | |
| out << "};\n"; | |
| out << " result = transpose(tmp_);\n"; | |
| } | |
| else | |
| { | |
| out << " = {"; | |
| for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++) | |
| { | |
| out << "asfloat(buffer.Load" << ssboFunction.type.getRows() << "(loc + " | |
| << columnIndex * ssboFunction.matrixStride << ")), "; | |
| } | |
| out << "};\n"; | |
| } | |
| } | |
| else | |
| { | |
| // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 | |
| out << ";\n"; | |
| } | |
| out << " return result;\n"; | |
| return; | |
| } | |
| // static | |
| void ShaderStorageBlockFunctionHLSL::OutputSSBOStoreFunctionBody( | |
| TInfoSinkBase &out, | |
| const ShaderStorageBlockFunction &ssboFunction) | |
| { | |
| size_t bytesPerComponent = | |
| gl::VariableComponentSize(gl::VariableComponentType(GLVariableType(ssboFunction.type))); | |
| if (ssboFunction.type.isScalar()) | |
| { | |
| size_t offset = ssboFunction.swizzleOffsets[0] * bytesPerComponent; | |
| if (ssboFunction.type.getBasicType() == EbtBool) | |
| { | |
| out << " buffer.Store(loc + " << offset << ", uint(value));\n"; | |
| } | |
| else | |
| { | |
| out << " buffer.Store(loc + " << offset << ", asuint(value));\n"; | |
| } | |
| } | |
| else if (ssboFunction.type.isVector()) | |
| { | |
| out << " uint" << ssboFunction.type.getNominalSize() << " _value;\n"; | |
| if (ssboFunction.type.getBasicType() == EbtBool) | |
| { | |
| out << " _value = uint" << ssboFunction.type.getNominalSize() << "(value);\n"; | |
| } | |
| else | |
| { | |
| out << " _value = asuint(value);\n"; | |
| } | |
| if (ssboFunction.rowMajor || !ssboFunction.isDefaultSwizzle) | |
| { | |
| size_t componentStride = bytesPerComponent; | |
| if (ssboFunction.rowMajor) | |
| { | |
| componentStride = ssboFunction.matrixStride; | |
| } | |
| const TVector<int> &swizzleOffsets = ssboFunction.swizzleOffsets; | |
| for (int index = 0; index < static_cast<int>(swizzleOffsets.size()); index++) | |
| { | |
| size_t offsetInBytes = swizzleOffsets[index] * componentStride; | |
| out << "buffer.Store(loc + " << offsetInBytes << ", _value[" << index << "]);\n"; | |
| } | |
| } | |
| else | |
| { | |
| out << " buffer.Store" << ssboFunction.type.getNominalSize() << "(loc, _value);\n"; | |
| } | |
| } | |
| else if (ssboFunction.type.isMatrix()) | |
| { | |
| if (ssboFunction.rowMajor) | |
| { | |
| out << " float" << ssboFunction.type.getRows() << "x" << ssboFunction.type.getCols() | |
| << " tmp_ = transpose(value);\n"; | |
| for (int rowIndex = 0; rowIndex < ssboFunction.type.getRows(); rowIndex++) | |
| { | |
| out << " buffer.Store" << ssboFunction.type.getCols() << "(loc + " | |
| << rowIndex * ssboFunction.matrixStride << ", asuint(tmp_[" << rowIndex | |
| << "]));\n"; | |
| } | |
| } | |
| else | |
| { | |
| for (int columnIndex = 0; columnIndex < ssboFunction.type.getCols(); columnIndex++) | |
| { | |
| out << " buffer.Store" << ssboFunction.type.getRows() << "(loc + " | |
| << columnIndex * ssboFunction.matrixStride << ", asuint(value[" << columnIndex | |
| << "]));\n"; | |
| } | |
| } | |
| } | |
| else | |
| { | |
| // TODO(jiajia.qin@intel.com): Process all possible return types. http://anglebug.com/1951 | |
| } | |
| } | |
| // static | |
| void ShaderStorageBlockFunctionHLSL::OutputSSBOLengthFunctionBody(TInfoSinkBase &out, | |
| int unsizedArrayStride) | |
| { | |
| out << " uint dim = 0;\n"; | |
| out << " buffer.GetDimensions(dim);\n"; | |
| out << " return int((dim - loc)/uint(" << unsizedArrayStride << "));\n"; | |
| } | |
| // static | |
| void ShaderStorageBlockFunctionHLSL::OutputSSBOAtomicMemoryFunctionBody( | |
| TInfoSinkBase &out, | |
| const ShaderStorageBlockFunction &ssboFunction) | |
| { | |
| out << " " << ssboFunction.typeString << " original_value;\n"; | |
| switch (ssboFunction.method) | |
| { | |
| case SSBOMethod::ATOMIC_ADD: | |
| out << " buffer.InterlockedAdd(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_MIN: | |
| out << " buffer.InterlockedMin(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_MAX: | |
| out << " buffer.InterlockedMax(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_AND: | |
| out << " buffer.InterlockedAnd(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_OR: | |
| out << " buffer.InterlockedOr(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_XOR: | |
| out << " buffer.InterlockedXor(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_EXCHANGE: | |
| out << " buffer.InterlockedExchange(loc, value, original_value);\n"; | |
| break; | |
| case SSBOMethod::ATOMIC_COMPSWAP: | |
| out << " buffer.InterlockedCompareExchange(loc, compare_value, value, " | |
| "original_value);\n"; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| out << " return original_value;\n"; | |
| } | |
| bool ShaderStorageBlockFunctionHLSL::ShaderStorageBlockFunction::operator<( | |
| const ShaderStorageBlockFunction &rhs) const | |
| { | |
| return functionName < rhs.functionName; | |
| } | |
| TString ShaderStorageBlockFunctionHLSL::registerShaderStorageBlockFunction( | |
| const TType &type, | |
| SSBOMethod method, | |
| TLayoutBlockStorage storage, | |
| bool rowMajor, | |
| int matrixStride, | |
| int unsizedArrayStride, | |
| TIntermSwizzle *swizzleNode) | |
| { | |
| ShaderStorageBlockFunction ssboFunction; | |
| ssboFunction.typeString = TypeString(type); | |
| ssboFunction.method = method; | |
| switch (method) | |
| { | |
| case SSBOMethod::LOAD: | |
| ssboFunction.functionName = "_Load_"; | |
| break; | |
| case SSBOMethod::STORE: | |
| ssboFunction.functionName = "_Store_"; | |
| break; | |
| case SSBOMethod::LENGTH: | |
| ssboFunction.unsizedArrayStride = unsizedArrayStride; | |
| ssboFunction.functionName = "_Length_" + str(unsizedArrayStride); | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_ADD: | |
| ssboFunction.functionName = "_ssbo_atomicAdd_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_MIN: | |
| ssboFunction.functionName = "_ssbo_atomicMin_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_MAX: | |
| ssboFunction.functionName = "_ssbo_atomicMax_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_AND: | |
| ssboFunction.functionName = "_ssbo_atomicAnd_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_OR: | |
| ssboFunction.functionName = "_ssbo_atomicOr_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_XOR: | |
| ssboFunction.functionName = "_ssbo_atomicXor_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_EXCHANGE: | |
| ssboFunction.functionName = "_ssbo_atomicExchange_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| case SSBOMethod::ATOMIC_COMPSWAP: | |
| ssboFunction.functionName = "_ssbo_atomicCompSwap_" + ssboFunction.typeString; | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| ssboFunction.functionName += ssboFunction.typeString; | |
| ssboFunction.type = type; | |
| if (swizzleNode != nullptr) | |
| { | |
| ssboFunction.swizzleOffsets = swizzleNode->getSwizzleOffsets(); | |
| ssboFunction.isDefaultSwizzle = false; | |
| } | |
| else | |
| { | |
| if (ssboFunction.type.getNominalSize() > 1) | |
| { | |
| for (int index = 0; index < ssboFunction.type.getNominalSize(); index++) | |
| { | |
| ssboFunction.swizzleOffsets.push_back(index); | |
| } | |
| } | |
| else | |
| { | |
| ssboFunction.swizzleOffsets.push_back(0); | |
| } | |
| ssboFunction.isDefaultSwizzle = true; | |
| } | |
| ssboFunction.rowMajor = rowMajor; | |
| ssboFunction.matrixStride = matrixStride; | |
| ssboFunction.functionName += "_" + TString(getBlockStorageString(storage)); | |
| if (rowMajor) | |
| { | |
| ssboFunction.functionName += "_rm_"; | |
| } | |
| else | |
| { | |
| ssboFunction.functionName += "_cm_"; | |
| } | |
| for (const int offset : ssboFunction.swizzleOffsets) | |
| { | |
| switch (offset) | |
| { | |
| case 0: | |
| ssboFunction.functionName += "x"; | |
| break; | |
| case 1: | |
| ssboFunction.functionName += "y"; | |
| break; | |
| case 2: | |
| ssboFunction.functionName += "z"; | |
| break; | |
| case 3: | |
| ssboFunction.functionName += "w"; | |
| break; | |
| default: | |
| UNREACHABLE(); | |
| } | |
| } | |
| mRegisteredShaderStorageBlockFunctions.insert(ssboFunction); | |
| return ssboFunction.functionName; | |
| } | |
| void ShaderStorageBlockFunctionHLSL::shaderStorageBlockFunctionHeader(TInfoSinkBase &out) | |
| { | |
| for (const ShaderStorageBlockFunction &ssboFunction : mRegisteredShaderStorageBlockFunctions) | |
| { | |
| switch (ssboFunction.method) | |
| { | |
| case SSBOMethod::LOAD: | |
| { | |
| // Function header | |
| out << ssboFunction.typeString << " " << ssboFunction.functionName | |
| << "(RWByteAddressBuffer buffer, uint loc)\n"; | |
| out << "{\n"; | |
| OutputSSBOLoadFunctionBody(out, ssboFunction); | |
| break; | |
| } | |
| case SSBOMethod::STORE: | |
| { | |
| // Function header | |
| out << "void " << ssboFunction.functionName | |
| << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString | |
| << " value)\n"; | |
| out << "{\n"; | |
| OutputSSBOStoreFunctionBody(out, ssboFunction); | |
| break; | |
| } | |
| case SSBOMethod::LENGTH: | |
| { | |
| out << "int " << ssboFunction.functionName | |
| << "(RWByteAddressBuffer buffer, uint loc)\n"; | |
| out << "{\n"; | |
| OutputSSBOLengthFunctionBody(out, ssboFunction.unsizedArrayStride); | |
| break; | |
| } | |
| case SSBOMethod::ATOMIC_ADD: | |
| case SSBOMethod::ATOMIC_MIN: | |
| case SSBOMethod::ATOMIC_MAX: | |
| case SSBOMethod::ATOMIC_AND: | |
| case SSBOMethod::ATOMIC_OR: | |
| case SSBOMethod::ATOMIC_XOR: | |
| case SSBOMethod::ATOMIC_EXCHANGE: | |
| { | |
| out << ssboFunction.typeString << " " << ssboFunction.functionName | |
| << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString | |
| << " value)\n"; | |
| out << "{\n"; | |
| OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction); | |
| break; | |
| } | |
| case SSBOMethod::ATOMIC_COMPSWAP: | |
| { | |
| out << ssboFunction.typeString << " " << ssboFunction.functionName | |
| << "(RWByteAddressBuffer buffer, uint loc, " << ssboFunction.typeString | |
| << " compare_value, " << ssboFunction.typeString << " value)\n"; | |
| out << "{\n"; | |
| OutputSSBOAtomicMemoryFunctionBody(out, ssboFunction); | |
| break; | |
| } | |
| default: | |
| UNREACHABLE(); | |
| } | |
| out << "}\n" | |
| "\n"; | |
| } | |
| } | |
| } // namespace sh |