Fix shaders reading 10_11_11 bitfields backwards.
This commit is contained in:
parent
2e5c64fb13
commit
55a8964428
|
@ -18,9 +18,7 @@ namespace gl4 {
|
||||||
|
|
||||||
GL4Shader::GL4Shader(ShaderType shader_type, uint64_t data_hash,
|
GL4Shader::GL4Shader(ShaderType shader_type, uint64_t data_hash,
|
||||||
const uint32_t* dword_ptr, uint32_t dword_count)
|
const uint32_t* dword_ptr, uint32_t dword_count)
|
||||||
: Shader(shader_type, data_hash, dword_ptr, dword_count),
|
: Shader(shader_type, data_hash, dword_ptr, dword_count) {}
|
||||||
program_(0),
|
|
||||||
vao_(0) {}
|
|
||||||
|
|
||||||
GL4Shader::~GL4Shader() {
|
GL4Shader::~GL4Shader() {
|
||||||
glDeleteProgram(program_);
|
glDeleteProgram(program_);
|
||||||
|
@ -28,21 +26,29 @@ GL4Shader::~GL4Shader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL4Shader::Prepare() {
|
bool GL4Shader::Prepare() {
|
||||||
if (!Shader::Prepare()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Build static vertex array descriptor.
|
// Build static vertex array descriptor.
|
||||||
if (!PrepareVertexArrayObject()) {
|
if (!PrepareVertexArrayObject()) {
|
||||||
XELOGE("Unable to prepare vertex shader array object");
|
XELOGE("Unable to prepare vertex shader array object");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!CompileProgram()) {
|
bool success = true;
|
||||||
return false;
|
if (!CompileShader()) {
|
||||||
|
host_error_log_ = GetShaderInfoLog();
|
||||||
|
success = false;
|
||||||
|
}
|
||||||
|
if (success && !LinkProgram()) {
|
||||||
|
host_error_log_ = GetProgramInfoLog();
|
||||||
|
success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
if (success) {
|
||||||
|
host_binary_ = GetBinary();
|
||||||
|
host_disassembly_ = GetHostDisasmNV(host_binary_);
|
||||||
|
}
|
||||||
|
is_valid_ = success;
|
||||||
|
|
||||||
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL4Shader::PrepareVertexArrayObject() {
|
bool GL4Shader::PrepareVertexArrayObject() {
|
||||||
|
@ -52,23 +58,24 @@ bool GL4Shader::PrepareVertexArrayObject() {
|
||||||
for (const auto& attrib : vertex_binding.attributes) {
|
for (const auto& attrib : vertex_binding.attributes) {
|
||||||
auto comp_count = GetVertexFormatComponentCount(
|
auto comp_count = GetVertexFormatComponentCount(
|
||||||
attrib.fetch_instr.attributes.data_format);
|
attrib.fetch_instr.attributes.data_format);
|
||||||
GLenum comp_type;
|
GLenum comp_type = 0;
|
||||||
bool is_signed = attrib.fetch_instr.attributes.is_signed;
|
bool is_signed = attrib.fetch_instr.attributes.is_signed;
|
||||||
switch (attrib.fetch_instr.attributes.data_format) {
|
switch (attrib.fetch_instr.attributes.data_format) {
|
||||||
case VertexFormat::k_8_8_8_8:
|
case VertexFormat::k_8_8_8_8:
|
||||||
comp_type = is_signed ? GL_BYTE : GL_UNSIGNED_BYTE;
|
comp_type = is_signed ? GL_BYTE : GL_UNSIGNED_BYTE;
|
||||||
break;
|
break;
|
||||||
case VertexFormat::k_2_10_10_10:
|
case VertexFormat::k_2_10_10_10:
|
||||||
comp_type = is_signed ? GL_INT_2_10_10_10_REV
|
comp_type = is_signed ? GL_INT : GL_UNSIGNED_INT;
|
||||||
: GL_UNSIGNED_INT_2_10_10_10_REV;
|
comp_count = 1;
|
||||||
break;
|
break;
|
||||||
case VertexFormat::k_10_11_11:
|
case VertexFormat::k_10_11_11:
|
||||||
// assert_false(is_signed);
|
comp_type = is_signed ? GL_INT : GL_UNSIGNED_INT;
|
||||||
XELOGW("Signed k_10_11_11 vertex format not supported by GL");
|
comp_count = 1;
|
||||||
comp_type = GL_UNSIGNED_INT_10F_11F_11F_REV;
|
break;
|
||||||
|
case VertexFormat::k_11_11_10:
|
||||||
|
assert_true(is_signed);
|
||||||
|
comp_type = is_signed ? GL_R11F_G11F_B10F : 0;
|
||||||
break;
|
break;
|
||||||
/*case VertexFormat::k_11_11_10:
|
|
||||||
break;*/
|
|
||||||
case VertexFormat::k_16_16:
|
case VertexFormat::k_16_16:
|
||||||
comp_type = is_signed ? GL_SHORT : GL_UNSIGNED_SHORT;
|
comp_type = is_signed ? GL_SHORT : GL_UNSIGNED_SHORT;
|
||||||
break;
|
break;
|
||||||
|
@ -120,83 +127,137 @@ bool GL4Shader::PrepareVertexArrayObject() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GL4Shader::CompileProgram() {
|
bool GL4Shader::CompileShader() {
|
||||||
assert_zero(program_);
|
assert_zero(program_);
|
||||||
|
|
||||||
// Give source to GL.
|
shader_ =
|
||||||
auto source_str = GetTranslatedBinaryString();
|
glCreateShader(shader_type_ == ShaderType::kVertex ? GL_VERTEX_SHADER
|
||||||
auto source_str_ptr = source_str.c_str();
|
: GL_FRAGMENT_SHADER);
|
||||||
program_ = glCreateShaderProgramv(shader_type_ == ShaderType::kVertex
|
if (!shader_) {
|
||||||
? GL_VERTEX_SHADER
|
XELOGE("OpenGL could not create a shader object!");
|
||||||
: GL_FRAGMENT_SHADER,
|
|
||||||
1, &source_str_ptr);
|
|
||||||
if (!program_) {
|
|
||||||
XELOGE("Unable to create shader program");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output info log.
|
auto source_str = GetTranslatedBinaryString();
|
||||||
// log_length includes the null character.
|
auto source_str_ptr = source_str.c_str();
|
||||||
GLint log_length = 0;
|
GLint source_length = GLint(source_str.length());
|
||||||
glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &log_length);
|
glShaderSource(shader_, 1, &source_str_ptr, &source_length);
|
||||||
std::string info_log;
|
glCompileShader(shader_);
|
||||||
if (log_length > 0) {
|
|
||||||
info_log.resize(log_length - 1);
|
GLint status = 0;
|
||||||
glGetProgramInfoLog(program_, log_length, &log_length, &info_log[0]);
|
glGetShaderiv(shader_, GL_COMPILE_STATUS, &status);
|
||||||
|
|
||||||
|
return status == GL_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GL4Shader::LinkProgram() {
|
||||||
|
program_ = glCreateProgram();
|
||||||
|
if (!program_) {
|
||||||
|
XELOGE("OpenGL could not create a shader program!");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info_log.empty()) {
|
glAttachShader(program_, shader_);
|
||||||
XELOGD("Shader log: %s", info_log.c_str());
|
|
||||||
|
// Enable TFB
|
||||||
|
if (shader_type_ == ShaderType::kVertex) {
|
||||||
|
const GLchar* feedbackVaryings = "gl_Position";
|
||||||
|
glTransformFeedbackVaryings(program_, 1, &feedbackVaryings,
|
||||||
|
GL_SEPARATE_ATTRIBS);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get error log, if we failed to link.
|
glProgramParameteri(program_, GL_PROGRAM_SEPARABLE, GL_TRUE);
|
||||||
|
glLinkProgram(program_);
|
||||||
|
|
||||||
GLint link_status = 0;
|
GLint link_status = 0;
|
||||||
glGetProgramiv(program_, GL_LINK_STATUS, &link_status);
|
glGetProgramiv(program_, GL_LINK_STATUS, &link_status);
|
||||||
if (!link_status) {
|
if (!link_status) {
|
||||||
host_error_log_ = std::move(info_log);
|
|
||||||
assert_always("Unable to link generated shader");
|
assert_always("Unable to link generated shader");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get program binary, if it's available.
|
|
||||||
GLint binary_length = 0;
|
|
||||||
glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binary_length);
|
|
||||||
if (binary_length) {
|
|
||||||
host_binary_.resize(binary_length);
|
|
||||||
GLenum binary_format;
|
|
||||||
glGetProgramBinary(program_, binary_length, &binary_length, &binary_format,
|
|
||||||
host_binary_.data());
|
|
||||||
|
|
||||||
// If we are on nvidia, we can find the disassembly string.
|
|
||||||
// I haven't been able to figure out from the format how to do this
|
|
||||||
// without a search like this.
|
|
||||||
const char* disasm_start = nullptr;
|
|
||||||
size_t search_offset = 0;
|
|
||||||
char* search_start = reinterpret_cast<char*>(host_binary_.data());
|
|
||||||
while (true) {
|
|
||||||
auto p = reinterpret_cast<char*>(
|
|
||||||
memchr(host_binary_.data() + search_offset, '!',
|
|
||||||
host_binary_.size() - search_offset));
|
|
||||||
if (!p) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
if (p[0] == '!' && p[1] == '!' && p[2] == 'N' && p[3] == 'V') {
|
|
||||||
disasm_start = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
search_offset = p - search_start;
|
|
||||||
++search_offset;
|
|
||||||
}
|
|
||||||
if (disasm_start) {
|
|
||||||
host_disassembly_ = std::string(disasm_start);
|
|
||||||
} else {
|
|
||||||
host_disassembly_ = std::string("Shader disassembly not available.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string GL4Shader::GetShaderInfoLog() {
|
||||||
|
if (!shader_) {
|
||||||
|
return "GL4Shader::GetShaderInfoLog(): Program is NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string log;
|
||||||
|
GLint log_length = 0;
|
||||||
|
glGetShaderiv(shader_, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
log.resize(log_length - 1);
|
||||||
|
glGetShaderInfoLog(shader_, log_length, &log_length, &log[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GL4Shader::GetProgramInfoLog() {
|
||||||
|
if (!program_) {
|
||||||
|
return "GL4Shader::GetProgramInfoLog(): Program is NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string log;
|
||||||
|
GLint log_length = 0;
|
||||||
|
glGetProgramiv(program_, GL_INFO_LOG_LENGTH, &log_length);
|
||||||
|
if (log_length > 0) {
|
||||||
|
log.resize(log_length - 1);
|
||||||
|
glGetProgramInfoLog(program_, log_length, &log_length, &log[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return log;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> GL4Shader::GetBinary() {
|
||||||
|
std::vector<uint8_t> binary;
|
||||||
|
|
||||||
|
// Get program binary, if it's available.
|
||||||
|
GLint binary_length = 0;
|
||||||
|
glGetProgramiv(program_, GL_PROGRAM_BINARY_LENGTH, &binary_length);
|
||||||
|
if (binary_length) {
|
||||||
|
binary.resize(binary_length);
|
||||||
|
GLenum binary_format;
|
||||||
|
glGetProgramBinary(program_, binary_length, &binary_length, &binary_format,
|
||||||
|
binary.data());
|
||||||
|
}
|
||||||
|
|
||||||
|
return binary;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string GL4Shader::GetHostDisasmNV(const std::vector<uint8_t>& binary) {
|
||||||
|
// If we are on nvidia, we can find the disassembly string.
|
||||||
|
// I haven't been able to figure out from the format how to do this
|
||||||
|
// without a search like this.
|
||||||
|
std::string disasm;
|
||||||
|
|
||||||
|
const char* disasm_start = nullptr;
|
||||||
|
size_t search_offset = 0;
|
||||||
|
const char* search_start = reinterpret_cast<const char*>(binary.data());
|
||||||
|
while (true) {
|
||||||
|
auto p = reinterpret_cast<const char*>(memchr(
|
||||||
|
binary.data() + search_offset, '!', binary.size() - search_offset));
|
||||||
|
if (!p) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (p[0] == '!' && p[1] == '!' && p[2] == 'N' && p[3] == 'V') {
|
||||||
|
disasm_start = p;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
search_offset = p - search_start;
|
||||||
|
++search_offset;
|
||||||
|
}
|
||||||
|
if (disasm_start) {
|
||||||
|
disasm = std::string(disasm_start);
|
||||||
|
} else {
|
||||||
|
disasm = std::string("Shader disassembly not available.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return disasm;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace gl4
|
} // namespace gl4
|
||||||
} // namespace gpu
|
} // namespace gpu
|
||||||
} // namespace xe
|
} // namespace xe
|
||||||
|
|
|
@ -26,16 +26,24 @@ class GL4Shader : public Shader {
|
||||||
~GL4Shader() override;
|
~GL4Shader() override;
|
||||||
|
|
||||||
GLuint program() const { return program_; }
|
GLuint program() const { return program_; }
|
||||||
|
GLuint shader() const { return shader_; }
|
||||||
GLuint vao() const { return vao_; }
|
GLuint vao() const { return vao_; }
|
||||||
|
|
||||||
bool Prepare() override;
|
bool Prepare();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool PrepareVertexArrayObject();
|
bool PrepareVertexArrayObject();
|
||||||
bool CompileProgram();
|
bool CompileShader();
|
||||||
|
bool LinkProgram();
|
||||||
|
|
||||||
GLuint program_;
|
std::string GetShaderInfoLog();
|
||||||
GLuint vao_;
|
std::string GetProgramInfoLog();
|
||||||
|
std::vector<uint8_t> GetBinary();
|
||||||
|
static std::string GetHostDisasmNV(const std::vector<uint8_t>& binary);
|
||||||
|
|
||||||
|
GLuint program_ = 0;
|
||||||
|
GLuint shader_ = 0;
|
||||||
|
GLuint vao_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace gl4
|
} // namespace gl4
|
||||||
|
|
|
@ -25,7 +25,7 @@ constexpr int kMaxTemporaryRegisters = 64;
|
||||||
source_.Append(depth_prefix_); \
|
source_.Append(depth_prefix_); \
|
||||||
source_.AppendFormat(__VA_ARGS__)
|
source_.AppendFormat(__VA_ARGS__)
|
||||||
|
|
||||||
const char* GetVertexFormatTypeName(VertexFormat format) {
|
const char* GetVertexFormatTypeName(VertexFormat format, bool is_signed) {
|
||||||
switch (format) {
|
switch (format) {
|
||||||
case VertexFormat::k_32:
|
case VertexFormat::k_32:
|
||||||
case VertexFormat::k_32_FLOAT:
|
case VertexFormat::k_32_FLOAT:
|
||||||
|
@ -36,11 +36,13 @@ const char* GetVertexFormatTypeName(VertexFormat format) {
|
||||||
case VertexFormat::k_32_32_FLOAT:
|
case VertexFormat::k_32_32_FLOAT:
|
||||||
return "vec2";
|
return "vec2";
|
||||||
case VertexFormat::k_10_11_11:
|
case VertexFormat::k_10_11_11:
|
||||||
|
return is_signed ? "int" : "uint";
|
||||||
|
case VertexFormat::k_2_10_10_10:
|
||||||
|
return is_signed ? "int" : "uint";
|
||||||
case VertexFormat::k_11_11_10:
|
case VertexFormat::k_11_11_10:
|
||||||
case VertexFormat::k_32_32_32_FLOAT:
|
case VertexFormat::k_32_32_32_FLOAT:
|
||||||
return "vec3";
|
return "vec3";
|
||||||
case VertexFormat::k_8_8_8_8:
|
case VertexFormat::k_8_8_8_8:
|
||||||
case VertexFormat::k_2_10_10_10:
|
|
||||||
case VertexFormat::k_16_16_16_16:
|
case VertexFormat::k_16_16_16_16:
|
||||||
case VertexFormat::k_32_32_32_32:
|
case VertexFormat::k_32_32_32_32:
|
||||||
case VertexFormat::k_16_16_16_16_FLOAT:
|
case VertexFormat::k_16_16_16_16_FLOAT:
|
||||||
|
@ -189,6 +191,39 @@ out gl_PerVertex {
|
||||||
};
|
};
|
||||||
layout(location = 0) flat out uint draw_id;
|
layout(location = 0) flat out uint draw_id;
|
||||||
layout(location = 1) out VertexData vtx;
|
layout(location = 1) out VertexData vtx;
|
||||||
|
|
||||||
|
vec3 get_10_11_11_u(const uint data_in) {
|
||||||
|
vec3 vec;
|
||||||
|
vec.x = bitfieldExtract(data_in, 0, 10);
|
||||||
|
vec.y = bitfieldExtract(data_in, 10, 11);
|
||||||
|
vec.z = bitfieldExtract(data_in, 21, 11);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
vec3 get_10_11_11_s(const int data_in) {
|
||||||
|
vec3 vec;
|
||||||
|
vec.x = bitfieldExtract(data_in, 0, 10);
|
||||||
|
vec.y = bitfieldExtract(data_in, 10, 11);
|
||||||
|
vec.z = bitfieldExtract(data_in, 21, 11);
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 get_2_10_10_10_u(const uint data_in) {
|
||||||
|
vec4 vec;
|
||||||
|
vec.x = bitfieldExtract(data_in, 0, 10);
|
||||||
|
vec.y = bitfieldExtract(data_in, 10, 10);
|
||||||
|
vec.z = bitfieldExtract(data_in, 20, 10);
|
||||||
|
vec.w = bitfieldExtract(data_in, 30, 2 );
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
vec4 get_2_10_10_10_s(const int data_in) {
|
||||||
|
vec4 vec;
|
||||||
|
vec.x = bitfieldExtract(data_in, 0, 10);
|
||||||
|
vec.y = bitfieldExtract(data_in, 10, 10);
|
||||||
|
vec.z = bitfieldExtract(data_in, 20, 10);
|
||||||
|
vec.w = bitfieldExtract(data_in, 30, 2 );
|
||||||
|
return vec;
|
||||||
|
}
|
||||||
|
|
||||||
vec4 applyTransform(const in StateData state, vec4 pos) {
|
vec4 applyTransform(const in StateData state, vec4 pos) {
|
||||||
if (state.vtx_fmt.w == 0.0) {
|
if (state.vtx_fmt.w == 0.0) {
|
||||||
// w is 1/W0, so fix it.
|
// w is 1/W0, so fix it.
|
||||||
|
@ -262,7 +297,8 @@ void main() {
|
||||||
}
|
}
|
||||||
defined_locations.insert(key);
|
defined_locations.insert(key);
|
||||||
const char* type_name =
|
const char* type_name =
|
||||||
GetVertexFormatTypeName(attrib.fetch_instr.attributes.data_format);
|
GetVertexFormatTypeName(attrib.fetch_instr.attributes.data_format,
|
||||||
|
attrib.fetch_instr.attributes.is_signed);
|
||||||
EmitSource("layout(location = %d) in %s vf%u_%d;\n",
|
EmitSource("layout(location = %d) in %s vf%u_%d;\n",
|
||||||
attrib.attrib_index, type_name, binding.fetch_constant,
|
attrib.attrib_index, type_name, binding.fetch_constant,
|
||||||
attrib.fetch_instr.attributes.offset);
|
attrib.fetch_instr.attributes.offset);
|
||||||
|
@ -557,16 +593,29 @@ void GlslShaderTranslator::ProcessVertexFetchInstruction(
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (instr.opcode) {
|
switch (instr.opcode) {
|
||||||
case FetchOpcode::kVertexFetch:
|
case FetchOpcode::kVertexFetch: {
|
||||||
EmitSourceDepth("pv.");
|
EmitSourceDepth("pv.");
|
||||||
for (int i = 0;
|
for (int i = 0;
|
||||||
i < GetVertexFormatComponentCount(instr.attributes.data_format);
|
i < GetVertexFormatComponentCount(instr.attributes.data_format);
|
||||||
++i) {
|
++i) {
|
||||||
EmitSource("%c", GetCharForComponentIndex(i));
|
EmitSource("%c", GetCharForComponentIndex(i));
|
||||||
}
|
}
|
||||||
EmitSource(" = vf%u_%d;\n", instr.operands[1].storage_index,
|
|
||||||
instr.attributes.offset);
|
auto format = instr.attributes.data_format;
|
||||||
break;
|
if (format == VertexFormat::k_10_11_11) {
|
||||||
|
// GL doesn't support this format as a fetch type, so convert it.
|
||||||
|
EmitSource(" = get_10_11_11_%c(vf%u_%d);\n",
|
||||||
|
instr.attributes.is_signed ? 's' : 'u',
|
||||||
|
instr.operands[1].storage_index, instr.attributes.offset);
|
||||||
|
} else if (format == VertexFormat::k_2_10_10_10) {
|
||||||
|
EmitSource(" = get_2_10_10_10_%c(vf%u_%d);\n",
|
||||||
|
instr.attributes.is_signed ? 's' : 'u',
|
||||||
|
instr.operands[1].storage_index, instr.attributes.offset);
|
||||||
|
} else {
|
||||||
|
EmitSource(" = vf%u_%d;\n", instr.operands[1].storage_index,
|
||||||
|
instr.attributes.offset);
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
assert_always();
|
assert_always();
|
||||||
break;
|
break;
|
||||||
|
@ -834,7 +883,7 @@ void GlslShaderTranslator::EmitStoreResult(const InstructionResult& result,
|
||||||
EmitSourceDepth("gl_FragDepth");
|
EmitSourceDepth("gl_FragDepth");
|
||||||
break;
|
break;
|
||||||
case InstructionStorageTarget::kNone:
|
case InstructionStorageTarget::kNone:
|
||||||
break;
|
return;
|
||||||
}
|
}
|
||||||
if (uses_storage_index) {
|
if (uses_storage_index) {
|
||||||
switch (result.storage_addressing_mode) {
|
switch (result.storage_addressing_mode) {
|
||||||
|
|
Loading…
Reference in New Issue