コード例 #1
0
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());
			}
		}
	}
}
コード例 #2
0
ファイル: D3D9Compiler.cpp プロジェクト: wighawag/kfx
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);
コード例 #3
0
  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;
  }
コード例 #4
0
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;
}
コード例 #5
0
/**
* 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;
}
コード例 #6
0
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;
}
コード例 #7
0
ファイル: hlsl_tool.cpp プロジェクト: gdtiti/kinnabari
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();
	}
}
コード例 #8
0
ファイル: D3D9Compiler.cpp プロジェクト: billhollings/krafix
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);