The support for UINT shader constants added in this is just returning warnings in GLES drivers as this would need ES 3.0 git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@6115 dfc29bdd-3216-0410-991c-e03cc46cb475
		
			
				
	
	
		
			425 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			425 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (C) 2002-2012 Nikolaus Gebhardt
 | |
| // This file is part of the "Irrlicht Engine".
 | |
| // For conditions of distribution and use, see copyright notice in irrlicht.h
 | |
| 
 | |
| #include "IrrCompileConfig.h"
 | |
| #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_
 | |
| 
 | |
| #include "CD3D9HLSLMaterialRenderer.h"
 | |
| #include "IShaderConstantSetCallBack.h"
 | |
| #include "IVideoDriver.h"
 | |
| #include "os.h"
 | |
| #include "irrString.h"
 | |
| 
 | |
| #ifndef _IRR_D3D_NO_SHADER_DEBUGGING
 | |
| #include <stdio.h>
 | |
| #endif
 | |
| 
 | |
| 
 | |
| namespace irr
 | |
| {
 | |
| namespace video
 | |
| {
 | |
| 
 | |
| 
 | |
| //! Public constructor
 | |
| CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev,
 | |
| 	video::IVideoDriver* driver, s32& outMaterialTypeNr,
 | |
| 	const c8* vertexShaderProgram,
 | |
| 	const c8* vertexShaderEntryPointName,
 | |
| 	E_VERTEX_SHADER_TYPE vsCompileTarget,
 | |
| 	const c8* pixelShaderProgram,
 | |
| 	const c8* pixelShaderEntryPointName,
 | |
| 	E_PIXEL_SHADER_TYPE psCompileTarget,
 | |
| 	IShaderConstantSetCallBack* callback,
 | |
| 	IMaterialRenderer* baseMaterial,
 | |
| 	s32 userData)
 | |
| 	: CD3D9ShaderMaterialRenderer(d3ddev, driver, callback, baseMaterial, userData),
 | |
| 	VSConstantsTable(0), PSConstantsTable(0)
 | |
| {
 | |
| 
 | |
| 	#ifdef _DEBUG
 | |
| 	setDebugName("CD3D9HLSLMaterialRenderer");
 | |
| 	#endif
 | |
| 
 | |
| 	outMaterialTypeNr = -1;
 | |
| 
 | |
| 	// now create shaders
 | |
| 
 | |
| 	if (vsCompileTarget < 0 || vsCompileTarget > EVST_COUNT)
 | |
| 	{
 | |
| 		os::Printer::log("Invalid HLSL vertex shader compilation target", ELL_ERROR);
 | |
| 		return;
 | |
| 	}
 | |
| 
 | |
| 	if (!createHLSLVertexShader(vertexShaderProgram,
 | |
| 		vertexShaderEntryPointName, VERTEX_SHADER_TYPE_NAMES[vsCompileTarget]))
 | |
| 		return;
 | |
| 
 | |
| 	if (!createHLSLPixelShader(pixelShaderProgram,
 | |
| 		pixelShaderEntryPointName, PIXEL_SHADER_TYPE_NAMES[psCompileTarget]))
 | |
| 		return;
 | |
| 
 | |
| 	// register myself as new material
 | |
| 	outMaterialTypeNr = Driver->addMaterialRenderer(this);
 | |
| }
 | |
| 
 | |
| 
 | |
| //! Destructor
 | |
| CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer()
 | |
| {
 | |
| 	if (VSConstantsTable)
 | |
| 		VSConstantsTable->Release();
 | |
| 
 | |
| 	if (PSConstantsTable)
 | |
| 		PSConstantsTable->Release();
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderProgram,
 | |
| 			const char* shaderEntryPointName,
 | |
| 			const char* shaderTargetName)
 | |
| {
 | |
| 	if (!vertexShaderProgram)
 | |
| 		return true;
 | |
| 
 | |
| 	LPD3DXBUFFER buffer = 0;
 | |
| 	LPD3DXBUFFER errors = 0;
 | |
| 
 | |
| #ifdef _IRR_D3D_NO_SHADER_DEBUGGING
 | |
| 
 | |
| 	size_t dataLen_t = strlen(vertexShaderProgram);
 | |
| 	UINT dataLen = (UINT)dataLen_t;
 | |
| 	if ( dataLen != dataLen_t )
 | |
| 		return false;
 | |
| 
 | |
| 	// compile without debug info
 | |
| 	HRESULT h = stubD3DXCompileShader(
 | |
| 		vertexShaderProgram,
 | |
| 		dataLen,
 | |
| 		0, // macros
 | |
| 		0, // no includes
 | |
| 		shaderEntryPointName,
 | |
| 		shaderTargetName,
 | |
| 		0, // no flags
 | |
| 		&buffer,
 | |
| 		&errors,
 | |
| 		&VSConstantsTable);
 | |
| 
 | |
| #else
 | |
| 
 | |
| 	// compile shader and emit some debug information to
 | |
| 	// make it possible to debug the shader in visual studio
 | |
| 
 | |
| 	static int irr_dbg_hlsl_file_nr = 0;
 | |
| 	++irr_dbg_hlsl_file_nr;
 | |
| 	char tmp[32];
 | |
| 	sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.vsh", irr_dbg_hlsl_file_nr);
 | |
| 
 | |
| 	FILE* f = fopen(tmp, "wb");
 | |
| 	fwrite(vertexShaderProgram, strlen(vertexShaderProgram), 1, f);
 | |
| 	fflush(f);
 | |
| 	fclose(f);
 | |
| 
 | |
| 	HRESULT h = stubD3DXCompileShaderFromFile(
 | |
| 		tmp,
 | |
| 		0, // macros
 | |
| 		0, // no includes
 | |
| 		shaderEntryPointName,
 | |
| 		shaderTargetName,
 | |
| 		D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
 | |
| 		&buffer,
 | |
| 		&errors,
 | |
| 		&VSConstantsTable);
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 	if (FAILED(h))
 | |
| 	{
 | |
| 		os::Printer::log("HLSL vertex shader compilation failed:", ELL_ERROR);
 | |
| 		if (errors)
 | |
| 		{
 | |
| 			os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
 | |
| 			errors->Release();
 | |
| 			if (buffer)
 | |
| 				buffer->Release();
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (errors)
 | |
| 		errors->Release();
 | |
| 
 | |
| 	if (buffer)
 | |
| 	{
 | |
| 		if (FAILED(pID3DDevice->CreateVertexShader((DWORD*)buffer->GetBufferPointer(),
 | |
| 			&VertexShader)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not create hlsl vertex shader.", ELL_ERROR);
 | |
| 			buffer->Release();
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		buffer->Release();
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram,
 | |
| 		const char* shaderEntryPointName,
 | |
| 		const char* shaderTargetName)
 | |
| {
 | |
| 	if (!pixelShaderProgram)
 | |
| 		return true;
 | |
| 
 | |
| 	LPD3DXBUFFER buffer = 0;
 | |
| 	LPD3DXBUFFER errors = 0;
 | |
| 
 | |
| 	DWORD flags = 0;
 | |
| 
 | |
| #ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
 | |
| 	if (Driver->queryFeature(video::EVDF_VERTEX_SHADER_2_0) || Driver->queryFeature(video::EVDF_VERTEX_SHADER_3_0))
 | |
| 		// this one's for newer DX SDKs which don't support ps_1_x anymore
 | |
| 		// instead they'll silently compile 1_x as 2_x when using this flag
 | |
| 		flags |= D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY;
 | |
| #endif
 | |
| #if defined(_IRR_D3D_USE_LEGACY_HLSL_COMPILER) && defined(D3DXSHADER_USE_LEGACY_D3DX9_31_DLL)
 | |
| #ifdef D3DXSHADER_ENABLE_BACKWARDS_COMPATIBILITY
 | |
| 	else
 | |
| #endif
 | |
| 		flags |= D3DXSHADER_USE_LEGACY_D3DX9_31_DLL;
 | |
| #endif
 | |
| 
 | |
| #ifdef _IRR_D3D_NO_SHADER_DEBUGGING
 | |
| 
 | |
| 	size_t dataLen_t = strlen(pixelShaderProgram);
 | |
| 	UINT dataLen = (UINT)dataLen_t;
 | |
| 	if ( dataLen != dataLen_t )
 | |
| 		return false;
 | |
| 
 | |
| 	// compile without debug info
 | |
| 	HRESULT h = stubD3DXCompileShader(
 | |
| 		pixelShaderProgram,
 | |
| 		dataLen,
 | |
| 		0, // macros
 | |
| 		0, // no includes
 | |
| 		shaderEntryPointName,
 | |
| 		shaderTargetName,
 | |
| 		flags,
 | |
| 		&buffer,
 | |
| 		&errors,
 | |
| 		&PSConstantsTable);
 | |
| 
 | |
| #else
 | |
| 
 | |
| 	// compile shader and emit some debug information to
 | |
| 	// make it possible to debug the shader in visual studio
 | |
| 
 | |
| 	static int irr_dbg_hlsl_file_nr = 0;
 | |
| 	++irr_dbg_hlsl_file_nr;
 | |
| 	char tmp[32];
 | |
| 	sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.psh", irr_dbg_hlsl_file_nr);
 | |
| 
 | |
| 	FILE* f = fopen(tmp, "wb");
 | |
| 	fwrite(pixelShaderProgram, strlen(pixelShaderProgram), 1, f);
 | |
| 	fflush(f);
 | |
| 	fclose(f);
 | |
| 
 | |
| 	HRESULT h = stubD3DXCompileShaderFromFile(
 | |
| 		tmp,
 | |
| 		0, // macros
 | |
| 		0, // no includes
 | |
| 		shaderEntryPointName,
 | |
| 		shaderTargetName,
 | |
| 		flags | D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION,
 | |
| 		&buffer,
 | |
| 		&errors,
 | |
| 		&PSConstantsTable);
 | |
| 
 | |
| #endif
 | |
| 
 | |
| 	if (FAILED(h))
 | |
| 	{
 | |
| 		os::Printer::log("HLSL pixel shader compilation failed:", ELL_ERROR);
 | |
| 		if (errors)
 | |
| 		{
 | |
| 			os::Printer::log((c8*)errors->GetBufferPointer(), ELL_ERROR);
 | |
| 			errors->Release();
 | |
| 			if (buffer)
 | |
| 				buffer->Release();
 | |
| 		}
 | |
| 		return false;
 | |
| 	}
 | |
| 
 | |
| 	if (errors)
 | |
| 		errors->Release();
 | |
| 
 | |
| 	if (buffer)
 | |
| 	{
 | |
| 		if (FAILED(pID3DDevice->CreatePixelShader((DWORD*)buffer->GetBufferPointer(),
 | |
| 			&PixelShader)))
 | |
| 		{
 | |
| 			os::Printer::log("Could not create hlsl pixel shader.", ELL_ERROR);
 | |
| 			buffer->Release();
 | |
| 			return false;
 | |
| 		}
 | |
| 
 | |
| 		buffer->Release();
 | |
| 		return true;
 | |
| 	}
 | |
| 
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| s32 CD3D9HLSLMaterialRenderer::getVariableID(bool vertexShader, const c8* name)
 | |
| {
 | |
| 	LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
 | |
| 	if (!tbl)
 | |
| 		return -1;
 | |
| 
 | |
| 	D3DXCONSTANTTABLE_DESC tblDesc;
 | |
| 	if (!FAILED(tbl->GetDesc(&tblDesc)))
 | |
| 	{
 | |
| 		for (u32 i = 0; i < tblDesc.Constants; ++i)
 | |
| 		{
 | |
| 			D3DXHANDLE curConst = tbl->GetConstant(NULL, i);
 | |
| 			D3DXCONSTANT_DESC constDesc;
 | |
| 			UINT ucount = 1;
 | |
| 
 | |
| 			if (!FAILED(tbl->GetConstantDesc(curConst, &constDesc, &ucount)))
 | |
| 				if(strcmp(name, constDesc.Name) == 0)
 | |
| 					return i;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	core::stringc s = "HLSL Variable to get ID not found: '";
 | |
| 	s += name;
 | |
| 	s += "'. Available variables are:";
 | |
| 	os::Printer::log(s.c_str(), ELL_WARNING);
 | |
| 	printHLSLVariables(tbl);
 | |
| 
 | |
| 	return -1;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index,
 | |
| 					const f32* floats, int count)
 | |
| {
 | |
| 	LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
 | |
| 	if (index < 0 || !tbl)
 | |
| 		return false;
 | |
| 
 | |
| 	// currently we only support top level parameters.
 | |
| 	// Should be enough for the beginning. (TODO)
 | |
| 
 | |
| 	D3DXHANDLE hndl = tbl->GetConstant(NULL, index);
 | |
| 	if (!hndl)
 | |
| 		return false;
 | |
| 
 | |
| 	D3DXCONSTANT_DESC Description;
 | |
| 	UINT ucount = 1;
 | |
|     tbl->GetConstantDesc(hndl, &Description, &ucount);
 | |
| 
 | |
| 	if(Description.RegisterSet != D3DXRS_SAMPLER)
 | |
| 	{
 | |
| 		HRESULT hr = tbl->SetFloatArray(pID3DDevice, hndl, floats, count);
 | |
| 		if (FAILED(hr))
 | |
| 		{
 | |
| 			os::Printer::log("Error setting float array for HLSL variable", ELL_WARNING);
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index,
 | |
| 					const s32* ints, int count)
 | |
| {
 | |
| 	LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable;
 | |
| 	if (index < 0 || !tbl)
 | |
| 		return false;
 | |
| 
 | |
| 	// currently we only support top level parameters.
 | |
| 	// Should be enough for the beginning. (TODO)
 | |
| 
 | |
| 	D3DXHANDLE hndl = tbl->GetConstant(NULL, index);
 | |
| 	if (!hndl)
 | |
| 		return false;
 | |
| 
 | |
| 	D3DXCONSTANT_DESC Description;
 | |
| 	UINT ucount = 1;
 | |
|     tbl->GetConstantDesc(hndl, &Description, &ucount);
 | |
| 
 | |
| 	if(Description.RegisterSet != D3DXRS_SAMPLER)
 | |
| 	{
 | |
| 		HRESULT hr = tbl->SetIntArray(pID3DDevice, hndl, ints, count);
 | |
| 		if (FAILED(hr))
 | |
| 		{
 | |
| 			os::Printer::log("Error setting int array for HLSL variable", ELL_WARNING);
 | |
| 			return false;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return true;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, s32 index,
 | |
| 					const u32* ints, int count)
 | |
| {
 | |
| 	os::Printer::log("Error DirectX 9 does not support unsigned integer constants in shaders.", ELL_ERROR);
 | |
| 	return false;
 | |
| }
 | |
| 
 | |
| 
 | |
| bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype)
 | |
| {
 | |
| 	if (VSConstantsTable)
 | |
| 		VSConstantsTable->SetDefaults(pID3DDevice);
 | |
| 
 | |
| 	return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype);
 | |
| }
 | |
| 
 | |
| 
 | |
| 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());
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| }
 | |
| 
 | |
| 
 | |
| } // end namespace video
 | |
| } // end namespace irr
 | |
| 
 | |
| #endif // _IRR_COMPILE_WITH_DIRECT3D_9_
 |