From 15740faf9fe9fe4be08965098bbf2947e096aeeb Mon Sep 17 00:00:00 2001 From: chai Date: Wed, 14 Aug 2019 22:50:43 +0800 Subject: +Unity Runtime code --- Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp | 705 +++++++++++++++++++++++++++++++ 1 file changed, 705 insertions(+) create mode 100644 Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp (limited to 'Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp') diff --git a/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp b/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp new file mode 100644 index 0000000..8a91f74 --- /dev/null +++ b/Runtime/GfxDevice/d3d/VertexPipeD3D9.cpp @@ -0,0 +1,705 @@ +#include "UnityPrefix.h" +#include "VertexPipeD3D9.h" +#include "ShaderGenerator.h" +#include "D3D9Utils.h" +#include "Runtime/GfxDevice/BuiltinShaderParams.h" +#include "External/DirectX/builds/dx9include/d3dx9.h" +#include + + + +#define PRINT_VERTEX_PIPE_STATS 0 + +#define PRINT_AMD_SHADER_ANALYZER_OUTPUT 0 + + + + +// GpuProgramsD3D.cpp +ID3DXBuffer* AssembleD3DShader( const std::string& source ); + + +#if PRINT_AMD_SHADER_ANALYZER_OUTPUT +void PrintAMDShaderAnalyzer( const std::string& source ) +{ + const char* kPath = "C:\\Program Files\\AMD\\GPU ShaderAnalyzer 1.45\\GPUShaderAnalyzer.exe"; + const char* kInputPath = "ShaderInput.txt"; + const char* kOutputPath = "ShaderOutput.txt"; + DeleteFileA(kInputPath); + DeleteFileA(kOutputPath); + FILE* fout = fopen(kInputPath, "wt"); + fwrite(source.c_str(), source.size(), 1, fout); + fclose(fout); + + std::string commandLine = std::string(kPath) + " " + kInputPath + " -Analyze " + kOutputPath + " -Module Latest -ASIC HD3870"; + + STARTUPINFOA si; + ZeroMemory( &si, sizeof(si) ); + si.cb = sizeof(si); + + PROCESS_INFORMATION pi; + ZeroMemory( &pi, sizeof(pi) ); + + if( CreateProcessA( + NULL, // name of executable module + (char*)commandLine.c_str(), // command line string + NULL, // process attributes + NULL, // thread attributes + FALSE, // handle inheritance option + 0, // creation flags + NULL, // new environment block + NULL, // current directory name + &si, // startup information + &pi ) ) // process information + { + WaitForSingleObject( pi.hProcess, INFINITE ); + CloseHandle( pi.hProcess ); + CloseHandle( pi.hThread ); + + FILE* fin = fopen(kOutputPath, "rt"); + if( fin ) { + fseek(fin, 0, SEEK_END); + int length = ftell(fin); + fseek(fin, 0, SEEK_SET); + char* buffer = new char[length+1]; + memset(buffer, 0,length+1); + fread(buffer, length, 1, fin); + fclose(fin); + } + } + //DeleteFileA(kInputPath); + //DeleteFileA(kOutputPath); +} +#endif + + + +static inline D3DCOLOR ColorToD3D( const float color[4] ) +{ + return D3DCOLOR_RGBA( NormalizedToByte(color[0]), NormalizedToByte(color[1]), NormalizedToByte(color[2]), NormalizedToByte(color[3]) ); +} + + +static void ResetDeviceVertexPipeStateD3D9 (IDirect3DDevice9* dev, const TransformState& state, const BuiltinShaderParamValues& builtins, const VertexPipeConfig& config, const VertexPipeDataD3D9& data) +{ + DebugAssertIf (!dev); + + data.haveToResetDeviceState = false; + + dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() ); + Matrix4x4f dummyViewMatrix; + dummyViewMatrix.SetIdentity(); dummyViewMatrix.Get(2,2) = -1.0f; + dev->SetTransform( D3DTS_VIEW, (const D3DMATRIX*)dummyViewMatrix.GetPtr() ); + dev->SetTransform( D3DTS_PROJECTION, (const D3DMATRIX*)builtins.GetMatrixParam(kShaderMatProj).GetPtr() ); + + dev->SetRenderState( D3DRS_COLORVERTEX, FALSE ); + + for( int i = 0; i < kMaxSupportedVertexLights; ++i ) + dev->LightEnable( i, FALSE ); + + dev->SetRenderState( D3DRS_AMBIENT, 0 ); + dev->SetRenderState( D3DRS_LIGHTING, FALSE ); + dev->SetRenderState( D3DRS_SPECULARENABLE, FALSE ); + + for( int i = 0; i < kMaxSupportedTextureCoords; ++i ) { + dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i ); + dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTSS_TCI_PASSTHRU ); + } +} + +void ResetVertexPipeStateD3D9 (IDirect3DDevice9* dev, TransformState& state, BuiltinShaderParamValues& builtins, VertexPipeConfig& config, VertexPipeDataD3D9& data, VertexPipePrevious& previous) +{ + config.Reset(); + data.Reset(); + state.Invalidate(builtins); + previous.Reset(); + + data.haveToResetDeviceState = true; + if (dev) + ResetDeviceVertexPipeStateD3D9 (dev, state, builtins, config, data); +} + + +void SetupFixedFunctionD3D9 ( + IDirect3DDevice9* dev, + TransformState& state, + BuiltinShaderParamValues& builtins, + const VertexPipeConfig& config, + const VertexPipeDataD3D9& data, + VertexPipePrevious& previous, + bool vsActive, bool immediateMode) +{ + if (dev && data.haveToResetDeviceState) + ResetDeviceVertexPipeStateD3D9 (dev, state, builtins, config, data); + + // matrices + if (!vsActive) + { + D3D9_CALL(dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() )); + } + + // set color material first, then material, then color + if( config.colorMaterial != previous.config.colorMaterial ) + { + if( config.colorMaterial != kColorMatDisabled ) + { + D3DMATERIALCOLORSOURCE srcAmbient, srcDiffuse, srcEmission; + switch( config.colorMaterial ) + { + case kColorMatEmission: + srcAmbient = D3DMCS_MATERIAL; + srcDiffuse = D3DMCS_MATERIAL; + srcEmission = D3DMCS_COLOR1; + break; + case kColorMatAmbientAndDiffuse: + srcAmbient = D3DMCS_COLOR1; + srcDiffuse = D3DMCS_COLOR1; + srcEmission = D3DMCS_MATERIAL; + break; + default: + return; + } + D3D9_CALL(dev->SetRenderState( D3DRS_AMBIENTMATERIALSOURCE, srcAmbient )); + D3D9_CALL(dev->SetRenderState( D3DRS_DIFFUSEMATERIALSOURCE, srcDiffuse )); + D3D9_CALL(dev->SetRenderState( D3DRS_SPECULARMATERIALSOURCE, D3DMCS_MATERIAL )); + D3D9_CALL(dev->SetRenderState( D3DRS_EMISSIVEMATERIALSOURCE, srcEmission )); + D3D9_CALL(dev->SetRenderState( D3DRS_COLORVERTEX, TRUE )); + } + else + { + D3D9_CALL(dev->SetRenderState( D3DRS_COLORVERTEX, FALSE )); + } + } + + // material + if( !vsActive && config.hasLighting ) + D3D9_CALL(dev->SetMaterial( &data.material )); + + // lights + D3DLIGHT9 d3dlight; + d3dlight.Ambient.r = d3dlight.Ambient.g = d3dlight.Ambient.b = d3dlight.Ambient.a = 0.0f; + d3dlight.Falloff = 1.0f; + d3dlight.Attenuation0 = 1.0f; + d3dlight.Attenuation1 = 0.0f; + + const UInt32 lightsEnabled = (1<SetLight (i,&d3dlight)); + if (lightDiff) + D3D9_CALL(dev->LightEnable (i,TRUE)); + } + else + { + if (lightDiff) + D3D9_CALL(dev->LightEnable (i, FALSE)); + } + } + previous.vertexLightCount = data.vertexLightCount; + + + // ambient, lighting & specular + if( data.ambient != previous.ambient ) + { + D3D9_CALL(dev->SetRenderState( D3DRS_AMBIENT, ColorToD3D(data.ambient.GetPtr()) )); + previous.ambient = data.ambient; + } + if( config.hasLighting != previous.config.hasLighting ) + { + D3D9_CALL(dev->SetRenderState( D3DRS_LIGHTING, config.hasLighting ? TRUE : FALSE )); + } + if( config.hasSpecular != previous.config.hasSpecular ) + { + D3D9_CALL(dev->SetRenderState( D3DRS_SPECULARENABLE, config.hasSpecular ? TRUE : FALSE )); + } + if (config.hasNormalization != previous.config.hasNormalization) + { + D3D9_CALL(dev->SetRenderState (D3DRS_NORMALIZENORMALS, config.hasNormalization ? TRUE : FALSE)); + } + + + UInt32 textureMatrixModes = config.textureMatrixModes; + UInt32 projectedTextures = data.projectedTextures; + UInt32 textureSources = config.textureSources; + for( int i = 0; i < config.texCoordCount; ++i ) + { + // texgen + UInt32 texSource = (textureSources >> (i*3)) & 0x7; + if( !vsActive ) + { + static DWORD kTexSourceFlags[kTexSourceTypeCount] = { 0, 1, D3DTSS_TCI_SPHEREMAP, D3DTSS_TCI_CAMERASPACEPOSITION, D3DTSS_TCI_CAMERASPACEPOSITION, D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR, D3DTSS_TCI_CAMERASPACENORMAL }; + DWORD d3dsource = kTexSourceFlags[texSource]; + if( immediateMode && texSource <= kTexSourceUV1 ) + d3dsource = i; + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, d3dsource )); + } + else + { + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i )); + } + + // matrix + unsigned matmode = (textureMatrixModes >> (i*2)) & 3; + static DWORD kTexFlags[kTexMatrixTypeCount] = { D3DTTFF_DISABLE, D3DTTFF_COUNT2, D3DTTFF_COUNT3, D3DTTFF_COUNT4 }; + DWORD textureTransformFlags = kTexFlags[matmode]; + if (projectedTextures & (1<SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, textureTransformFlags )); + + if( !vsActive ) + { + if( texSource == kTexSourceObject ) + { + // D3D has no "object space" texture generation. + // So instead we use camera space, and multiply the matrix so it matches: + // newMatrix = matrix * inverse(modelview) * mirrorZ + // Mirror along Z is required to match OpenGL's generation (eye space Z is negative). + Matrix4x4f mv = state.worldViewMatrix; + mv.Invert_Full(); + // Negate Z axis (mv = mv * Scale(1,1,-1)) + mv.Get(0,2) = -mv.Get(0,2); + mv.Get(1,2) = -mv.Get(1,2); + mv.Get(2,2) = -mv.Get(2,2); + mv.Get(3,2) = -mv.Get(3,2); + Matrix4x4f texmat; + MultiplyMatrices4x4 (&state.texMatrices[i], &mv, &texmat); + D3D9_CALL(dev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + i), (const D3DMATRIX*)texmat.GetPtr() )); + } + else + { + D3D9_CALL(dev->SetTransform( (D3DTRANSFORMSTATETYPE)(D3DTS_TEXTURE0 + i), (const D3DMATRIX*)state.texMatrices[i].GetPtr() )); + } + } + } + if( config.texCoordCount != previous.config.texCoordCount ) + { + for( int i = config.texCoordCount; i < kMaxSupportedTextureCoords; ++i ) + { + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i )); + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE )); + } + } + + if( !vsActive ) + D3D9_CALL(dev->SetVertexShader(NULL)); + previous.vertexShader = NULL; + previous.config = config; +} + + + + + +// ---------------------------------------------------------------------- + + + + +struct VSLightData { + Vector4f pos; + Vector4f dir; + Vector4f color; + Vector4f params; +}; + +struct ShaderData { + IDirect3DVertexShader9* shader; + unsigned int usedConstants; + std::string text; + //std::string debug; +}; + + +struct VertexPipeKeyCompare { + union { + VertexPipeConfig key; + UInt64 asint; + } u; + VertexPipeKeyCompare() { u.asint = 0; } + bool operator <( const VertexPipeKeyCompare& r ) const { return u.asint < r.u.asint; } +}; + +typedef std::map ShaderCache; +static ShaderCache g_Shaders; + + +static IDirect3DVertexShader9* GetShaderForConfig( const VertexPipeConfig& config, IDirect3DDevice9* dev, unsigned int& usedConstants ) +{ + VertexPipeKeyCompare key; + key.u.key = config; + ShaderCache::iterator it = g_Shaders.find(key); + if( it != g_Shaders.end() ) { + const ShaderData& sdata = it->second; + usedConstants = sdata.usedConstants; + return sdata.shader; + } + + ShaderGenerator gen; + gen.AddFragment( &kVS_Pos ); + + // lighting + if( config.hasLighting ) + { + // normalize normals? + if (config.hasNormalization) + gen.AddFragment (&kVS_Normalize_Normal); + + UInt32 hasLightType = config.hasLightType; + if( config.hasSpecular ) + { + gen.AddFragment( &kVS_Light_Specular_Pre ); + if( hasLightType & (1<> (i*3)) & 7; + // normalize normals? + if (config.hasNormalization) + { + if (src == kTexSourceSphereMap || src == kTexSourceCubeReflect || src == kTexSourceCubeNormal) + gen.AddFragment (&kVS_Normalize_Normal); + } + gen.AddFragment( kFragSources[src] ); + } + for( int i = 0; i < config.texCoordCount; ++i ) + { + unsigned src = (config.textureSources >> (i*3)) & 7; + unsigned matmode = (config.textureMatrixModes >> (i*2)) & 3; + gen.AddFragment (kFragMatrices[matmode], kFragSourceNames[src], i); + } + ShaderData data; + data.shader = NULL; + gen.GenerateShader( data.text, data.usedConstants ); + + ID3DXBuffer* compiledShader = AssembleD3DShader( data.text ); + if( compiledShader ) { + dev->CreateVertexShader( (const DWORD*)compiledShader->GetBufferPointer(), &data.shader ); + compiledShader->Release(); + } + + AssertIf(!data.shader); + g_Shaders.insert( std::make_pair(key, data) ); + + #if PRINT_AMD_SHADER_ANALYZER_OUTPUT + PrintAMDShaderAnalyzer( data.text ); + #endif + + usedConstants = data.usedConstants; + return data.shader; +} + +void SetupVertexShaderD3D9 ( + IDirect3DDevice9* dev, + TransformState& state, + const BuiltinShaderParamValues& builtins, + VertexPipeConfig& config, + const VertexPipeDataD3D9& data, + VertexPipePrevious& previous, + VertexShaderConstantCache& cache, + bool vsActive, bool immediateMode) +{ + if( vsActive ) + return; + + D3D9_CALL(dev->SetTransform( D3DTS_WORLD, (const D3DMATRIX*)state.worldViewMatrix.GetPtr() )); + + // figure out which light types do we have + if( !config.hasLighting ) { + config.hasLightType = 0; + } else { + UInt32 hasLightType = 0; + for (int i = 0; i < data.vertexLightCount; ++i) + { + hasLightType |= (1<SetVertexShader( shader )); + previous.vertexShader = shader; + } + + // matrices + Matrix4x4f mvp; + MultiplyMatrices4x4 (&builtins.GetMatrixParam(kShaderMatProj), &state.worldViewMatrix, &mvp ); + mvp.Transpose(); + cache.SetValues( kConstantLocations[kConstMatrixMVP], mvp.GetPtr(), 4 ); + + const Matrix4x4f& mv = state.worldViewMatrix; + cache.SetValues( kConstantLocations[kConstMatrixMV], mv.GetPtr(), 4 ); + + if( usedConstants & (1<SetVertexShaderConstantF( kConstantLocations[kConstMatDiffuse], &data.material.Diffuse.r, 1 )); + if( usedConstants & (1<SetVertexShaderConstantI( 0, miscI[0], kLightTypeCount )); + + if (lightsTotal) + cache.SetValues( 60, (const float*)lights, 4*lightsTotal ); + misc[0] = lightStart[0] * 4.0f; + misc[1] = lightStart[1] * 4.0f; + misc[2] = lightStart[2] * 4.0f; + misc[3] = 0.0f; + cache.SetValues(kConstantLocations[kConstLightIndexes], misc, 1); + } + + // texture matrices & transform flags + UInt32 matrixModes = config.textureMatrixModes; + UInt32 projectedTextures = data.projectedTextures; + UInt32 textureSources = config.textureSources; + for( int i = 0; i < config.texCoordCount; ++i ) + { + unsigned matmode = (matrixModes >> (i*2)) & 0x3; + if( matmode != kTexMatrixNone ) + { + cache.SetValues(kConstantLocations[kConstMatrixTexture]+i*4, state.texMatrices[i].GetPtr(), 4); + } + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i )); + // projected texture flag + DWORD textureTransformFlags = (projectedTextures & (1<SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, textureTransformFlags )); + } + + if( config.texCoordCount != previous.config.texCoordCount ) + { + for( int i = config.texCoordCount; i < kMaxSupportedTextureCoords; ++i ) + { + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXCOORDINDEX, i )); + D3D9_CALL(dev->SetTextureStageState( i, D3DTSS_TEXTURETRANSFORMFLAGS, D3DTTFF_DISABLE )); + } + } + + previous.config = config; +} + + +void CleanupVertexShadersD3D9 () +{ + #if PRINT_VERTEX_PIPE_STATS + printf_console("Vertex pipe shader cache: %i shaders generated\n", g_Shaders.size()); + #endif + ShaderCache::iterator it, itEnd = g_Shaders.end(); + for( it = g_Shaders.begin(); it != itEnd; ++it ) + { + IDirect3DVertexShader9* vs = it->second.shader; + if( vs ) { + ULONG refCount = vs->Release(); + AssertIf( refCount != 0 ); + } + } + g_Shaders.clear (); +} + -- cgit v1.1-26-g67d0