mirror of
https://github.com/mirkobrombin/raven.git
synced 2026-11-01 21:45:06 +00:00
251 lines
13 KiB
C
251 lines
13 KiB
C
#define INITGUID
|
|
#define CINTERFACE
|
|
#define COBJMACROS
|
|
#define WIN32_LEAN_AND_MEAN
|
|
#include <windows.h>
|
|
#include <d3dcompiler.h>
|
|
#include <d3d11shader.h>
|
|
|
|
/* The MinGW reflection header declares the interfaces without their C call macros. */
|
|
#define CALL(object, method, ...) ((object)->lpVtbl->method((object), ##__VA_ARGS__))
|
|
#define ID3D11ShaderReflection_GetDesc(p, ...) CALL(p, GetDesc, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_GetConstantBufferByName(p, ...) CALL(p, GetConstantBufferByName, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_GetVariableByName(p, ...) CALL(p, GetVariableByName, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_GetInputParameterDesc(p, ...) CALL(p, GetInputParameterDesc, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_GetOutputParameterDesc(p, ...) CALL(p, GetOutputParameterDesc, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_GetThreadGroupSize(p, ...) CALL(p, GetThreadGroupSize, __VA_ARGS__)
|
|
#define ID3D11ShaderReflection_Release(p) CALL(p, Release)
|
|
#define ID3D11ShaderReflectionConstantBuffer_GetDesc(p, ...) CALL(p, GetDesc, __VA_ARGS__)
|
|
#define ID3D11ShaderReflectionConstantBuffer_GetVariableByIndex(p, ...) CALL(p, GetVariableByIndex, __VA_ARGS__)
|
|
#define ID3D11ShaderReflectionVariable_GetDesc(p, ...) CALL(p, GetDesc, __VA_ARGS__)
|
|
#define ID3D11ShaderReflectionVariable_GetType(p) CALL(p, GetType)
|
|
#define ID3D11ShaderReflectionType_GetDesc(p, ...) CALL(p, GetDesc, __VA_ARGS__)
|
|
#define VERTEX_SHADER_TYPE 1
|
|
|
|
static int same(const char *left, const char *right)
|
|
{
|
|
while (*left && *left == *right) ++left, ++right;
|
|
return *left == *right;
|
|
}
|
|
|
|
static int contains(const char *text, const char *part)
|
|
{
|
|
for (; *text; ++text) {
|
|
const char *a = text, *b = part;
|
|
while (*a && *b && *a == *b) ++a, ++b;
|
|
if (!*b)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* The program's own include handler, serving one header from memory. */
|
|
static const char header[] = "#define SCALE 2.0\nfloat4 scaled(float4 v) { return v * SCALE; }\n";
|
|
static int opened, closed;
|
|
|
|
static HRESULT STDMETHODCALLTYPE include_open(ID3DInclude *self, D3D_INCLUDE_TYPE type, const char *name, const void *parent, const void **data, UINT *bytes)
|
|
{
|
|
if (type != D3D_INCLUDE_LOCAL || !same(name, "common.hlsli"))
|
|
return E_FAIL;
|
|
++opened;
|
|
*data = header;
|
|
*bytes = sizeof(header) - 1;
|
|
return S_OK;
|
|
}
|
|
|
|
static HRESULT STDMETHODCALLTYPE include_close(ID3DInclude *self, const void *data)
|
|
{
|
|
++closed;
|
|
return S_OK;
|
|
}
|
|
|
|
static ID3DIncludeVtbl include_vtbl = {include_open, include_close};
|
|
static ID3DInclude include = {&include_vtbl};
|
|
|
|
static const char vertex[] =
|
|
"#include \"common.hlsli\"\n"
|
|
"cbuffer Frame : register(b0) { float4x4 world; float4 tint; };\n"
|
|
"struct Out { float4 position : SV_Position; float4 color : COLOR0; };\n"
|
|
"Out main(float4 position : POSITION, float4 color : COLOR0)\n"
|
|
"{ Out o; o.position = mul(scaled(position), world); o.color = color * tint; return o; }\n";
|
|
|
|
static const char broken[] = "float4 main() : SV_Target { return undefined_name; }\n";
|
|
|
|
static const char compute[] =
|
|
"RWStructuredBuffer<uint> output : register(u0);\n"
|
|
"[numthreads(8, 4, 1)] void main(uint3 id : SV_DispatchThreadID) { output[id.y * 8 + id.x] = id.x + VALUE; }\n";
|
|
|
|
static const char tessellation[] =
|
|
"struct Point { float3 position : POSITION; };\n"
|
|
"struct Constants { float edges[3] : SV_TessFactor; float inside : SV_InsideTessFactor; };\n"
|
|
"Constants constants(InputPatch<Point, 3> patch) { Constants c; c.edges[0] = c.edges[1] = c.edges[2] = 4; c.inside = 2; return c; }\n"
|
|
"[domain(\"tri\")] [partitioning(\"integer\")] [outputtopology(\"triangle_cw\")] [outputcontrolpoints(3)] [patchconstantfunc(\"constants\")]\n"
|
|
"Point hull(InputPatch<Point, 3> patch, uint i : SV_OutputControlPointID) { return patch[i]; }\n"
|
|
"[domain(\"tri\")] float4 domain(Constants c, float3 at : SV_DomainLocation, const OutputPatch<Point, 3> patch) : SV_Position\n"
|
|
"{ return float4(patch[0].position * at.x + patch[1].position * at.y + patch[2].position * at.z, c.inside); }\n";
|
|
|
|
static const char effect[] =
|
|
"float4 tint = float4(1, 0.5, 0.25, 1);\n"
|
|
"float4 vs(float4 p : POSITION) : SV_Position { return p; }\n"
|
|
"float4 ps() : SV_Target { return tint; }\n"
|
|
"BlendState opaque { BlendEnable[0] = FALSE; };\n"
|
|
"technique11 Draw { pass P { SetVertexShader(CompileShader(vs_4_0, vs())); SetPixelShader(CompileShader(ps_4_0, ps()));\n"
|
|
"SetBlendState(opaque, float4(0, 0, 0, 0), 0xffffffff); } }\n";
|
|
|
|
static const char legacy[] = "float4 tint; sampler2D image; float4 main(float2 uv : TEXCOORD0) : COLOR { return tex2D(image, uv) * tint; }\n";
|
|
static const char effect9[] = "float4 tint; sampler2D image; float4 main(float2 uv : TEXCOORD0) : COLOR { return tex2D(image, uv) * tint; }\n"
|
|
"technique T { pass P { AlphaBlendEnable = true; PixelShader = compile ps_2_0 main(); } }\n";
|
|
|
|
int raven_entry(void)
|
|
{
|
|
ID3DBlob *code = NULL, *errors = NULL, *part = NULL;
|
|
ID3D11ShaderReflection *reflector = NULL;
|
|
ID3D11ShaderReflectionConstantBuffer *buffer;
|
|
ID3D11ShaderReflectionVariable *variable;
|
|
ID3D11ShaderReflectionType *type;
|
|
D3D11_SHADER_DESC desc;
|
|
D3D11_SHADER_BUFFER_DESC buffer_desc;
|
|
D3D11_SHADER_VARIABLE_DESC variable_desc;
|
|
D3D11_SHADER_TYPE_DESC type_desc;
|
|
D3D11_SIGNATURE_PARAMETER_DESC parameter;
|
|
D3D_SHADER_MACRO macros[] = {{"VALUE", "7"}, {NULL, NULL}};
|
|
UINT x = 0, y = 0, z = 0;
|
|
const unsigned char *bytes;
|
|
|
|
/* A vertex shader through the program's include handler, then its reflection. */
|
|
if (D3DCompile(vertex, sizeof(vertex) - 1, "vertex.hlsl", NULL, &include, "main", "vs_4_0", 0, 0, &code, &errors) != S_OK || !code)
|
|
return 1;
|
|
if (opened != 1 || closed != 1)
|
|
return 2;
|
|
bytes = ID3D10Blob_GetBufferPointer(code);
|
|
if (ID3D10Blob_GetBufferSize(code) < 32 || bytes[0] != 'D' || bytes[1] != 'X' || bytes[2] != 'B' || bytes[3] != 'C')
|
|
return 3;
|
|
if (D3DReflect(bytes, ID3D10Blob_GetBufferSize(code), &IID_ID3D11ShaderReflection, (void **)&reflector) != S_OK)
|
|
return 4;
|
|
if (ID3D11ShaderReflection_GetDesc(reflector, &desc) != S_OK || desc.Version >> 16 != VERTEX_SHADER_TYPE || (desc.Version >> 4 & 15) != 4)
|
|
return 5;
|
|
if (desc.ConstantBuffers != 1 || desc.InputParameters != 2 || desc.OutputParameters != 2 || !desc.InstructionCount || !desc.Creator)
|
|
return 6;
|
|
buffer = ID3D11ShaderReflection_GetConstantBufferByName(reflector, "Frame");
|
|
if (ID3D11ShaderReflectionConstantBuffer_GetDesc(buffer, &buffer_desc) != S_OK || buffer_desc.Variables != 2 || buffer_desc.Size != 80)
|
|
return 7;
|
|
variable = ID3D11ShaderReflection_GetVariableByName(reflector, "tint");
|
|
if (ID3D11ShaderReflectionVariable_GetDesc(variable, &variable_desc) != S_OK || variable_desc.StartOffset != 64 || variable_desc.Size != 16)
|
|
return 8;
|
|
type = ID3D11ShaderReflectionVariable_GetType(ID3D11ShaderReflectionConstantBuffer_GetVariableByIndex(buffer, 0));
|
|
if (ID3D11ShaderReflectionType_GetDesc(type, &type_desc) != S_OK || type_desc.Class != D3D_SVC_MATRIX_COLUMNS || type_desc.Rows != 4 ||
|
|
type_desc.Columns != 4 || type_desc.Type != D3D_SVT_FLOAT)
|
|
return 9;
|
|
if (ID3D11ShaderReflection_GetInputParameterDesc(reflector, 1, ¶meter) != S_OK || !same(parameter.SemanticName, "COLOR") ||
|
|
parameter.Register != 1)
|
|
return 10;
|
|
if (ID3D11ShaderReflection_GetOutputParameterDesc(reflector, 0, ¶meter) != S_OK || parameter.SystemValueType != D3D_NAME_POSITION)
|
|
return 11;
|
|
/* A lookup that finds nothing still returns an object, whose description fails. */
|
|
if (ID3D11ShaderReflectionVariable_GetDesc(ID3D11ShaderReflection_GetVariableByName(reflector, "missing"), &variable_desc) == S_OK)
|
|
return 12;
|
|
ID3D11ShaderReflection_Release(reflector);
|
|
|
|
/* Parts of the container: a signature, a stripped copy and a listing. */
|
|
if (D3DGetInputSignatureBlob(bytes, ID3D10Blob_GetBufferSize(code), &part) != S_OK || ((unsigned char *)ID3D10Blob_GetBufferPointer(part))[0] != 'D')
|
|
return 13;
|
|
ID3D10Blob_Release(part);
|
|
if (D3DStripShader(bytes, ID3D10Blob_GetBufferSize(code), D3DCOMPILER_STRIP_REFLECTION_DATA, &part) != S_OK ||
|
|
ID3D10Blob_GetBufferSize(part) >= ID3D10Blob_GetBufferSize(code))
|
|
return 14;
|
|
ID3D10Blob_Release(part);
|
|
if (D3DGetBlobPart(bytes, ID3D10Blob_GetBufferSize(code), D3D_BLOB_PRIVATE_DATA, 0, &part) == S_OK)
|
|
return 15;
|
|
if (D3DDisassemble(bytes, ID3D10Blob_GetBufferSize(code), 0, NULL, &part) != S_OK || !contains(ID3D10Blob_GetBufferPointer(part), "vs_4_0"))
|
|
return 16;
|
|
ID3D10Blob_Release(part);
|
|
ID3D10Blob_Release(code);
|
|
if (errors)
|
|
ID3D10Blob_Release(errors);
|
|
|
|
/* A failing compile gives no code and a message naming the file. */
|
|
code = errors = NULL;
|
|
if (D3DCompile(broken, sizeof(broken) - 1, "broken.hlsl", NULL, NULL, "main", "ps_4_0", 0, 0, &code, &errors) != E_FAIL || code || !errors)
|
|
return 17;
|
|
if (!contains(ID3D10Blob_GetBufferPointer(errors), "broken.hlsl(") || !contains(ID3D10Blob_GetBufferPointer(errors), "error"))
|
|
return 18;
|
|
ID3D10Blob_Release(errors);
|
|
/* An include with no handler fails the same way. */
|
|
code = errors = NULL;
|
|
if (D3DCompile(vertex, sizeof(vertex) - 1, "vertex.hlsl", NULL, NULL, "main", "vs_4_0", 0, 0, &code, &errors) != E_FAIL || code || !errors ||
|
|
!contains(ID3D10Blob_GetBufferPointer(errors), "common.hlsli"))
|
|
return 19;
|
|
ID3D10Blob_Release(errors);
|
|
|
|
/* Macros, preprocessing and a compute shader's thread group. */
|
|
if (D3DPreprocess(compute, sizeof(compute) - 1, "compute.hlsl", macros, NULL, &part, NULL) != S_OK ||
|
|
!contains(ID3D10Blob_GetBufferPointer(part), "+ 7") || contains(ID3D10Blob_GetBufferPointer(part), "VALUE"))
|
|
return 20;
|
|
ID3D10Blob_Release(part);
|
|
if (D3DCompile(compute, sizeof(compute) - 1, NULL, macros, NULL, "main", "cs_5_0", 0, 0, &code, NULL) != S_OK)
|
|
return 21;
|
|
if (D3DReflect(ID3D10Blob_GetBufferPointer(code), ID3D10Blob_GetBufferSize(code), &IID_ID3D11ShaderReflection, (void **)&reflector) != S_OK)
|
|
return 22;
|
|
if (ID3D11ShaderReflection_GetThreadGroupSize(reflector, &x, &y, &z) != 32 || x != 8 || y != 4 || z != 1)
|
|
return 23;
|
|
ID3D11ShaderReflection_GetDesc(reflector, &desc);
|
|
if (desc.BoundResources != 1)
|
|
return 24;
|
|
ID3D11ShaderReflection_Release(reflector);
|
|
ID3D10Blob_Release(code);
|
|
|
|
/* Hull and domain shaders, with the tessellator's settings in their reflection. */
|
|
if (D3DCompile(tessellation, sizeof(tessellation) - 1, NULL, NULL, NULL, "hull", "hs_5_0", 0, 0, &code, &errors) != S_OK)
|
|
return 26;
|
|
if (D3DReflect(ID3D10Blob_GetBufferPointer(code), ID3D10Blob_GetBufferSize(code), &IID_ID3D11ShaderReflection, (void **)&reflector) != S_OK)
|
|
return 27;
|
|
ID3D11ShaderReflection_GetDesc(reflector, &desc);
|
|
if (desc.Version >> 16 != 3 || desc.cControlPoints != 3 || desc.TessellatorDomain != D3D_TESSELLATOR_DOMAIN_TRI ||
|
|
desc.HSPartitioning != D3D_TESSELLATOR_PARTITIONING_INTEGER || desc.HSOutputPrimitive != D3D_TESSELLATOR_OUTPUT_TRIANGLE_CW ||
|
|
desc.PatchConstantParameters != 4)
|
|
return 28;
|
|
ID3D11ShaderReflection_Release(reflector);
|
|
ID3D10Blob_Release(code);
|
|
if (D3DCompile(tessellation, sizeof(tessellation) - 1, NULL, NULL, NULL, "domain", "ds_5_0", 0, 0, &code, NULL) != S_OK)
|
|
return 29;
|
|
ID3D10Blob_Release(code);
|
|
|
|
/* An effect has no entry point: fx_5_0 comes out bare, fx_4_0 inside a container. */
|
|
if (D3DCompile(effect, sizeof(effect) - 1, NULL, NULL, NULL, NULL, "fx_5_0", 0, 0, &code, NULL) != S_OK)
|
|
return 30;
|
|
bytes = ID3D10Blob_GetBufferPointer(code);
|
|
if (ID3D10Blob_GetBufferSize(code) < 96 || bytes[0] != 0x01 || bytes[1] != 0x20 || bytes[2] != 0xff || bytes[3] != 0xfe)
|
|
return 31;
|
|
ID3D10Blob_Release(code);
|
|
if (D3DCompile(effect, sizeof(effect) - 1, NULL, NULL, NULL, NULL, "fx_4_0", 0, 0, &code, NULL) != E_FAIL)
|
|
return 32;
|
|
if (D3DCompile(effect, sizeof(effect) - 1, NULL, NULL, NULL, NULL, "fx_5_0", 0, D3DCOMPILE_EFFECT_CHILD_EFFECT, &code, NULL) != E_NOTIMPL)
|
|
return 33;
|
|
|
|
/* A shader model 3 pixel shader starts with its version token. */
|
|
if (D3DCompile(legacy, sizeof(legacy) - 1, NULL, NULL, NULL, "main", "ps_3_0", 0, 0, &code, NULL) != S_OK)
|
|
return 34;
|
|
bytes = ID3D10Blob_GetBufferPointer(code);
|
|
if (ID3D10Blob_GetBufferSize(code) < 8 || bytes[0] != 0x00 || bytes[1] != 0x03 || bytes[2] != 0xff || bytes[3] != 0xff)
|
|
return 35;
|
|
if (D3DDisassemble(bytes, ID3D10Blob_GetBufferSize(code), 0, NULL, &part) != S_OK || !contains(ID3D10Blob_GetBufferPointer(part), "ps_3_0") ||
|
|
!contains(ID3D10Blob_GetBufferPointer(part), "texld"))
|
|
return 36;
|
|
ID3D10Blob_Release(part);
|
|
ID3D10Blob_Release(code);
|
|
|
|
/* A Direct3D 9 effect comes out bare, starting with its version. */
|
|
if (D3DCompile(effect9, sizeof(effect9) - 1, NULL, NULL, NULL, NULL, "fx_2_0", 0, 0, &code, NULL) != S_OK)
|
|
return 37;
|
|
bytes = ID3D10Blob_GetBufferPointer(code);
|
|
if (ID3D10Blob_GetBufferSize(code) < 64 || bytes[0] != 0x01 || bytes[1] != 0x09 || bytes[2] != 0xff || bytes[3] != 0xfe)
|
|
return 38;
|
|
ID3D10Blob_Release(code);
|
|
|
|
/* Blobs made by the program. */
|
|
if (D3DCreateBlob(12, &part) != S_OK || ID3D10Blob_GetBufferSize(part) != 12)
|
|
return 25;
|
|
ID3D10Blob_Release(part);
|
|
return 0;
|
|
}
|