//===--- HLSLRootSignature.cpp -- HLSL root signature parsing -------------===// /////////////////////////////////////////////////////////////////////////////// // // // HLSLRootSignature.cpp // // Copyright (C) Microsoft Corporation. All rights reserved. // // This file is distributed under the University of Illinois Open Source // // License. See LICENSE.TXT for details. // // // // This file implements the parser for the root signature mini-language. // // // /////////////////////////////////////////////////////////////////////////////// #include "llvm/ADT/SmallVector.h" #include "llvm/Support/raw_ostream.h" #include "clang/Basic/Diagnostic.h" #include "clang/Parse/ParseHLSL.h" #include "clang/Parse/ParseDiagnostic.h" #include "dxc/Support/Global.h" #include "dxc/Support/WinIncludes.h" #include "HLSLRootSignature.h" using namespace llvm; using namespace hlsl; // Error codes. These could be useful for localization at some point. #define ERR_RS_UNEXPECTED_TOKEN 4612 #define ERR_RS_ROOTFLAGS_MORE_THAN_ONCE 4613 #define ERR_RS_CREATION_FAILED 4614 #define ERR_RS_BAD_SM 4615 #define ERR_RS_UNDEFINED_REGISTER 4616 #define ERR_RS_INCORRECT_REGISTER_TYPE 4617 #define ERR_RS_NOT_ALLOWED_FOR_HS_PATCH_CONST 4618 #define ERR_RS_WRONG_ROOT_DESC_FLAG 4619 #define ERR_RS_WRONG_DESC_RANGE_FLAG 4620 #define ERR_RS_BAD_FLOAT 5000 // Non-throwing new #define NEW new (std::nothrow) DEFINE_ENUM_FLAG_OPERATORS(DxilRootSignatureFlags) DEFINE_ENUM_FLAG_OPERATORS(DxilRootDescriptorFlags) DEFINE_ENUM_FLAG_OPERATORS(DxilDescriptorRangeFlags) RootSignatureTokenizer::RootSignatureTokenizer(const char *pStr, size_t len) : m_pOrigStr(pStr) , m_pStrPos(pStr) , m_pEndPos(pStr + len) { m_TokenBufferIdx = 0; ReadNextToken(m_TokenBufferIdx); } RootSignatureTokenizer::RootSignatureTokenizer(const char *pStr) : m_pOrigStr(pStr) , m_pStrPos(pStr) , m_pEndPos(pStr + strlen(pStr)) { m_TokenBufferIdx = 0; ReadNextToken(m_TokenBufferIdx); } RootSignatureTokenizer::Token RootSignatureTokenizer::GetToken() { uint32_t CurBufferIdx = m_TokenBufferIdx; m_TokenBufferIdx = (m_TokenBufferIdx + 1) % kNumBuffers; ReadNextToken(m_TokenBufferIdx); return m_Tokens[CurBufferIdx]; } RootSignatureTokenizer::Token RootSignatureTokenizer::PeekToken() { return m_Tokens[m_TokenBufferIdx]; } bool RootSignatureTokenizer::IsDone() const { return m_pStrPos == m_pEndPos; } void RootSignatureTokenizer::ReadNextToken(uint32_t BufferIdx) { char *pBuffer = m_TokenStrings[BufferIdx]; Token &T = m_Tokens[BufferIdx]; bool bFloat = false; EatSpace(); // Identify token uint32_t TokLen = 0; char ch; // Any time m_pStrPos moves, update ch; no null termination assumptions made. // Test ch, not m_StrPos[0], which may be at end. #define STRPOS_MOVED() ch = m_pStrPos == m_pEndPos ? '\0' : m_pStrPos[0]; STRPOS_MOVED(); if(IsSeparator(ch)) { pBuffer[TokLen++] = *m_pStrPos++; } else if(IsDigit(ch) || ch == '+' || ch == '-' || ch == '.') { if(ch == '+' || ch == '-') { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); } bool bSeenDigit = false; while(IsDigit(ch) && TokLen < kMaxTokenLength) { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); bSeenDigit = true; } if(ch == '.') { bFloat = true; pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); if(!bSeenDigit && !IsDigit(ch)) { goto lUnknownToken; } while(IsDigit(ch) && TokLen < kMaxTokenLength) { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); bSeenDigit = true; } } if(!bSeenDigit) { goto lUnknownToken; } if(ch == 'e' || ch == 'E') { bFloat = true; pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED() if(ch == '+' || ch == '-') { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); } if(!IsDigit(ch)) { goto lUnknownToken; } while(IsDigit(ch) && TokLen < kMaxTokenLength) { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); } } if(ch == 'f' || ch == 'F') { bFloat = true; pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); } } else if(IsAlpha(ch) || ch == '_') { while((IsAlpha(ch) || ch == '_' || IsDigit(ch)) && TokLen < kMaxTokenLength) { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); } } else { while(m_pStrPos < m_pEndPos && TokLen < kMaxTokenLength) { pBuffer[TokLen++] = *m_pStrPos++; STRPOS_MOVED(); // not really needed, but good for consistency } } pBuffer[TokLen] = '\0'; #undef STRPOS_MOVED // // Classify token // char c = pBuffer[0]; // Delimiters switch(c) { case '\0': T = Token(Token::Type::EOL, pBuffer); return; case ',': T = Token(Token::Type::Comma, pBuffer); return; case '(': T = Token(Token::Type::LParen, pBuffer); return; case ')': T = Token(Token::Type::RParen, pBuffer); return; case '=': T = Token(Token::Type::EQ, pBuffer); return; case '|': T = Token(Token::Type::OR, pBuffer); return; } // Number if(IsDigit(c) || c == '+' || c == '-' || c == '.') { if(bFloat) { float v = 0.f; if(ToFloat(pBuffer, v)) { T = Token(Token::Type::NumberFloat, pBuffer, v); return; } } else { if(c == '-') { int n = 0; if(ToI32(pBuffer, n)) { T = Token(Token::Type::NumberI32, pBuffer, (uint32_t)n); return; } } else { uint32_t n = 0; if(ToU32(pBuffer, n)) { T = Token(Token::Type::NumberU32, pBuffer, n); return; } } } goto lUnknownToken; } // Register if(IsDigit(pBuffer[1]) && (c == 't' || c == 's' || c == 'u' || c == 'b')) { if(ToRegister(pBuffer, T)) return; } // Keyword #define KW(__name) ToKeyword(pBuffer, T, #__name, Token::Type::__name) bool bKW = false; // Case-incensitive switch(toupper(c)) { case 'A': bKW = KW(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT) || KW(ALLOW_STREAM_OUTPUT) || KW(addressU) || KW(addressV) || KW(addressW); break; case 'B': bKW = KW(borderColor); break; case 'C': bKW = KW(CBV) || KW(comparisonFunc) || KW(COMPARISON_NEVER) || KW(COMPARISON_LESS) || KW(COMPARISON_EQUAL) || KW(COMPARISON_LESS_EQUAL) || KW(COMPARISON_GREATER) || KW(COMPARISON_NOT_EQUAL) || KW(COMPARISON_GREATER_EQUAL) || KW(COMPARISON_ALWAYS); break; case 'D': bKW = KW(DescriptorTable) || KW(DESCRIPTOR_RANGE_OFFSET_APPEND) || KW(DENY_VERTEX_SHADER_ROOT_ACCESS) || KW(DENY_HULL_SHADER_ROOT_ACCESS) || KW(DENY_DOMAIN_SHADER_ROOT_ACCESS) || KW(DENY_GEOMETRY_SHADER_ROOT_ACCESS) || KW(DENY_PIXEL_SHADER_ROOT_ACCESS) || KW(DESCRIPTORS_VOLATILE) || KW(DATA_VOLATILE) || KW(DATA_STATIC) || KW(DATA_STATIC_WHILE_SET_AT_EXECUTE); break; case 'F': bKW = KW(flags) || KW(filter) || KW(FILTER_MIN_MAG_MIP_POINT) || KW(FILTER_MIN_MAG_POINT_MIP_LINEAR) || KW(FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT) || KW(FILTER_MIN_POINT_MAG_MIP_LINEAR) || KW(FILTER_MIN_LINEAR_MAG_MIP_POINT) || KW(FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || KW(FILTER_MIN_MAG_LINEAR_MIP_POINT) || KW(FILTER_MIN_MAG_MIP_LINEAR) || KW(FILTER_ANISOTROPIC) || KW(FILTER_COMPARISON_MIN_MAG_MIP_POINT) || KW(FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR) || KW(FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT) || KW(FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR) || KW(FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT) || KW(FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || KW(FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT) || KW(FILTER_COMPARISON_MIN_MAG_MIP_LINEAR) || KW(FILTER_COMPARISON_ANISOTROPIC) || KW(FILTER_MINIMUM_MIN_MAG_MIP_POINT) || KW(FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR) || KW(FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT) || KW(FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR) || KW(FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT) || KW(FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || KW(FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT) || KW(FILTER_MINIMUM_MIN_MAG_MIP_LINEAR) || KW(FILTER_MINIMUM_ANISOTROPIC) || KW(FILTER_MAXIMUM_MIN_MAG_MIP_POINT) || KW(FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR) || KW(FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT) || KW(FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR) || KW(FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT) || KW(FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR) || KW(FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT) || KW(FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR) || KW(FILTER_MAXIMUM_ANISOTROPIC); break; case 'M': bKW = KW(maxAnisotropy) || KW(mipLODBias) || KW(minLOD) || KW(maxLOD); break; case 'N': bKW = KW(numDescriptors) || KW(num32BitConstants); break; case 'O': bKW = KW(offset); break; case 'R': bKW = KW(RootFlags) || KW(RootConstants); break; case 'S': bKW = KW(space) || KW(Sampler) || KW(StaticSampler) || KW(SRV) || KW(SHADER_VISIBILITY_ALL) || KW(SHADER_VISIBILITY_VERTEX) || KW(SHADER_VISIBILITY_HULL) || KW(SHADER_VISIBILITY_DOMAIN) || KW(SHADER_VISIBILITY_GEOMETRY) || KW(SHADER_VISIBILITY_PIXEL) || KW(STATIC_BORDER_COLOR_TRANSPARENT_BLACK) || KW(STATIC_BORDER_COLOR_OPAQUE_BLACK) || KW(STATIC_BORDER_COLOR_OPAQUE_WHITE); break; case 'T': bKW = KW(TEXTURE_ADDRESS_WRAP) || KW(TEXTURE_ADDRESS_MIRROR) || KW(TEXTURE_ADDRESS_CLAMP) || KW(TEXTURE_ADDRESS_BORDER) || KW(TEXTURE_ADDRESS_MIRROR_ONCE); break; case 'U': bKW = KW(unbounded) || KW(UAV); break; case 'V': bKW = KW(visibility); break; } #undef KW if(!bKW) goto lUnknownToken; return; lUnknownToken: T = Token(Token::Type::Unknown, pBuffer); } void RootSignatureTokenizer::EatSpace() { while(m_pStrPos < m_pEndPos && *m_pStrPos == ' ') m_pStrPos++; } bool RootSignatureTokenizer::ToI32(LPCSTR pBuf, int & n) { if(pBuf[0] == '\0') return false; long long N = _atoi64(pBuf); if(N > INT_MAX || N < INT_MIN) return false; n = static_cast(N); return true; } bool RootSignatureTokenizer::ToU32(LPCSTR pBuf, uint32_t & n) { if(pBuf[0] == '\0') return false; long long N = _atoi64(pBuf); if(N > UINT32_MAX || N < 0) return false; n = static_cast(N); return true; } bool RootSignatureTokenizer::ToFloat(LPCSTR pBuf, float & n) { if(pBuf[0] == '\0') return false; errno = 0; double N = strtod(pBuf, NULL); if (errno == ERANGE || (N > FLT_MAX || N < -FLT_MAX)) { return false; } n = static_cast(N); return true; } bool RootSignatureTokenizer::ToRegister(LPCSTR pBuf, Token & T) { uint32_t n; if(ToU32(&pBuf[1], n)) { switch(pBuf[0]) { case 't': T = Token(Token::Type::TReg, pBuf, n); return true; case 's': T = Token(Token::Type::SReg, pBuf, n); return true; case 'u': T = Token(Token::Type::UReg, pBuf, n); return true; case 'b': T = Token(Token::Type::BReg, pBuf, n); return true; } } return false; } bool RootSignatureTokenizer::ToKeyword(LPCSTR pBuf, Token & T, const char *pKeyword, Token::Type Type) { // Tokens are case-insencitive to allow more flexibility for programmers if(_stricmp(pBuf, pKeyword) == 0) { T = Token(Type, pBuf); return true; } else { T = Token(Token::Type::Unknown, pBuf); return false; } } bool RootSignatureTokenizer::IsSeparator(char c) const { return (c == ',' || c == '=' || c == '|' || c == '(' || c == ')' || c == ' ' || c == '\t' || c == '\n'); } bool RootSignatureTokenizer::IsDigit(char c) const { return isdigit(c) > 0; } bool RootSignatureTokenizer::IsAlpha(char c) const { return isalpha(c) > 0; } RootSignatureParser::RootSignatureParser( RootSignatureTokenizer *pTokenizer, DxilRootSignatureVersion DefaultVersion, llvm::raw_ostream &OS) : m_pTokenizer(pTokenizer), m_Version(DefaultVersion), m_OS(OS) {} HRESULT RootSignatureParser::Parse(DxilVersionedRootSignatureDesc **ppRootSignature) { HRESULT hr = S_OK; DxilVersionedRootSignatureDesc *pRS = NULL; if(ppRootSignature != NULL) { IFC(ParseRootSignature(&pRS)); *ppRootSignature = pRS; } Cleanup: return hr; } HRESULT RootSignatureParser::GetAndMatchToken(TokenType & Token, TokenType::Type Type) { HRESULT hr = S_OK; Token = m_pTokenizer->GetToken(); if(Token.GetType() != Type) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); Cleanup: return hr; } HRESULT RootSignatureParser::Error(uint32_t uErrorNum, LPCSTR pError, ...) { va_list Args; char msg[512]; int len; va_start(Args, pError); len = vsprintf_s(msg, pError, Args); va_end(Args); try { m_OS << msg; } CATCH_CPP_RETURN_HRESULT(); return E_FAIL; } HRESULT RootSignatureParser::ParseRootSignature(DxilVersionedRootSignatureDesc **ppRootSignature) { HRESULT hr = S_OK; TokenType Token; bool bSeenFlags = false; SmallVector RSParameters; DxilRootParameter1 *pRSParams = NULL; SmallVector StaticSamplers; DxilStaticSamplerDesc *pStaticSamplers = NULL; DxilVersionedRootSignatureDesc *pRS = NULL; *ppRootSignature = NULL; IFCOOM(pRS = NEW DxilVersionedRootSignatureDesc); // Always parse root signature string to the latest version. pRS->Version = DxilRootSignatureVersion::Version_1_1; memset(&pRS->Desc_1_1, 0, sizeof(pRS->Desc_1_1)); Token = m_pTokenizer->PeekToken(); while(Token.GetType() != TokenType::EOL) { switch(Token.GetType()) { case TokenType::RootFlags: if(!bSeenFlags) { IFC(ParseRootSignatureFlags(pRS->Desc_1_1.Flags)); bSeenFlags = true; } else { IFC(Error(ERR_RS_ROOTFLAGS_MORE_THAN_ONCE, "RootFlags cannot be specified more than once")); } break; case TokenType::RootConstants: { DxilRootParameter1 P; IFC(ParseRootConstants(P)); RSParameters.push_back(P); break; } case TokenType::CBV: { DxilRootParameter1 P; IFC(ParseRootShaderResource(Token.GetType(), TokenType::BReg, DxilRootParameterType::CBV, P)); RSParameters.push_back(P); break; } case TokenType::SRV: { DxilRootParameter1 P; IFC(ParseRootShaderResource(Token.GetType(), TokenType::TReg, DxilRootParameterType::SRV, P)); RSParameters.push_back(P); break; } case TokenType::UAV: { DxilRootParameter1 P; IFC(ParseRootShaderResource(Token.GetType(), TokenType::UReg, DxilRootParameterType::UAV, P)); RSParameters.push_back(P); break; } case TokenType::DescriptorTable: { DxilRootParameter1 P; IFC(ParseRootDescriptorTable(P)); RSParameters.push_back(P); break; } case TokenType::StaticSampler: { DxilStaticSamplerDesc P; IFC(ParseStaticSampler(P)); StaticSamplers.push_back(P); break; } default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s' when parsing root signature", Token.GetStr())); } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::EOL) break; // Consume ',' if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected ',', found: '%s'", Token.GetStr())); Token = m_pTokenizer->PeekToken(); } if(RSParameters.size() > 0) { IFCOOM(pRSParams = NEW DxilRootParameter1[RSParameters.size()]); pRS->Desc_1_1.NumParameters = RSParameters.size(); memcpy(pRSParams, RSParameters.data(), pRS->Desc_1_1.NumParameters*sizeof(DxilRootParameter1)); pRS->Desc_1_1.pParameters = pRSParams; } if(StaticSamplers.size() > 0) { IFCOOM(pStaticSamplers = NEW DxilStaticSamplerDesc[StaticSamplers.size()]); pRS->Desc_1_1.NumStaticSamplers = StaticSamplers.size(); memcpy(pStaticSamplers, StaticSamplers.data(), pRS->Desc_1_1.NumStaticSamplers*sizeof(DxilStaticSamplerDesc)); pRS->Desc_1_1.pStaticSamplers = pStaticSamplers; } // Down-convert root signature to the right version, if needed. if(pRS->Version != m_Version) { DxilVersionedRootSignatureDesc *pRS1 = NULL; try { hlsl::ConvertRootSignature(pRS, m_Version, (const DxilVersionedRootSignatureDesc **)&pRS1); } CATCH_CPP_ASSIGN_HRESULT(); IFC(hr); hlsl::DeleteRootSignature(pRS); pRS = pRS1; } *ppRootSignature = pRS; Cleanup: if(FAILED(hr)) { hlsl::DeleteRootSignature(pRS); } return hr; } HRESULT RootSignatureParser::ParseRootSignatureFlags(DxilRootSignatureFlags & Flags) { //RootFlags(ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT | DENY_VERTEX_SHADER_ROOT_ACCESS) // ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT // DENY_VERTEX_SHADER_ROOT_ACCESS // DENY_HULL_SHADER_ROOT_ACCESS // DENY_DOMAIN_SHADER_ROOT_ACCESS // DENY_GEOMETRY_SHADER_ROOT_ACCESS // DENY_PIXEL_SHADER_ROOT_ACCESS // ALLOW_STREAM_OUTPUT HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::RootFlags)); IFC(GetAndMatchToken(Token, TokenType::LParen)); Flags = DxilRootSignatureFlags::None; Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::NumberU32) { IFC(GetAndMatchToken(Token, TokenType::NumberU32)); uint32_t n = Token.GetU32Value(); if(n != 0) { IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Root signature flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr())); } } else { for(;;) { Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT: Flags |= DxilRootSignatureFlags::AllowInputAssemblerInputLayout; break; case TokenType::DENY_VERTEX_SHADER_ROOT_ACCESS: Flags |= DxilRootSignatureFlags::DenyVertexShaderRootAccess; break; case TokenType::DENY_HULL_SHADER_ROOT_ACCESS: Flags |= DxilRootSignatureFlags::DenyHullShaderRootAccess; break; case TokenType::DENY_DOMAIN_SHADER_ROOT_ACCESS: Flags |= DxilRootSignatureFlags::DenyDomainShaderRootAccess; break; case TokenType::DENY_GEOMETRY_SHADER_ROOT_ACCESS: Flags |= DxilRootSignatureFlags::DenyGeometryShaderRootAccess; break; case TokenType::DENY_PIXEL_SHADER_ROOT_ACCESS: Flags |= DxilRootSignatureFlags::DenyPixelShaderRootAccess; break; case TokenType::ALLOW_STREAM_OUTPUT: Flags |= DxilRootSignatureFlags::AllowStreamOutput; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a root signature flag value, found: '%s'", Token.GetStr())); } Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::RParen) break; IFC(GetAndMatchToken(Token, TokenType::OR)); } } IFC(GetAndMatchToken(Token, TokenType::RParen)); Cleanup: return hr; } HRESULT RootSignatureParser::ParseRootConstants(DxilRootParameter1 &P) { //"RootConstants(num32BitConstants=3, b2 [, space=1, visibility=SHADER_VISIBILITY_ALL ] ), " HRESULT hr = S_OK; TokenType Token; memset(&P, 0, sizeof(P)); DXASSERT(P.ShaderVisibility == DxilShaderVisibility::All, "else default isn't zero"); P.ParameterType = DxilRootParameterType::Constants32Bit; bool bSeenNum32BitConstants = false; bool bSeenBReg = false; bool bSeenSpace = false; bool bSeenVisibility = false; IFC(GetAndMatchToken(Token, TokenType::RootConstants)); IFC(GetAndMatchToken(Token, TokenType::LParen)); for(;;) { Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::num32BitConstants: IFC(MarkParameter(bSeenNum32BitConstants, "num32BitConstants")); IFC(ParseNum32BitConstants(P.Constants.Num32BitValues)); break; case TokenType::BReg: IFC(MarkParameter(bSeenBReg, "cbuffer register b#")); IFC(ParseRegister(TokenType::BReg, P.Constants.ShaderRegister)); break; case TokenType::space: IFC(MarkParameter(bSeenSpace, "space")); IFC(ParseSpace(P.Constants.RegisterSpace)); break; case TokenType::visibility: IFC(MarkParameter(bSeenVisibility, "visibility")); IFC(ParseVisibility(P.ShaderVisibility)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); break; } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::RParen) break; else if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); } if(!bSeenNum32BitConstants) { IFC(Error(ERR_RS_UNDEFINED_REGISTER, "num32BitConstants must be defined for each RootConstants")); } if(!bSeenBReg) { IFC(Error(ERR_RS_UNDEFINED_REGISTER, "Constant buffer register b# must be defined for each RootConstants")); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseRootShaderResource(TokenType::Type TokType, TokenType::Type RegType, DxilRootParameterType ResType, DxilRootParameter1 &P) { // CBV(b0 [, space=3, flags=0, visibility=VISIBILITY_ALL] ) HRESULT hr = S_OK; TokenType Token; P.ParameterType = ResType; P.ShaderVisibility = DxilShaderVisibility::All; P.Descriptor.ShaderRegister = 0; P.Descriptor.RegisterSpace = 0; P.Descriptor.Flags = DxilRootDescriptorFlags::None; bool bSeenReg = false; bool bSeenFlags = false; bool bSeenSpace = false; bool bSeenVisibility = false; IFC(GetAndMatchToken(Token, TokType)); IFC(GetAndMatchToken(Token, TokenType::LParen)); for(;;) { Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::BReg: case TokenType::TReg: case TokenType::UReg: IFC(MarkParameter(bSeenReg, "shader register")); IFC(ParseRegister(RegType, P.Descriptor.ShaderRegister)); break; case TokenType::flags: IFC(MarkParameter(bSeenFlags, "flags")); IFC(ParseRootDescFlags(P.Descriptor.Flags)); break; case TokenType::space: IFC(MarkParameter(bSeenSpace, "space")); IFC(ParseSpace(P.Descriptor.RegisterSpace)); break; case TokenType::visibility: IFC(MarkParameter(bSeenVisibility, "visibility")); IFC(ParseVisibility(P.ShaderVisibility)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); break; } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::RParen) break; else if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); } if(!bSeenReg) { IFC(Error(ERR_RS_UNDEFINED_REGISTER, "shader register must be defined for each CBV/SRV/UAV")); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseRootDescriptorTable(DxilRootParameter1 &P) { //DescriptorTable( SRV(t2, numDescriptors = 6), UAV(u0, numDescriptors = 4) [, visibility = SHADER_VISIBILITY_ALL ] ) HRESULT hr = S_OK; TokenType Token; memset(&P, 0, sizeof(P)); DXASSERT(P.ShaderVisibility == DxilShaderVisibility::All, "else default isn't zero"); P.ParameterType = DxilRootParameterType::DescriptorTable; bool bSeenVisibility = false; DxilDescriptorRange1 * pDescs = NULL; SmallVector Ranges; IFC(GetAndMatchToken(Token, TokenType::DescriptorTable)); IFC(GetAndMatchToken(Token, TokenType::LParen)); for(;;) { Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::CBV: { DxilDescriptorRange1 R; IFC(ParseDescTableResource(Token.GetType(), TokenType::BReg, DxilDescriptorRangeType::CBV, R)); Ranges.push_back(R); break; } case TokenType::SRV: { DxilDescriptorRange1 R; IFC(ParseDescTableResource(Token.GetType(), TokenType::TReg, DxilDescriptorRangeType::SRV, R)); Ranges.push_back(R); break; } case TokenType::UAV: { DxilDescriptorRange1 R; IFC(ParseDescTableResource(Token.GetType(), TokenType::UReg, DxilDescriptorRangeType::UAV, R)); Ranges.push_back(R); break; } case TokenType::Sampler: { DxilDescriptorRange1 R; IFC(ParseDescTableResource(Token.GetType(), TokenType::SReg, DxilDescriptorRangeType::Sampler, R)); Ranges.push_back(R); break; } case TokenType::visibility: IFC(MarkParameter(bSeenVisibility, "visibility")); IFC(ParseVisibility(P.ShaderVisibility)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); break; } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::RParen) break; else if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); } if(Ranges.size() > 0) { IFCOOM(pDescs = NEW DxilDescriptorRange1[Ranges.size()]); for(uint32_t i = 0; i < Ranges.size(); i++) { pDescs[i] = Ranges[i]; } P.DescriptorTable.pDescriptorRanges = pDescs; P.DescriptorTable.NumDescriptorRanges = Ranges.size(); } Cleanup: if(FAILED(hr)) { delete[] pDescs; } return hr; } HRESULT RootSignatureParser::ParseDescTableResource(TokenType::Type TokType, TokenType::Type RegType, DxilDescriptorRangeType RangeType, DxilDescriptorRange1 &R) { HRESULT hr = S_OK; TokenType Token; // CBV(b0 [, numDescriptors = 1, space=0, flags=0, offset = DESCRIPTOR_RANGE_OFFSET_APPEND] ) R.RangeType = RangeType; R.NumDescriptors = 1; R.BaseShaderRegister = 0; R.RegisterSpace = 0; R.Flags = DxilDescriptorRangeFlags::None; R.OffsetInDescriptorsFromTableStart = DxilDescriptorRangeOffsetAppend; bool bSeenReg = false; bool bSeenNumDescriptors = false; bool bSeenSpace = false; bool bSeenFlags = false; bool bSeenOffset = false; IFC(GetAndMatchToken(Token, TokType)); IFC(GetAndMatchToken(Token, TokenType::LParen)); for(;;) { Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::BReg: case TokenType::TReg: case TokenType::UReg: case TokenType::SReg: IFC(MarkParameter(bSeenReg, "shader register")); IFC(ParseRegister(RegType, R.BaseShaderRegister)); break; case TokenType::numDescriptors: IFC(MarkParameter(bSeenNumDescriptors, "numDescriptors")); IFC(ParseNumDescriptors(R.NumDescriptors)); break; case TokenType::space: IFC(MarkParameter(bSeenSpace, "space")); IFC(ParseSpace(R.RegisterSpace)); break; case TokenType::flags: IFC(MarkParameter(bSeenFlags, "flags")); IFC(ParseDescRangeFlags(RangeType, R.Flags)); break; case TokenType::offset: IFC(MarkParameter(bSeenOffset, "offset")); IFC(ParseOffset(R.OffsetInDescriptorsFromTableStart)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); break; } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::RParen) break; else if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); } if(!bSeenReg) { IFC(Error(ERR_RS_UNDEFINED_REGISTER, "shader register must be defined for each CBV/SRV/UAV")); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseRegister(TokenType::Type RegType, uint32_t & Reg) { HRESULT hr = S_OK; TokenType Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::BReg: IFC(GetAndMatchToken(Token, TokenType::BReg)); break; case TokenType::TReg: IFC(GetAndMatchToken(Token, TokenType::TReg)); break; case TokenType::UReg: IFC(GetAndMatchToken(Token, TokenType::UReg)); break; case TokenType::SReg: IFC(GetAndMatchToken(Token, TokenType::SReg)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a register token (CBV, SRV, UAV, Sampler), found: '%s'", Token.GetStr())); } if(Token.GetType() != RegType) { switch(RegType) { case TokenType::BReg: IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in CBV (expected b#)", Token.GetStr())); break; case TokenType::TReg: IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in SRV (expected t#)", Token.GetStr())); break; case TokenType::UReg: IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in UAV (expected u#)", Token.GetStr())); break; case TokenType::SReg: IFC(Error(ERR_RS_INCORRECT_REGISTER_TYPE, "Incorrect register type '%s' in Sampler/StaticSampler (expected s#)", Token.GetStr())); break; } } Reg = Token.GetU32Value(); Cleanup: return hr; } HRESULT RootSignatureParser::ParseSpace(uint32_t & Space) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::space)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(GetAndMatchToken(Token, TokenType::NumberU32)); Space = Token.GetU32Value(); Cleanup: return hr; } HRESULT RootSignatureParser::ParseNumDescriptors(uint32_t & NumDescriptors) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::numDescriptors)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::unbounded) { IFC(GetAndMatchToken(Token, TokenType::unbounded)); NumDescriptors = UINT32_MAX; } else { IFC(GetAndMatchToken(Token, TokenType::NumberU32)); NumDescriptors = Token.GetU32Value(); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseRootDescFlags(DxilRootDescriptorFlags &Flags) { // flags=DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE HRESULT hr = S_OK; TokenType Token; if (m_Version == DxilRootSignatureVersion::Version_1_0) { IFC(Error(ERR_RS_WRONG_ROOT_DESC_FLAG, "Root descriptor flags cannot be specified for root_sig_1_0")); } IFC(GetAndMatchToken(Token, TokenType::flags)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Flags = DxilRootDescriptorFlags::None; Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::NumberU32) { IFC(GetAndMatchToken(Token, TokenType::NumberU32)); uint32_t n = Token.GetU32Value(); if(n != 0) { IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Root descriptor flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr())); } } else { for(;;) { Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::DATA_VOLATILE: Flags |= DxilRootDescriptorFlags::DataVolatile; break; case TokenType::DATA_STATIC: Flags |= DxilRootDescriptorFlags::DataStatic; break; case TokenType::DATA_STATIC_WHILE_SET_AT_EXECUTE: Flags |= DxilRootDescriptorFlags::DataStaticWhileSetAtExecute; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a root descriptor flag value, found: '%s'", Token.GetStr())); } Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::RParen || Token.GetType() == TokenType::Comma) break; IFC(GetAndMatchToken(Token, TokenType::OR)); } } Cleanup: return hr; } HRESULT RootSignatureParser::ParseDescRangeFlags(DxilDescriptorRangeType, DxilDescriptorRangeFlags & Flags) { // flags=DESCRIPTORS_VOLATILE | DATA_VOLATILE | DATA_STATIC | DATA_STATIC_WHILE_SET_AT_EXECUTE HRESULT hr = S_OK; TokenType Token; if (m_Version == DxilRootSignatureVersion::Version_1_0) { IFC(Error(ERR_RS_WRONG_DESC_RANGE_FLAG, "Descriptor range flags cannot be specified for root_sig_1_0")); } IFC(GetAndMatchToken(Token, TokenType::flags)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Flags = DxilDescriptorRangeFlags::None; Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::NumberU32) { IFC(GetAndMatchToken(Token, TokenType::NumberU32)); uint32_t n = Token.GetU32Value(); if(n != 0) { IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Descriptor range flag values can only be 0 or flag enum values, found: '%s'", Token.GetStr())); } } else { for(;;) { Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::DESCRIPTORS_VOLATILE: Flags |= DxilDescriptorRangeFlags::DescriptorsVolatile; break; case TokenType::DATA_VOLATILE: Flags |= DxilDescriptorRangeFlags::DataVolatile; break; case TokenType::DATA_STATIC: Flags |= DxilDescriptorRangeFlags::DataStatic; break; case TokenType::DATA_STATIC_WHILE_SET_AT_EXECUTE: Flags |= DxilDescriptorRangeFlags::DataStaticWhileSetAtExecute; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected a descriptor range flag value, found: '%s'", Token.GetStr())); } Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::RParen || Token.GetType() == TokenType::Comma) break; IFC(GetAndMatchToken(Token, TokenType::OR)); } } Cleanup: return hr; } HRESULT RootSignatureParser::ParseOffset(uint32_t & Offset) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::offset)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->PeekToken(); if(Token.GetType() == TokenType::DESCRIPTOR_RANGE_OFFSET_APPEND) { IFC(GetAndMatchToken(Token, TokenType::DESCRIPTOR_RANGE_OFFSET_APPEND)); Offset = DxilDescriptorRangeOffsetAppend; } else { IFC(GetAndMatchToken(Token, TokenType::NumberU32)); Offset = Token.GetU32Value(); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseVisibility(DxilShaderVisibility & Vis) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::visibility)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::SHADER_VISIBILITY_ALL: Vis = DxilShaderVisibility::All; break; case TokenType::SHADER_VISIBILITY_VERTEX: Vis = DxilShaderVisibility::Vertex; break; case TokenType::SHADER_VISIBILITY_HULL: Vis = DxilShaderVisibility::Hull; break; case TokenType::SHADER_VISIBILITY_DOMAIN: Vis = DxilShaderVisibility::Domain; break; case TokenType::SHADER_VISIBILITY_GEOMETRY: Vis = DxilShaderVisibility::Geometry; break; case TokenType::SHADER_VISIBILITY_PIXEL: Vis = DxilShaderVisibility::Pixel; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected visibility value: '%s'.", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseNum32BitConstants(uint32_t & NumConst) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::num32BitConstants)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(GetAndMatchToken(Token, TokenType::NumberU32)); NumConst = Token.GetU32Value(); Cleanup: return hr; } HRESULT RootSignatureParser::ParseStaticSampler(DxilStaticSamplerDesc &P) { // StaticSampler( s0, // [ Filter = FILTER_ANISOTROPIC, // AddressU = TEXTURE_ADDRESS_WRAP, // AddressV = TEXTURE_ADDRESS_WRAP, // AddressW = TEXTURE_ADDRESS_WRAP, // MipLODBias = 0, // MaxAnisotropy = 16, // ComparisonFunc = COMPARISON_LESS_EQUAL, // BorderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE, // MinLOD = 0.f, // MaxLOD = 3.402823466e+38f // space = 0, // visibility = SHADER_VISIBILITY_ALL ] ) HRESULT hr = S_OK; TokenType Token; memset(&P, 0, sizeof(P)); P.Filter = DxilFilter::ANISOTROPIC; P.AddressU = P.AddressV = P.AddressW = DxilTextureAddressMode::Wrap; P.MaxAnisotropy = 16; P.ComparisonFunc = DxilComparisonFunc::LessEqual; P.BorderColor = DxilStaticBorderColor::OpaqueWhite; P.MaxLOD = DxilFloat32Max; bool bSeenFilter = false; bool bSeenAddressU = false; bool bSeenAddressV = false; bool bSeenAddressW = false; bool bSeenMipLODBias = false; bool bSeenMaxAnisotropy = false; bool bSeenComparisonFunc = false; bool bSeenBorderColor = false; bool bSeenMinLOD = false; bool bSeenMaxLOD = false; bool bSeenSReg = false; bool bSeenSpace = false; bool bSeenVisibility = false; IFC(GetAndMatchToken(Token, TokenType::StaticSampler)); IFC(GetAndMatchToken(Token, TokenType::LParen)); for(;;) { Token = m_pTokenizer->PeekToken(); switch(Token.GetType()) { case TokenType::filter: IFC(MarkParameter(bSeenFilter, "filter")); IFC(ParseFilter(P.Filter)); break; case TokenType::addressU: IFC(MarkParameter(bSeenAddressU, "addressU")); IFC(ParseTextureAddressMode(P.AddressU)); break; case TokenType::addressV: IFC(MarkParameter(bSeenAddressV, "addressV")); IFC(ParseTextureAddressMode(P.AddressV)); break; case TokenType::addressW: IFC(MarkParameter(bSeenAddressW, "addressW")); IFC(ParseTextureAddressMode(P.AddressW)); break; case TokenType::mipLODBias: IFC(MarkParameter(bSeenMipLODBias, "mipLODBias")); IFC(ParseMipLODBias(P.MipLODBias)); break; case TokenType::maxAnisotropy: IFC(MarkParameter(bSeenMaxAnisotropy, "maxAnisotropy")); IFC(ParseMaxAnisotropy(P.MaxAnisotropy)); break; case TokenType::comparisonFunc: IFC(MarkParameter(bSeenComparisonFunc, "comparisonFunc")); IFC(ParseComparisonFunction(P.ComparisonFunc)); break; case TokenType::borderColor: IFC(MarkParameter(bSeenBorderColor, "borderColor")); IFC(ParseBorderColor(P.BorderColor)); break; case TokenType::minLOD: IFC(MarkParameter(bSeenMinLOD, "minLOD")); IFC(ParseMinLOD(P.MinLOD)); break; case TokenType::maxLOD: IFC(MarkParameter(bSeenMaxLOD, "maxLOD")); IFC(ParseMaxLOD(P.MaxLOD)); break; case TokenType::SReg: IFC(MarkParameter(bSeenSReg, "sampler register s#")); IFC(ParseRegister(TokenType::SReg, P.ShaderRegister)); break; case TokenType::space: IFC(MarkParameter(bSeenSpace, "space")); IFC(ParseSpace(P.RegisterSpace)); break; case TokenType::visibility: IFC(MarkParameter(bSeenVisibility, "visibility")); IFC(ParseVisibility(P.ShaderVisibility)); break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); break; } Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::RParen) break; else if(Token.GetType() != TokenType::Comma) IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected token '%s'", Token.GetStr())); } if(!bSeenSReg) { IFC(Error(ERR_RS_UNDEFINED_REGISTER, "Sampler register s# must be defined for each static sampler")); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseFilter(DxilFilter & Filter) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::filter)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::FILTER_MIN_MAG_MIP_POINT: Filter = DxilFilter::MIN_MAG_MIP_POINT; break; case TokenType::FILTER_MIN_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MIN_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MIN_POINT_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MIN_POINT_MAG_MIP_LINEAR: Filter = DxilFilter::MIN_POINT_MAG_MIP_LINEAR; break; case TokenType::FILTER_MIN_LINEAR_MAG_MIP_POINT: Filter = DxilFilter::MIN_LINEAR_MAG_MIP_POINT; break; case TokenType::FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MIN_LINEAR_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MIN_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MIN_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MIN_MAG_MIP_LINEAR: Filter = DxilFilter::MIN_MAG_MIP_LINEAR; break; case TokenType::FILTER_ANISOTROPIC: Filter = DxilFilter::ANISOTROPIC; break; case TokenType::FILTER_COMPARISON_MIN_MAG_MIP_POINT: Filter = DxilFilter::COMPARISON_MIN_MAG_MIP_POINT; break; case TokenType::FILTER_COMPARISON_MIN_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::COMPARISON_MIN_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::COMPARISON_MIN_POINT_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_COMPARISON_MIN_POINT_MAG_MIP_LINEAR: Filter = DxilFilter::COMPARISON_MIN_POINT_MAG_MIP_LINEAR; break; case TokenType::FILTER_COMPARISON_MIN_LINEAR_MAG_MIP_POINT: Filter = DxilFilter::COMPARISON_MIN_LINEAR_MAG_MIP_POINT; break; case TokenType::FILTER_COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::COMPARISON_MIN_LINEAR_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_COMPARISON_MIN_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::COMPARISON_MIN_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_COMPARISON_MIN_MAG_MIP_LINEAR: Filter = DxilFilter::COMPARISON_MIN_MAG_MIP_LINEAR; break; case TokenType::FILTER_COMPARISON_ANISOTROPIC: Filter = DxilFilter::COMPARISON_ANISOTROPIC; break; case TokenType::FILTER_MINIMUM_MIN_MAG_MIP_POINT: Filter = DxilFilter::MINIMUM_MIN_MAG_MIP_POINT; break; case TokenType::FILTER_MINIMUM_MIN_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MINIMUM_MIN_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MINIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MINIMUM_MIN_POINT_MAG_MIP_LINEAR: Filter = DxilFilter::MINIMUM_MIN_POINT_MAG_MIP_LINEAR; break; case TokenType::FILTER_MINIMUM_MIN_LINEAR_MAG_MIP_POINT: Filter = DxilFilter::MINIMUM_MIN_LINEAR_MAG_MIP_POINT; break; case TokenType::FILTER_MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MINIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MINIMUM_MIN_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MINIMUM_MIN_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MINIMUM_MIN_MAG_MIP_LINEAR: Filter = DxilFilter::MINIMUM_MIN_MAG_MIP_LINEAR; break; case TokenType::FILTER_MINIMUM_ANISOTROPIC: Filter = DxilFilter::MINIMUM_ANISOTROPIC; break; case TokenType::FILTER_MAXIMUM_MIN_MAG_MIP_POINT: Filter = DxilFilter::MAXIMUM_MIN_MAG_MIP_POINT; break; case TokenType::FILTER_MAXIMUM_MIN_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MAXIMUM_MIN_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MAXIMUM_MIN_POINT_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MAXIMUM_MIN_POINT_MAG_MIP_LINEAR: Filter = DxilFilter::MAXIMUM_MIN_POINT_MAG_MIP_LINEAR; break; case TokenType::FILTER_MAXIMUM_MIN_LINEAR_MAG_MIP_POINT: Filter = DxilFilter::MAXIMUM_MIN_LINEAR_MAG_MIP_POINT; break; case TokenType::FILTER_MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR: Filter = DxilFilter::MAXIMUM_MIN_LINEAR_MAG_POINT_MIP_LINEAR; break; case TokenType::FILTER_MAXIMUM_MIN_MAG_LINEAR_MIP_POINT: Filter = DxilFilter::MAXIMUM_MIN_MAG_LINEAR_MIP_POINT; break; case TokenType::FILTER_MAXIMUM_MIN_MAG_MIP_LINEAR: Filter = DxilFilter::MAXIMUM_MIN_MAG_MIP_LINEAR; break; case TokenType::FILTER_MAXIMUM_ANISOTROPIC: Filter = DxilFilter::MAXIMUM_ANISOTROPIC; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected filter value: '%s'.", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseTextureAddressMode(DxilTextureAddressMode & AddressMode) { HRESULT hr = S_OK; TokenType Token = m_pTokenizer->GetToken(); DXASSERT_NOMSG(Token.GetType() == TokenType::addressU || Token.GetType() == TokenType::addressV || Token.GetType() == TokenType::addressW); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::TEXTURE_ADDRESS_WRAP: AddressMode = DxilTextureAddressMode::Wrap; break; case TokenType::TEXTURE_ADDRESS_MIRROR: AddressMode = DxilTextureAddressMode::Mirror; break; case TokenType::TEXTURE_ADDRESS_CLAMP: AddressMode = DxilTextureAddressMode::Clamp; break; case TokenType::TEXTURE_ADDRESS_BORDER: AddressMode = DxilTextureAddressMode::Border; break; case TokenType::TEXTURE_ADDRESS_MIRROR_ONCE: AddressMode = DxilTextureAddressMode::MirrorOnce; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected texture address mode value: '%s'.", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseMipLODBias(float & MipLODBias) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::mipLODBias)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(ParseFloat(MipLODBias)); Cleanup: return hr; } HRESULT RootSignatureParser::ParseMaxAnisotropy(uint32_t & MaxAnisotropy) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::maxAnisotropy)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(GetAndMatchToken(Token, TokenType::NumberU32)); MaxAnisotropy = Token.GetU32Value(); Cleanup: return hr; } HRESULT RootSignatureParser::ParseComparisonFunction(DxilComparisonFunc & ComparisonFunc) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::comparisonFunc)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::COMPARISON_NEVER: ComparisonFunc = DxilComparisonFunc::Never; break; case TokenType::COMPARISON_LESS: ComparisonFunc = DxilComparisonFunc::Less; break; case TokenType::COMPARISON_EQUAL: ComparisonFunc = DxilComparisonFunc::Equal; break; case TokenType::COMPARISON_LESS_EQUAL: ComparisonFunc = DxilComparisonFunc::LessEqual; break; case TokenType::COMPARISON_GREATER: ComparisonFunc = DxilComparisonFunc::Greater; break; case TokenType::COMPARISON_NOT_EQUAL: ComparisonFunc = DxilComparisonFunc::NotEqual; break; case TokenType::COMPARISON_GREATER_EQUAL: ComparisonFunc = DxilComparisonFunc::GreaterEqual; break; case TokenType::COMPARISON_ALWAYS: ComparisonFunc = DxilComparisonFunc::Always; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected texture address mode value: '%s'.", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseBorderColor(DxilStaticBorderColor & BorderColor) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::borderColor)); IFC(GetAndMatchToken(Token, TokenType::EQ)); Token = m_pTokenizer->GetToken(); switch(Token.GetType()) { case TokenType::STATIC_BORDER_COLOR_TRANSPARENT_BLACK: BorderColor = DxilStaticBorderColor::TransparentBlack; break; case TokenType::STATIC_BORDER_COLOR_OPAQUE_BLACK: BorderColor = DxilStaticBorderColor::OpaqueBlack; break; case TokenType::STATIC_BORDER_COLOR_OPAQUE_WHITE: BorderColor = DxilStaticBorderColor::OpaqueWhite; break; default: IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Unexpected texture address mode value: '%s'.", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::ParseMinLOD(float & MinLOD) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::minLOD)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(ParseFloat(MinLOD)); Cleanup: return hr; } HRESULT RootSignatureParser::ParseMaxLOD(float & MaxLOD) { HRESULT hr = S_OK; TokenType Token; IFC(GetAndMatchToken(Token, TokenType::maxLOD)); IFC(GetAndMatchToken(Token, TokenType::EQ)); IFC(ParseFloat(MaxLOD)); Cleanup: return hr; } HRESULT RootSignatureParser::ParseFloat(float & v) { HRESULT hr = S_OK; TokenType Token = m_pTokenizer->GetToken(); if(Token.GetType() == TokenType::NumberU32) { v = (float)Token.GetU32Value(); } else if(Token.GetType() == TokenType::NumberI32) { v = (float)Token.GetI32Value(); } else if(Token.GetType() == TokenType::NumberFloat) { v = Token.GetFloatValue(); } else { IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Expected float, found token '%s'", Token.GetStr())); } Cleanup: return hr; } HRESULT RootSignatureParser::MarkParameter(bool & bSeen, LPCSTR pName) { HRESULT hr = S_OK; if(bSeen) { IFC(Error(ERR_RS_UNEXPECTED_TOKEN, "Parameter '%s' can be specified only once", pName)); } bSeen = true; Cleanup: return hr; } _Use_decl_annotations_ bool clang::ParseHLSLRootSignature( const char *pData, unsigned Len, hlsl::DxilRootSignatureVersion Ver, hlsl::DxilVersionedRootSignatureDesc **ppDesc, SourceLocation Loc, clang::DiagnosticsEngine &Diags) { *ppDesc = nullptr; std::string OSStr; llvm::raw_string_ostream OS(OSStr); hlsl::RootSignatureTokenizer RST(pData, Len); hlsl::RootSignatureParser RSP(&RST, Ver, OS); hlsl::DxilVersionedRootSignatureDesc *D = nullptr; if (SUCCEEDED(RSP.Parse(&D))) { *ppDesc = D; return true; } else { // Create diagnostic error message. OS.flush(); if (OSStr.empty()) { Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << "unexpected"; } else { Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << OSStr.c_str(); } return false; } } _Use_decl_annotations_ void clang::ReportHLSLRootSigError(clang::DiagnosticsEngine &Diags, clang::SourceLocation Loc, const char *pData, unsigned Len) { Diags.Report(Loc, clang::diag::err_hlsl_rootsig) << StringRef(pData, Len); return; }