public void Decompile(string relPath) { string file = $"{ShaderDirectory}/{relPath}"; // Arrange. // Act. var bytecode = File.ReadAllBytes(file + ".o"); var decompiledHlsl = HlslWriter.Decompile(bytecode); File.WriteAllText($"{file}.d.hlsl", decompiledHlsl); // Assert. }
public void RecompileShaders(string relPath) { string file = $"{ShaderDirectory}/{relPath}"; // Arrange. var relDir = Path.GetDirectoryName(relPath); Directory.CreateDirectory($"{OutputDir}/{relDir}"); var sourceName = GetSourceNameFromObject($"{ShaderDirectory}/{relPath}.o"); if (ShaderDirectory != OutputDir) { File.Copy($"{ShaderDirectory}/{relDir}/{sourceName}", $"{OutputDir}/{relDir}/{sourceName}", true); } if (ShaderDirectory != OutputDir) { File.Copy($"{ShaderDirectory}/{relPath}.asm", $"{OutputDir}/{relPath}.asm", true); } var asmFileText = string.Join(Environment.NewLine, File.ReadAllLines(file + ".asm").Select(x => x.Trim())); // Act. var binaryFileBytes = File.ReadAllBytes(file + ".o"); var shaderModel = ShaderReader.ReadShader(binaryFileBytes); var decompiledHLSL = HlslWriter.Decompile(shaderModel); File.WriteAllText($"{OutputDir}/{relPath}.d.hlsl", decompiledHLSL); using (var shaderBytecode = ShaderBytecode.FromStream(new MemoryStream(binaryFileBytes))) { var profile = shaderModel.Type == DX9Shader.ShaderType.Pixel ? $"ps_{shaderModel.MajorVersion}_{shaderModel.MinorVersion}" : $"vs_{shaderModel.MajorVersion}_{shaderModel.MinorVersion}"; var compiledShader = ShaderBytecode.Compile(decompiledHLSL, "main", profile); var disassembly = shaderBytecode.Disassemble(); var redisassembly = compiledShader.Bytecode.Disassemble(); File.WriteAllText($"{OutputDir}/{relPath}.d1.asm", disassembly); File.WriteAllText($"{OutputDir}/{relPath}.d2.asm", redisassembly); // Assert. Warn.If(disassembly, Is.EqualTo(redisassembly)); } // Assert. Assert.Pass(); }
public void TestSimpleVertexShaderWithConstants() { var bytecode = ShaderBytecode.Compile(@" struct T { float f; float4 v; }; struct U { row_major float2x3 f; T t[2]; float g; }; U u[3]; float4 HakureiReimuAliceMargatroid; row_major float2x2 m; column_major float2x2 n; sampler Gensokyo[2]; float4 VS(float4 p : POSITION) : POSITION { return p * HakureiReimuAliceMargatroid.w * u[2].t[1].v * m[0].y * n[0].y; } float4 PS(float4 t : TEXCOORD) : COLOR { return tex2D(Gensokyo[0], t.xy) + tex2D(Gensokyo[1], t.zw); } technique Tq { pass p0 { VertexShader = compile vs_3_0 VS(); PixelShader = compile ps_3_0 PS(); } } " , "fx_2_0").Bytecode; var shaderModel = ShaderReader.ReadShader(bytecode); var shaders = from blob in shaderModel.EffectChunk.StateBlobLookup.Values where blob.BlobType == DX9Shader.FX9.StateBlobType.Shader select blob.Shader; string AstDecompile(ShaderModel shader) => new HlslWriter(shader, doAstAnalysis: true).Decompile(); var testVertexShader = shaders.First(s => s.Type == ShaderType.Vertex); var decompiledVertexShader = AstDecompile(testVertexShader); // here we use the `.w` component, to make sure `HakureiReimuAliceMargatroid.w` // is inside the actual decompiled shader too, not just inside constant declaration // (that is, `float4 HakureiReimuAliceMargatroid`). StringAssert.Contains("HakureiReimuAliceMargatroid.w", decompiledVertexShader); // assert that `u[2].t[1].v` appears inside the decompiled source code StringAssert.Contains("u[2].t[1].v", decompiledVertexShader); var testPixelShader = shaders.First(s => s.Type == ShaderType.Pixel); var decompiledPixelShader = AstDecompile(testPixelShader); // assert that sampler array elements `Gensokyo[0]` and `[1]` // appears inside the decompile source code StringAssert.Contains("Gensokyo[0]", decompiledPixelShader); StringAssert.Contains("Gensokyo[1]", decompiledPixelShader); var fromNonAst = HlslWriter.Decompile(bytecode); StringAssert.Contains("HakureiReimuAliceMargatroid.w", fromNonAst); StringAssert.Contains("u[2].t[1].v", fromNonAst); StringAssert.Contains("Gensokyo[0]", fromNonAst); StringAssert.Contains("Gensokyo[1]", fromNonAst); }