Skip to content

alicealys/shader-tool

Repository files navigation

shader-tool

shader-tool is a C++ library that allows to parse, assemble and disassemble DirectX shader objects at runtime.

Currently it only supports DXBC shaders.

version supported
SM1 DirectX 8
SM2 DirectX 9
SM3 DirectX 9
SM4 ✔️ DirectX 10
SM5 ✔️ DirectX 11
SM5.1 ✔️ DirectX 12
SM6 DirectX 12

Add it to your project

API examples

Parser Example

This code patches all constant buffer accesses by remapping the CB index.

#include <std_include.hpp>

#include <shader-tool/shader.hpp>

void main()
{
	const auto data = utils::io::read_file("ps_test.cso");

	auto shader = alys::shader::shader_object::parse(data);

	const auto remap_cb_index = [&](const std::uint32_t index)
	{
		if (index >= 0x7F)
		{
			return index;
		}
		if (index >= 65)
		{
			return index - 3;
		}
		if (index >= 15)
		{
			return index - 1;
		}
		return index;
	};

	for (auto& instruction : shader.get_instructions())
	{
		if (instruction.opcode.type == D3D10_SB_OPCODE_DCL_CONSTANT_BUFFER)
		{
			continue;
		}

		for (auto& operand : instruction.operands)
		{
			if (operand.type == D3D10_SB_OPERAND_TYPE_CONSTANT_BUFFER && operand.indices[0].value.uint32 <= 4 &&
				operand.indices[1].representation == D3D10_SB_OPERAND_INDEX_IMMEDIATE32)
			{
				operand.indices[1].value.uint32 = remap_cb_index(operand.indices[1].value.uint32);
			}
		}
	}

	shader.print();
	const auto new_shader = shader.serialize();
}

Assembler example

This code generates a shader using the assembler class.

#include <std_include.hpp>

#include <shader-tool/shader.hpp>

#include <utils/io.hpp>

using namespace alys::shader::literals;

