void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table) { // currently we only support top level parameters. // Should be enough for the beginning. (TODO) // print out constant names D3DXCONSTANTTABLE_DESC tblDesc; HRESULT hr = table->GetDesc(&tblDesc); if (!FAILED(hr)) { for (int i=0; i<(int)tblDesc.Constants; ++i) { D3DXCONSTANT_DESC d; UINT n = 1; D3DXHANDLE cHndl = table->GetConstant(NULL, i); if (!FAILED(table->GetConstantDesc(cHndl, &d, &n))) { core::stringc s = " '"; s += d.Name; s += "' Registers:[begin:"; s += (int)d.RegisterIndex; s += ", count:"; s += (int)d.RegisterCount; s += "]"; os::Printer::log(s.c_str()); } } } }
int compileHLSLToD3D9(const char* from, const char* to, const std::map<std::string, int>& attributes) { LPD3DXBUFFER errors; LPD3DXBUFFER shader; LPD3DXCONSTANTTABLE table; HRESULT hr = D3DXCompileShaderFromFileA(from, nullptr, nullptr, "main", isVertexShader(from) ? "vs_2_0" : "ps_2_0", 0, &shader, &errors, &table); if (FAILED(hr)) hr = D3DXCompileShaderFromFileA(from, nullptr, nullptr, "main", isVertexShader(from) ? "vs_3_0" : "ps_3_0", 0, &shader, &errors, &table); if (errors != nullptr) std::cerr << (char*)errors->GetBufferPointer(); if (!FAILED(hr)) { std::ofstream file(to, std::ios_base::binary); file.put(attributes.size()); for (std::map<std::string, int>::const_iterator attribute = attributes.begin(); attribute != attributes.end(); ++attribute) { file << attribute->first.c_str(); file.put(0); file.put(attribute->second); } D3DXCONSTANTTABLE_DESC desc; table->GetDesc(&desc); file.put(desc.Constants); for (UINT i = 0; i < desc.Constants; ++i) { D3DXHANDLE handle = table->GetConstant(nullptr, i); D3DXCONSTANT_DESC descriptions[10]; UINT count = 10; table->GetConstantDesc(handle, descriptions, &count); if (count > 1) std::cerr << "Error: Number of descriptors for one constant is greater than one." << std::endl; for (UINT i2 = 0; i2 < count; ++i2) { char regtype; switch (descriptions[i2].RegisterSet) { case D3DXRS_BOOL: regtype = 'b'; break; case D3DXRS_INT4: regtype = 'i'; break; case D3DXRS_FLOAT4: regtype = 'f'; break; case D3DXRS_SAMPLER: regtype = 's'; break; } //std::cout << descriptions[i2].Name << " " << regtype << descriptions[i2].RegisterIndex << " " << descriptions[i2].RegisterCount << std::endl; file << descriptions[i2].Name; file.put(0); file.put(regtype); file.put(descriptions[i2].RegisterIndex); file.put(descriptions[i2].RegisterCount); } } DWORD* data = (DWORD*)shader->GetBufferPointer(); for (unsigned i = 0; i < shader->GetBufferSize() / 4; ++i) { if ((data[i] & 0xffff) == 0xfffe) { //comment token unsigned size = (data[i] >> 16) & 0xffff; i += size; } else file.write((char*)&data[i], 4);
GXINT GShaderImpl::UpdateConstTabDesc(LPD3DXCONSTANTTABLE pct, LPD3DXCONSTANTTABLE_DESC pctd, GXUINT uHandleShift) { GXINT nCacheSize = 0; GXDWORD dwTopIndex = (GXDWORD)m_aConstDesc.size() + 1; Marimo::ShaderConstName* pConstNameObj = m_pGraphicsImpl->InlGetShaderConstantNameObj(); pct->GetDesc(pctd); GXD3DXCONSTDESC cd; for(GXUINT i = 0; i < pctd->Constants; i++) { GXUINT uCount; D3DXHANDLE hConst = pct->GetConstant(NULL, i); pct->GetConstantDesc(hConst, &cd, &uCount); //// 把RegisterIndex +1,便于Pixel与Vertex的Index打包 //cd.RegisterIndex = cd.RegisterIndex; #ifdef _DEBUG if(cd.RegisterSet == D3DXRS_SAMPLER) { ASSERT(cd.Bytes == 4); } else if(cd.RegisterSet == D3DXRS_FLOAT4 || cd.RegisterSet == D3DXRS_INT4) { // Shader被优化后有可能Rows和RegisterCount不相等 //ASSERT(cd.Rows == cd.RegisterCount); ASSERT(cd.Bytes == cd.Rows * cd.Columns * sizeof(float)); } else ASSERT(0); #endif // _DEBUG // Sampler不算在常量寄存器内 // 寄存器的大小按照出现的最大寄存器索引+占用的寄存器数量决定, // 因为寄存器可能是跳跃的,不一定是连续使用的. if(cd.RegisterSet != D3DXRS_SAMPLER) { nCacheSize = clMax(nCacheSize, (GXINT)((cd.RegisterIndex + cd.RegisterCount) * sizeof(float4))); // 根据上面的断言调整,保证这个计算不会覆盖 } cd.dwNameID = clStringA(cd.Name).GetHash(); cd.dwHandle = (i + dwTopIndex) << uHandleShift; cd.nCanvasUniform = pConstNameObj->AddName(this, cd.Name, cd.Bytes); m_aConstDesc.push_back(cd); } return nCacheSize; }
HRESULT APIENTRY D3DProxyDeviceAdv::SetVertexShader(IDirect3DVertexShader9* pvShader) { IDirect3DVertexShader9* pShader = NULL; LPD3DXCONSTANTTABLE pConstantTable = NULL; BYTE *pData = NULL; HRESULT hr = m_pDevice->SetVertexShader(pvShader); m_pDevice->GetVertexShader(&pShader); UINT pSizeOfData; if(NULL == pShader) goto grexit; pShader->GetFunction(NULL,&pSizeOfData); findWeirdMirrorsEdgeShader(pSizeOfData); pData = new BYTE[pSizeOfData]; pShader->GetFunction(pData,&pSizeOfData); bool shaderSeen = hasSeenShader(pSizeOfData); D3DXCONSTANT_DESC pConstantDesc[32]; UINT pConstantNum = 32; D3DXGetShaderConstantTable(reinterpret_cast<DWORD*>(pData),&pConstantTable); if(pConstantTable == NULL) goto grexit; D3DXCONSTANTTABLE_DESC pDesc; pConstantTable->GetDesc(&pDesc); for(UINT i = 0; i < pDesc.Constants; i++) { D3DXHANDLE Handle = pConstantTable->GetConstant(NULL,i); if(Handle == NULL) continue; pConstantTable->GetConstantDesc(Handle,pConstantDesc,&pConstantNum); for(UINT j = 0; j < pConstantNum; j++) { removeExistingMatrices(pConstantDesc[j]); parse4by4Matrices(pConstantDesc[j]); parseIndividualFloats(pConstantDesc[j]); } } grexit: _SAFE_RELEASE(pConstantTable); _SAFE_RELEASE(pShader); if(pData) delete[] pData; return hr; }
/** * Returns a collection of modified constants for the specified shader. * (may be an empty collection if no modifications apply) * <StrartRegister, StereoShaderConstant<float>> * * Hash the shader and load modification rules: * If rules for this specific shader use those else use default rules. * * For each shader constant: * Check if constant matches a rule (name and/or index). If it does create a stereoshaderconstant * based on rule and add to map of stereoshaderconstants to return. * * @param pActualVertexShader The actual (not wrapped) vertex shader. * @return Collection of stereoshaderconstants for this shader (empty collection if no modifications). ***/ std::map<UINT, StereoShaderConstant<float>> ShaderModificationRepository::GetModifiedConstantsF(IDirect3DVertexShader9* pActualVertexShader) { // All rules are assumed to be valid. Validation of rules should be done when rules are loaded/created std::vector<ConstantModificationRule*> rulesToApply; std::map<UINT, StereoShaderConstant<float>> result; // Hash the shader and load modification rules BYTE *pData = NULL; UINT pSizeOfData; pActualVertexShader->GetFunction(NULL, &pSizeOfData); pData = new BYTE[pSizeOfData]; pActualVertexShader->GetFunction(pData,&pSizeOfData); uint32_t hash; MurmurHash3_x86_32(pData, pSizeOfData, VIREIO_SEED, &hash); if (m_shaderSpecificModificationRuleIDs.count(hash) == 1) { // There are specific modification rules to use with this shader auto itRules = m_shaderSpecificModificationRuleIDs[hash].begin(); while (itRules != m_shaderSpecificModificationRuleIDs[hash].end()) { rulesToApply.push_back(&(m_AllModificationRules[*itRules])); ++itRules; } } else { // No specific rules, use general rules auto itRules = m_defaultModificationRuleIDs.begin(); while (itRules != m_defaultModificationRuleIDs.end()) { rulesToApply.push_back(&(m_AllModificationRules[*itRules])); ++itRules; } } // Load the constant descriptions for this shader and create StereoShaderConstants as the applicable rules require them. LPD3DXCONSTANTTABLE pConstantTable = NULL; D3DXGetShaderConstantTable(reinterpret_cast<DWORD*>(pData), &pConstantTable); if(pConstantTable) { D3DXCONSTANTTABLE_DESC pDesc; pConstantTable->GetDesc(&pDesc); D3DXCONSTANT_DESC pConstantDesc[64]; for(UINT i = 0; i < pDesc.Constants; i++) { D3DXHANDLE handle = pConstantTable->GetConstant(NULL,i); if(handle == NULL) continue; UINT pConstantNum = 64; pConstantTable->GetConstantDesc(handle, pConstantDesc, &pConstantNum); if (pConstantNum >= 64) { OutputDebugString("ShaderModificationRepository::GetModifiedConstantsF - Need larger constant description buffer"); } for(UINT j = 0; j < pConstantNum; j++) { // We are only modifying selected float vectors/matricies. if (pConstantDesc[j].RegisterSet != D3DXRS_FLOAT4) continue; if ( ((pConstantDesc[j].Class == D3DXPC_VECTOR) && (pConstantDesc[j].RegisterCount == 1)) || (((pConstantDesc[j].Class == D3DXPC_MATRIX_ROWS) || (pConstantDesc[j].Class == D3DXPC_MATRIX_COLUMNS)) && (pConstantDesc[j].RegisterCount == 4)) ) { // Check if any rules match this constant auto itRules = rulesToApply.begin(); while (itRules != rulesToApply.end()) { // Type match if ((*itRules)->m_constantType == pConstantDesc[j].Class) { // name match required if ((*itRules)->m_constantName.size() > 0) { bool nameMatch = false; if ((*itRules)->m_allowPartialNameMatch) { nameMatch = std::strstr(pConstantDesc[j].Name, (*itRules)->m_constantName.c_str()) != NULL; /*if (nameMatch) { OutputDebugString("Match\n"); } else { OutputDebugString("No Match\n"); }*/ } else { nameMatch = (*itRules)->m_constantName.compare(pConstantDesc[j].Name) == 0; //OutputDebugString("Full name match only\n"); } if (!nameMatch) { // no match ++itRules; continue; } } // register match required if ((*itRules)->m_startRegIndex != UINT_MAX) { if ((*itRules)->m_startRegIndex != pConstantDesc[j].RegisterIndex) { // no match ++itRules; continue; } } #ifdef _DEBUG // output shader constant + index switch(pConstantDesc[j].Class) { case D3DXPC_VECTOR: OutputDebugString("D3DXPC_VECTOR"); break; case D3DXPC_MATRIX_ROWS: OutputDebugString("D3DXPC_MATRIX_ROWS"); break; case D3DXPC_MATRIX_COLUMNS: OutputDebugString("D3DXPC_MATRIX_COLUMNS"); break; } char buf[32]; sprintf_s(buf,"Register Index: %d", pConstantDesc[j].RegisterIndex); OutputDebugString(buf); #endif // Create StereoShaderConstant<float> and add to result result.insert(std::pair<UINT, StereoShaderConstant<>>(pConstantDesc[j].RegisterIndex, CreateStereoConstantFrom(*itRules, pConstantDesc[j].RegisterIndex, pConstantDesc[j].RegisterCount))); // only the first matching rule is applied to a constant break; } ++itRules; } } } } } _SAFE_RELEASE(pConstantTable); if (pData) delete[] pData; return result; }
bool compileHLSLShaderDx9(bx::CommandLine& _cmdLine, const std::string& _code, bx::WriterI* _writer) { BX_TRACE("DX9"); const char* profile = _cmdLine.findOption('p', "profile"); if (NULL == profile) { fprintf(stderr, "Shader profile must be specified.\n"); return false; } bool debug = _cmdLine.hasArg('\0', "debug"); uint32_t flags = 0; flags |= debug ? D3DXSHADER_DEBUG : 0; flags |= _cmdLine.hasArg('\0', "avoid-flow-control") ? D3DXSHADER_AVOID_FLOW_CONTROL : 0; flags |= _cmdLine.hasArg('\0', "no-preshader") ? D3DXSHADER_NO_PRESHADER : 0; flags |= _cmdLine.hasArg('\0', "partial-precision") ? D3DXSHADER_PARTIALPRECISION : 0; flags |= _cmdLine.hasArg('\0', "prefer-flow-control") ? D3DXSHADER_PREFER_FLOW_CONTROL : 0; flags |= _cmdLine.hasArg('\0', "backwards-compatibility") ? D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY : 0; bool werror = _cmdLine.hasArg('\0', "Werror"); uint32_t optimization = 3; if (_cmdLine.hasArg(optimization, 'O') ) { optimization = bx::uint32_min(optimization, BX_COUNTOF(s_optimizationLevelDx9)-1); flags |= s_optimizationLevelDx9[optimization]; } else { flags |= D3DXSHADER_SKIPOPTIMIZATION; } BX_TRACE("Profile: %s", profile); BX_TRACE("Flags: 0x%08x", flags); LPD3DXBUFFER code; LPD3DXBUFFER errorMsg; LPD3DXCONSTANTTABLE constantTable; HRESULT hr; // Output preprocessed shader so that HLSL can be debugged via GPA // or PIX. Compiling through memory won't embed preprocessed shader // file path. if (debug) { std::string hlslfp = _cmdLine.findOption('o'); hlslfp += ".hlsl"; writeFile(hlslfp.c_str(), _code.c_str(), (int32_t)_code.size() ); hr = D3DXCompileShaderFromFileA(hlslfp.c_str() , NULL , NULL , "main" , profile , flags , &code , &errorMsg , &constantTable ); } else { hr = D3DXCompileShader(_code.c_str() , (uint32_t)_code.size() , NULL , NULL , "main" , profile , flags , &code , &errorMsg , &constantTable ); } if (FAILED(hr) || (werror && NULL != errorMsg) ) { const char* log = (const char*)errorMsg->GetBufferPointer(); char source[1024]; int32_t line = 0; int32_t column = 0; int32_t start = 0; int32_t end = INT32_MAX; if (3 == sscanf(log, "%[^(](%u,%u):", source, &line, &column) && 0 != line) { start = bx::uint32_imax(1, line-10); end = start + 20; } printCode(_code.c_str(), line, start, end); fprintf(stderr, "Error: 0x%08x %s\n", (uint32_t)hr, log); errorMsg->Release(); return false; } UniformArray uniforms; if (NULL != constantTable) { D3DXCONSTANTTABLE_DESC desc; hr = constantTable->GetDesc(&desc); if (FAILED(hr) ) { fprintf(stderr, "Error 0x%08x\n", (uint32_t)hr); return false; } BX_TRACE("Creator: %s 0x%08x", desc.Creator, (uint32_t /*mingw warning*/)desc.Version); BX_TRACE("Num constants: %d", desc.Constants); BX_TRACE("# cl ty RxC S By Name"); for (uint32_t ii = 0; ii < desc.Constants; ++ii) { D3DXHANDLE handle = constantTable->GetConstant(NULL, ii); D3DXCONSTANT_DESC constDesc; uint32_t count; constantTable->GetConstantDesc(handle, &constDesc, &count); BX_TRACE("%3d %2d %2d [%dx%d] %d %3d %s[%d] c%d (%d)" , ii , constDesc.Class , constDesc.Type , constDesc.Rows , constDesc.Columns , constDesc.StructMembers , constDesc.Bytes , constDesc.Name , constDesc.Elements , constDesc.RegisterIndex , constDesc.RegisterCount ); UniformType::Enum type = findUniformTypeDx9(constDesc); if (UniformType::Count != type) { Uniform un; un.name = '$' == constDesc.Name[0] ? constDesc.Name+1 : constDesc.Name; un.type = type; un.num = constDesc.Elements; un.regIndex = constDesc.RegisterIndex; un.regCount = constDesc.RegisterCount; uniforms.push_back(un); } } } uint16_t count = (uint16_t)uniforms.size(); bx::write(_writer, count); uint32_t fragmentBit = profile[0] == 'p' ? BGFX_UNIFORM_FRAGMENTBIT : 0; for (UniformArray::const_iterator it = uniforms.begin(); it != uniforms.end(); ++it) { const Uniform& un = *it; uint8_t nameSize = (uint8_t)un.name.size(); bx::write(_writer, nameSize); bx::write(_writer, un.name.c_str(), nameSize); uint8_t type = un.type|fragmentBit; bx::write(_writer, type); bx::write(_writer, un.num); bx::write(_writer, un.regIndex); bx::write(_writer, un.regCount); BX_TRACE("%s, %s, %d, %d, %d" , un.name.c_str() , getUniformTypeName(un.type) , un.num , un.regIndex , un.regCount ); } uint16_t shaderSize = (uint16_t)code->GetBufferSize(); bx::write(_writer, shaderSize); bx::write(_writer, code->GetBufferPointer(), shaderSize); uint8_t nul = 0; bx::write(_writer, nul); if (_cmdLine.hasArg('\0', "disasm") ) { LPD3DXBUFFER disasm; D3DXDisassembleShader( (const DWORD*)code->GetBufferPointer() , false , NULL , &disasm ); if (NULL != disasm) { std::string disasmfp = _cmdLine.findOption('o'); disasmfp += ".disasm"; writeFile(disasmfp.c_str(), disasm->GetBufferPointer(), disasm->GetBufferSize() ); disasm->Release(); } } if (NULL != code) { code->Release(); } if (NULL != errorMsg) { errorMsg->Release(); } if (NULL != constantTable) { constantTable->Release(); } return true; }
void main(int argc, char* argv[]) { int i, n; HRESULT hr; LPD3DXBUFFER pCode; LPD3DXBUFFER pErr; LPD3DXCONSTANTTABLE pTbl; char* src_name = "test.hlsl"; char* cod_name = "test.cod"; char* prm_name = "test.prm"; char* profile = "ps_3_0"; if (argc > 1) { src_name = argv[1]; } if (argc > 2) { cod_name = argv[2]; } if (argc > 3) { prm_name = argv[3]; } if (argc > 4) { profile = argv[4]; } hr = D3DXCompileShaderFromFile(src_name, NULL, NULL, "main", profile, D3DXSHADER_PREFER_FLOW_CONTROL, &pCode, &pErr, &pTbl); if (D3D_OK == hr) { D3DXCONSTANTTABLE_DESC desc; pTbl->GetDesc(&desc); n = desc.Constants; SymTbl* pSym = new SymTbl(2*1024*1024); s_tbl.nb_param = 0; printf("# const = %d\n", n); PARAM_INFO* pInfo = s_tbl.info; for (i = 0; i < n; ++i) { UINT count = 1; D3DXCONSTANT_DESC info[1]; D3DXHANDLE hConst = pTbl->GetConstant(NULL, i); pTbl->GetConstantDesc(hConst, info, &count); printf("%s, reg = %d, len = %d\n", info[0].Name, info[0].RegisterIndex, info[0].RegisterCount); int sym_id = pSym->Add((char*)info[0].Name); pInfo->name = sym_id; pInfo->reg = info[0].RegisterIndex; pInfo->len = info[0].RegisterCount; switch (info[0].Type) { case D3DXPT_FLOAT: if (info[0].Class == D3DXPC_SCALAR) { pInfo->type = E_PARAMTYPE_FLOAT; } else { pInfo->type = E_PARAMTYPE_FVEC; } break; case D3DXPT_INT: if (info[0].Class == D3DXPC_SCALAR) { pInfo->type = E_PARAMTYPE_INT; } else { pInfo->type = E_PARAMTYPE_IVEC; } break; case D3DXPT_BOOL: pInfo->type = E_PARAMTYPE_BOOL; break; case D3DXPT_SAMPLER: case D3DXPT_SAMPLER1D: case D3DXPT_SAMPLER2D: case D3DXPT_SAMPLER3D: case D3DXPT_SAMPLERCUBE: pInfo->type = E_PARAMTYPE_SMP; break; } ++pInfo; ++s_tbl.nb_param; } int tbl_size = sizeof(int) + s_tbl.nb_param*sizeof(PARAM_INFO); int prm_size = tbl_size + pSym->Length(); char* pPrm = new char[prm_size]; memcpy(pPrm, &s_tbl, tbl_size); memcpy(pPrm + tbl_size, pSym->Top(), pSym->Length()); Bin_write(cod_name, pCode->GetBufferPointer(), pCode->GetBufferSize()); Bin_write(prm_name, pPrm, prm_size); delete pSym; if (pTbl) { pTbl->Release(); } } else { if (pErr) { char* pErr_msg = (char*)pErr->GetBufferPointer(); printf("%s", pErr_msg); } } if (pErr) { pErr->Release(); } }
int compileHLSLToD3D9(const char* from, const char* to, const std::map<std::string, int>& attributes, EShLanguage stage) { #ifdef SYS_WINDOWS HMODULE lib = LoadLibraryA("d3dx9_43.dll"); if (lib != nullptr) CompileShaderFromFileA = (D3DXCompileShaderFromFileAType)GetProcAddress(lib, "D3DXCompileShaderFromFileA"); if (CompileShaderFromFileA == nullptr) { std::cerr << "d3dx9_43.dll could not be loaded, please install dxwebsetup." << std::endl; return 1; } LPD3DXBUFFER errors; LPD3DXBUFFER shader; LPD3DXCONSTANTTABLE table; HRESULT hr = CompileShaderFromFileA(from, nullptr, nullptr, "main", stage == EShLangVertex ? "vs_2_0" : "ps_2_0", 0, &shader, &errors, &table); if (FAILED(hr)) hr = CompileShaderFromFileA(from, nullptr, nullptr, "main", stage == EShLangVertex ? "vs_3_0" : "ps_3_0", 0, &shader, &errors, &table); if (errors != nullptr) std::cerr << (char*)errors->GetBufferPointer(); if (!FAILED(hr)) { std::ofstream file(to, std::ios_base::binary); file.put((char)attributes.size()); for (std::map<std::string, int>::const_iterator attribute = attributes.begin(); attribute != attributes.end(); ++attribute) { file << attribute->first.c_str(); file.put(0); file.put(attribute->second); } D3DXCONSTANTTABLE_DESC desc; table->GetDesc(&desc); file.put(desc.Constants); for (UINT i = 0; i < desc.Constants; ++i) { D3DXHANDLE handle = table->GetConstant(nullptr, i); D3DXCONSTANT_DESC descriptions[10]; UINT count = 10; table->GetConstantDesc(handle, descriptions, &count); if (count > 1) std::cerr << "Error: Number of descriptors for one constant is greater than one." << std::endl; for (UINT i2 = 0; i2 < count; ++i2) { char regtype; switch (descriptions[i2].RegisterSet) { case D3DXRS_BOOL: regtype = 'b'; break; case D3DXRS_INT4: regtype = 'i'; break; case D3DXRS_FLOAT4: regtype = 'f'; break; case D3DXRS_SAMPLER: regtype = 's'; break; } //std::cout << descriptions[i2].Name << " " << regtype << descriptions[i2].RegisterIndex << " " << descriptions[i2].RegisterCount << std::endl; if (strcmp(descriptions[i2].Name, "dx_ViewAdjust") != 0) file << "_"; // TODO: Remove when kfx is deprecated file << descriptions[i2].Name; file.put(0); file.put(regtype); file.put(descriptions[i2].RegisterIndex); file.put(descriptions[i2].RegisterCount); } } DWORD* data = (DWORD*)shader->GetBufferPointer(); for (unsigned i = 0; i < shader->GetBufferSize() / 4; ++i) { if ((data[i] & 0xffff) == 0xfffe) { //comment token unsigned size = (data[i] >> 16) & 0xffff; i += size; } else file.write((char*)&data[i], 4);