| // |
| // 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 |