|
|
@@ -99,20 +99,56 @@ gs_pixel_shader::gs_pixel_shader(device_t device, const char *file,
|
|
|
throw HRError("Failed to create vertex shader", hr);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Shader compilers will pack constants in to single registers when possible.
|
|
|
+ * For example:
|
|
|
+ *
|
|
|
+ * uniform float3 test1;
|
|
|
+ * uniform float test2;
|
|
|
+ *
|
|
|
+ * will inhabit a single constant register (c0.xyz for 'test1', and c0.w for
|
|
|
+ * 'test2')
|
|
|
+ *
|
|
|
+ * However, if two constants cannot inhabit the same register, the second one
|
|
|
+ * must begin at a new register, for example:
|
|
|
+ *
|
|
|
+ * uniform float2 test1;
|
|
|
+ * uniform float3 test2;
|
|
|
+ *
|
|
|
+ * 'test1' will inhabit register constant c0.xy. However, because there's no
|
|
|
+ * room for 'test2, it must use a new register constant entirely (c1.xyz).
|
|
|
+ *
|
|
|
+ * So if we want to calculate the position of the constants in the constant
|
|
|
+ * buffer, we must take this in to account.
|
|
|
+ */
|
|
|
+
|
|
|
void gs_shader::BuildConstantBuffer()
|
|
|
{
|
|
|
for (size_t i = 0; i < params.size(); i++) {
|
|
|
shader_param ¶m = params[i];
|
|
|
+ size_t size = 0;
|
|
|
+
|
|
|
switch (param.type) {
|
|
|
case SHADER_PARAM_BOOL:
|
|
|
case SHADER_PARAM_INT:
|
|
|
- case SHADER_PARAM_FLOAT: constantSize += sizeof(float); break;
|
|
|
- case SHADER_PARAM_VEC2: constantSize += sizeof(vec2); break;
|
|
|
- case SHADER_PARAM_VEC3: constantSize += sizeof(vec3); break;
|
|
|
- case SHADER_PARAM_VEC4: constantSize += sizeof(vec4); break;
|
|
|
- case SHADER_PARAM_MATRIX4X4:
|
|
|
- constantSize += sizeof(float)*4*4;
|
|
|
+ case SHADER_PARAM_FLOAT: size = sizeof(float); break;
|
|
|
+ case SHADER_PARAM_VEC2: size = sizeof(vec2); break;
|
|
|
+ case SHADER_PARAM_VEC3: size = sizeof(float)*3; break;
|
|
|
+ case SHADER_PARAM_VEC4: size = sizeof(vec4); break;
|
|
|
+ case SHADER_PARAM_MATRIX4X4: size = sizeof(float)*4*4;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* checks to see if this constant needs to start at a new
|
|
|
+ * register */
|
|
|
+ if (size && (constantSize & 15) != 0) {
|
|
|
+ size_t alignMax = (constantSize + 15) & ~15;
|
|
|
+
|
|
|
+ if ((size + constantSize) > alignMax)
|
|
|
+ constantSize = alignMax;
|
|
|
}
|
|
|
+
|
|
|
+ param.pos = constantSize;
|
|
|
+ constantSize += size;
|
|
|
}
|
|
|
|
|
|
if (constantSize) {
|
|
|
@@ -163,16 +199,19 @@ inline void gs_shader::UpdateParam(vector<uint8_t> &constData,
|
|
|
if (!param.curValue.size())
|
|
|
throw "Not all shader parameters were set";
|
|
|
|
|
|
+ /* padding in case the constant needs to start at a new
|
|
|
+ * register */
|
|
|
+ if (param.pos > constData.size()) {
|
|
|
+ uint8_t zero = 0;
|
|
|
+
|
|
|
+ constData.insert(constData.end(),
|
|
|
+ param.pos - constData.size(), zero);
|
|
|
+ }
|
|
|
+
|
|
|
constData.insert(constData.end(),
|
|
|
param.curValue.begin(),
|
|
|
param.curValue.end());
|
|
|
|
|
|
- /* alignment required for float3 constants */
|
|
|
- if (param.type == SHADER_PARAM_VEC3) {
|
|
|
- uint8_t zero = 0;
|
|
|
- constData.insert(constData.end(), sizeof(float), zero);
|
|
|
- }
|
|
|
-
|
|
|
if (param.changed) {
|
|
|
upload = true;
|
|
|
param.changed = false;
|