/
DXShaderData.mojo.cs
210 lines (175 loc) · 7 KB
/
DXShaderData.mojo.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
using System;
using System.Collections.Generic;
using System.Text;
using System.Linq;
namespace Microsoft.Xna.Framework.Graphics
{
internal partial class DXShaderData
{
private MojoShader.MOJOSHADER_symbol[] _symbols;
public static DXShaderData CreateGLSL (byte[] byteCode, List<DXConstantBufferData> cbuffers, int sharedIndex, Dictionary<string, SamplerState> samplerStates)
{
var dxshader = new DXShaderData ();
dxshader.SharedIndex = sharedIndex;
dxshader.Bytecode = (byte[])byteCode.Clone ();
// Use MojoShader to convert the HLSL bytecode to GLSL.
var parseDataPtr = MojoShader.NativeMethods.MOJOSHADER_parse (
"glsl",
byteCode,
byteCode.Length,
IntPtr.Zero,
0,
IntPtr.Zero,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero);
var parseData = DXHelper.Unmarshal<MojoShader.MOJOSHADER_parseData> (parseDataPtr);
if (parseData.error_count > 0) {
var errors = DXHelper.UnmarshalArray<MojoShader.MOJOSHADER_error> (
parseData.errors,
parseData.error_count
);
throw new Exception (errors [0].error);
}
switch (parseData.shader_type) {
case MojoShader.MOJOSHADER_shaderType.MOJOSHADER_TYPE_PIXEL:
dxshader.IsVertexShader = false;
break;
case MojoShader.MOJOSHADER_shaderType.MOJOSHADER_TYPE_VERTEX:
dxshader.IsVertexShader = true;
break;
default:
throw new NotSupportedException ();
}
// Conver the attributes.
//
// TODO: Could this be done using DX shader reflection?
//
{
var attributes = DXHelper.UnmarshalArray<MojoShader.MOJOSHADER_attribute> (
parseData.attributes, parseData.attribute_count);
dxshader._attributes = new Attribute[attributes.Length];
for (var i = 0; i < attributes.Length; i++) {
dxshader._attributes [i].name = attributes [i].name;
dxshader._attributes [i].index = attributes [i].index;
dxshader._attributes [i].usage = DXEffectObject.ToXNAVertexElementUsage (attributes [i].usage);
}
}
var symbols = DXHelper.UnmarshalArray<MojoShader.MOJOSHADER_symbol> (
parseData.symbols, parseData.symbol_count);
//try to put the symbols in the order they are eventually packed into the uniform arrays
//this /should/ be done by pulling the info from mojoshader
Array.Sort (symbols, delegate(MojoShader.MOJOSHADER_symbol a, MojoShader.MOJOSHADER_symbol b) {
uint va = a.register_index;
if (a.info.elements == 1)
va += 1024; //hax. mojoshader puts array objects first
uint vb = b.register_index;
if (b.info.elements == 1)
vb += 1024;
return va.CompareTo (vb);
}
);//(a, b) => ((int)(a.info.elements > 1))a.register_index.CompareTo(b.register_index));
// For whatever reason the register indexing is
// incorrect from MojoShader.
{
uint bool_index = 0;
uint float4_index = 0;
uint int4_index = 0;
for (var i = 0; i < symbols.Length; i++) {
switch (symbols [i].register_set) {
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL:
symbols [i].register_index = bool_index;
bool_index += symbols [i].register_count;
break;
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4:
symbols [i].register_index = float4_index;
float4_index += symbols[i].register_count;
break;
case MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4:
symbols [i].register_index = int4_index;
int4_index += symbols [i].register_count;
break;
}
}
}
// Get the samplers.
var samplers = DXHelper.UnmarshalArray<MojoShader.MOJOSHADER_sampler> (
parseData.samplers, parseData.sampler_count);
dxshader._samplers = new Sampler[samplers.Length];
for (var i = 0; i < samplers.Length; i++) {
//sampler mapping to parameter is unknown atm
dxshader._samplers [i].parameter = -1;
// GLSL needs the sampler name.
dxshader._samplers [i].samplerName = samplers [i].name;
// We need the parameter name for creating the parameter
// listing for the effect... look for that in the symbols.
dxshader._samplers [i].parameterName =
symbols.First (e => e.register_set == MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_SAMPLER &&
e.register_index == samplers [i].index
).name;
SamplerState state = null;
samplerStates.TryGetValue(dxshader._samplers[i].parameterName, out state);
dxshader._samplers[i].state = state;
// Set the rest of the sampler info.
dxshader._samplers [i].type = samplers [i].type;
dxshader._samplers [i].index = samplers [i].index;
}
// Gather all the parameters used by this shader.
var symbol_types = new [] {
new { name = dxshader.IsVertexShader ? "vs_uniforms_bool" : "ps_uniforms_bool", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_BOOL, },
new { name = dxshader.IsVertexShader ? "vs_uniforms_ivec4" : "ps_uniforms_ivec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_INT4, },
new { name = dxshader.IsVertexShader ? "vs_uniforms_vec4" : "ps_uniforms_vec4", set = MojoShader.MOJOSHADER_symbolRegisterSet.MOJOSHADER_SYMREGSET_FLOAT4, },
};
var cbuffer_index = new List<int> ();
for (var i = 0; i < symbol_types.Length; i++) {
var cbuffer = new DXConstantBufferData (symbol_types [i].name,
symbol_types [i].set,
symbols);
if (cbuffer.Size == 0)
continue;
var match = cbuffers.FindIndex (e => e.SameAs (cbuffer));
if (match == -1) {
cbuffer_index.Add (cbuffers.Count);
cbuffers.Add (cbuffer);
} else
cbuffer_index.Add (match);
}
dxshader._cbuffers = cbuffer_index.ToArray ();
var glslCode = parseData.output;
#if GLSLOPTIMIZER
//glslCode = GLSLOptimizer.Optimize(glslCode, ShaderType);
#endif
// TODO: This sort of sucks... why does MojoShader not produce
// code valid for GLES out of the box?
// GLES platforms do not like this.
glslCode = glslCode.Replace ("#version 110", "");
// Add the required precision specifiers for GLES.
var floatPrecision = dxshader.IsVertexShader ? "precision highp float;\r\n" : "precision mediump float;\r\n";
glslCode = "#ifdef GL_ES\r\n" +
floatPrecision +
"precision mediump int;\r\n" +
"#endif\r\n" +
glslCode;
// Store the code for serialization.
dxshader.ShaderCode = Encoding.ASCII.GetBytes (glslCode);
return dxshader;
}
public void SetSamplerParameters (Dictionary<string, DXEffectObject.d3dx_parameter> samplers,
List<DXEffectObject.d3dx_parameter> parameters)
{
for (int i=0; i<_samplers.Length; i++) {
DXEffectObject.d3dx_parameter param;
if (samplers.TryGetValue (_samplers[i].parameterName, out param)) {
var samplerState = (DXEffectObject.d3dx_sampler)param.data;
if (samplerState != null && samplerState.state_count > 0) {
var textureName = samplerState.states [0].parameter.name;
var index = parameters.FindIndex (e => e.name == textureName);
if (index != -1)
_samplers[i].parameter = index;
}
}
}
}
}
}