Fix shaders reading 10_11_11 bitfields backwards.

This commit is contained in:
Dr. Chat 2016-01-18 15:35:02 -06:00
parent 2e5c64fb13
commit 55a8964428
3 changed files with 206 additions and 88 deletions

View File

@ -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

View File

@ -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

View File

@ -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) {