void example1()
{
	alys::shader::shader_object shader(alys::shader::pixelshader);

	shader.add_input("SV_POSITION", 0, "xyzw", 0, alys::shader::POS, alys::shader::format_float, "");
	shader.add_input("COLOR", 0, "xyzw", 1, alys::shader::NONE, alys::shader::format_float, "xyzw");
	shader.add_input("TEXCOORD", 0, "xy", 2, alys::shader::NONE, alys::shader::format_float, "xy");
	shader.add_input("TEXCOORD", 1, "xyzw", 3, alys::shader::NONE, alys::shader::format_float, "xyzw");
	shader.add_input("TEXCOORD", 5, "xyz", 4, alys::shader::NONE, alys::shader::format_float, "xyz");

	shader.add_output("SV_TARGET", 0, "xyzw", 0, alys::shader::TARGET, alys::shader::format_float, "");

	auto a = shader.get_assembler();

	a.dcl_globalFlags(refactoring_allowed | early_depth_stencil);

	a.dcl_constantbuffer(cb1[6], immediate_indexed);
	a.dcl_constantbuffer(cb2[2], immediate_indexed);

	a.dcl_sampler(s0);
	a.dcl_sampler(s3);

	a.dcl_resource(t0, texture2d, c(t_float, t_float, t_float, t_float));
	a.dcl_resource(t3, texture2d, c(t_float, t_float, t_float, t_float));

	a.dcl_input_ps(v1.xyzw(), linear_centroid);
	a.dcl_input_ps(v2.xy(), linear_centroid);
	a.dcl_input_ps(v3.xyzw(), linear_centroid);
	a.dcl_input_ps(v4.xyz(), linear_centroid);

	a.dcl_output(o0.xyzw());
	a.dcl_temps(4);
	a.dp3(r0.x(), v3.xyzx(), v3.xyzx());
	a.rsq(r0.x(), r0.x());
	a.mul(r0.xyz(), r0.x(), v3.xyzx());
	a.add(r1.xyz(), -v4.xyzx(), cb1[4].xyzx());
	a.dp3(r0.w(), r1.xyzx(), r1.xyzx());
	a.rsq(r1.w(), r0.w());
	a.sqrt(r0.w(), r0.w());
	a.mul_sat(r0.w(), r0.w(), cb1[4].w());

	a.add_extension(res_dim, texture2d);
	a.add_extension(res_return_type, t_float, t_float, t_float, t_float);
	a.sample_indexable(r2.xyz(), r0.wwww(), t3.xyzw(), s3);

	a.mul(r2.xyz(), r2.xyzx(), r2.xyzx());
	a.mul(r1.xyz(), r1.wwww(), r1.xyzx());
	a.dp3_sat(r0.x(), r1.xyzx(), r0.xyzx());
	a.mul(r0.xyz(), r0.xxxx(), cb1[5].xyzx());

	a.add_extension(res_dim, texture2d);
	a.add_extension(res_return_type, t_float, t_float, t_float, t_float);
	a.sample_indexable(r1.xyzw(), v2.xyxx(), t0.xyzw(), s0);

	a.mul(r3.xyzw(), r1.xyzw(), v1.xyzw());
	a.mad(r0.w(), -r1.w(), v1.w(), l(1.f));
	a.add(r0.w(), -r0.w(), l(1.f));
	a.mul(r1.xyz(), r0.wwww(), cb2[1].xyzx());
	a.mul(r3.xyz(), r3.xyzx(), r3.xyzx());
	a.mul(r3.xyz(), r3.xyzx(), r3.wwww());
	a.mul(r2.xyz(), r2.xyzx(), r3.xyzx());
	a.mad(r0.xyz(), r2.xyzx(), r0.xyzx(), -r1.xyzx());
	a.mad(o0.xyz(), v3.wwww(), r0.xyzx(), r1.xyzx());
	a.mov(o0.w(), l(0.f));
	a.ret();

	shader.print();

	utils::io::write_file("ps_test.cso", shader.serialize());
}
output (printf)
//
// Generated by https://github.com/alicealys/shader-tool
//
//
// Input signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_POSITION              0   xyzw        0      POS   float
// COLOR                    0   xyzw        1   TARGET   float   xyzw
// TEXCOORD                 0     xy        2   TARGET   float     xy
// TEXCOORD                 1   xyzw        3   TARGET   float   xyzw
// TEXCOORD                 5    xyz        4   TARGET   float    xyz
//
// Output signature:
//
// Name                 Index   Mask Register SysValue  Format   Used
// -------------------- ----- ------ -------- -------- ------- ------
// SV_TARGET                0   xyzw        0   TARGET   float
//
ps_5_0
dcl_globalFlags refactoringAllowed | forceEarlyDepthStencil
dcl_constantbuffer CB1[6], immediateIndexed
dcl_constantbuffer CB2[2], immediateIndexed
dcl_sampler s0, mode_default
dcl_sampler s3, mode_default
dcl_resource_texture2d (float,float,float,float) t0
dcl_resource_texture2d (float,float,float,float) t3
dcl_input_ps linear centroid v1.xyzw
dcl_input_ps linear centroid v2.xy
dcl_input_ps linear centroid v3.xyzw
dcl_input_ps linear centroid v4.xyz
dcl_output o0.xyzw
dcl_temps 4
dp3 r0.x, v3.xyzx, v3.xyzx
rsq r0.x, r0.x
mul r0.xyz, r0.x, v3.xyzx
add r1.xyz, -v4.xyzx, cb1[4].xyzx
dp3 r0.w, r1.xyzx, r1.xyzx
rsq r1.w, r0.w
sqrt r0.w, r0.w
mul_sat r0.w, r0.w, cb1[4].w
sample_indexable(texture2d)(float,float,float,float) r2.xyz, r0.wwww, t3.xyzw, s3
mul r2.xyz, r2.xyzx, r2.xyzx
mul r1.xyz, r1.wwww, r1.xyzx
dp3_sat r0.x, r1.xyzx, r0.xyzx
mul r0.xyz, r0.xxxx, cb1[5].xyzx
sample_indexable(texture2d)(float,float,float,float) r1.xyzw, v2.xyxx, t0.xyzw, s0
mul r3.xyzw, r1.xyzw, v1.xyzw
mad r0.w, -r1.w, v1.w, l(1.000000)
add r0.w, -r0.w, l(1.000000)
mul r1.xyz, r0.wwww, cb2[1].xyzx
mul r3.xyz, r3.xyzx, r3.xyzx
mul r3.xyz, r3.xyzx, r3.wwww
mul r2.xyz, r2.xyzx, r3.xyzx
mad r0.xyz, r2.xyzx, r0.xyzx, -r1.xyzx
mad o0.xyz, v3.wwww, r0.xyzx, r1.xyzx
mov o0.w, l(0)
ret

Projects that use shader-tool

Credits