Merge pull request #2695 from ReinUsesLisp/layer-viewport

gl_shader_decompiler: Implement gl_ViewportIndex and gl_Layer in vertex shaders
This commit is contained in:
Fernando Sahmkow 2019-07-15 16:28:07 -04:00 committed by GitHub
commit 1bdb59fc6e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 137 additions and 40 deletions

View file

@ -27,6 +27,7 @@ Device::Device() {
shader_storage_alignment = GetInteger<std::size_t>(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT);
max_vertex_attributes = GetInteger<u32>(GL_MAX_VERTEX_ATTRIBS);
max_varyings = GetInteger<u32>(GL_MAX_VARYING_VECTORS);
has_vertex_viewport_layer = GLAD_GL_ARB_shader_viewport_layer_array;
has_variable_aoffi = TestVariableAoffi();
has_component_indexing_bug = TestComponentIndexingBug();
}
@ -35,6 +36,7 @@ Device::Device(std::nullptr_t) {
uniform_buffer_alignment = 0;
max_vertex_attributes = 16;
max_varyings = 15;
has_vertex_viewport_layer = true;
has_variable_aoffi = true;
has_component_indexing_bug = false;
}

View file

@ -30,6 +30,10 @@ public:
return max_varyings;
}
bool HasVertexViewportLayer() const {
return has_vertex_viewport_layer;
}
bool HasVariableAoffi() const {
return has_variable_aoffi;
}
@ -46,6 +50,7 @@ private:
std::size_t shader_storage_alignment{};
u32 max_vertex_attributes{};
u32 max_varyings{};
bool has_vertex_viewport_layer{};
bool has_variable_aoffi{};
bool has_component_indexing_bug{};
};

View file

@ -190,8 +190,11 @@ CachedProgram SpecializeShader(const std::string& code, const GLShader::ShaderEn
const auto texture_buffer_usage{variant.texture_buffer_usage};
std::string source = "#version 430 core\n"
"#extension GL_ARB_separate_shader_objects : enable\n\n";
source += fmt::format("#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
"#extension GL_ARB_separate_shader_objects : enable\n";
if (entries.shader_viewport_layer_array) {
source += "#extension GL_ARB_shader_viewport_layer_array : enable\n";
}
source += fmt::format("\n#define EMULATION_UBO_BINDING {}\n", base_bindings.cbuf++);
for (const auto& cbuf : entries.const_buffers) {
source +=

View file

@ -14,6 +14,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_device.h"
#include "video_core/renderer_opengl/gl_rasterizer.h"
@ -246,6 +247,8 @@ public:
usage.is_read, usage.is_written);
}
entries.clip_distances = ir.GetClipDistances();
entries.shader_viewport_layer_array =
stage == ShaderStage::Vertex && (ir.UsesLayer() || ir.UsesViewportIndex());
entries.shader_length = ir.GetLength();
return entries;
}
@ -282,22 +285,35 @@ private:
}
void DeclareVertexRedeclarations() {
bool clip_distances_declared = false;
code.AddLine("out gl_PerVertex {{");
++code.scope;
code.AddLine("vec4 gl_Position;");
for (const auto o : ir.GetOutputAttributes()) {
if (o == Attribute::Index::PointSize)
code.AddLine("float gl_PointSize;");
if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 ||
o == Attribute::Index::ClipDistances4567)) {
for (const auto attribute : ir.GetOutputAttributes()) {
if (attribute == Attribute::Index::ClipDistances0123 ||
attribute == Attribute::Index::ClipDistances4567) {
code.AddLine("float gl_ClipDistance[];");
clip_distances_declared = true;
break;
}
}
if (stage != ShaderStage::Vertex || device.HasVertexViewportLayer()) {
if (ir.UsesLayer()) {
code.AddLine("int gl_Layer;");
}
if (ir.UsesViewportIndex()) {
code.AddLine("int gl_ViewportIndex;");
}
} else if ((ir.UsesLayer() || ir.UsesViewportIndex()) && stage == ShaderStage::Vertex &&
!device.HasVertexViewportLayer()) {
LOG_ERROR(
Render_OpenGL,
"GL_ARB_shader_viewport_layer_array is not available and its required by a shader");
}
if (ir.UsesPointSize()) {
code.AddLine("float gl_PointSize;");
}
--code.scope;
code.AddLine("}};");
@ -805,6 +821,45 @@ private:
return CastOperand(VisitOperand(operation, operand_index), type);
}
std::optional<std::pair<std::string, bool>> GetOutputAttribute(const AbufNode* abuf) {
switch (const auto attribute = abuf->GetIndex()) {
case Attribute::Index::Position:
return std::make_pair("gl_Position"s + GetSwizzle(abuf->GetElement()), false);
case Attribute::Index::LayerViewportPointSize:
switch (abuf->GetElement()) {
case 0:
UNIMPLEMENTED();
return {};
case 1:
if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) {
return {};
}
return std::make_pair("gl_Layer", true);
case 2:
if (stage == ShaderStage::Vertex && !device.HasVertexViewportLayer()) {
return {};
}
return std::make_pair("gl_ViewportIndex", true);
case 3:
UNIMPLEMENTED_MSG("Requires some state changes for gl_PointSize to work in shader");
return std::make_pair("gl_PointSize", false);
}
return {};
case Attribute::Index::ClipDistances0123:
return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement()), false);
case Attribute::Index::ClipDistances4567:
return std::make_pair(fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4),
false);
default:
if (IsGenericAttribute(attribute)) {
return std::make_pair(
GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement()), false);
}
UNIMPLEMENTED_MSG("Unhandled output attribute: {}", static_cast<u32>(attribute));
return {};
}
}
std::string CastOperand(const std::string& value, Type type) const {
switch (type) {
case Type::Bool:
@ -1001,6 +1056,8 @@ private:
const Node& src = operation[1];
std::string target;
bool is_integer = false;
if (const auto gpr = std::get_if<GprNode>(&*dest)) {
if (gpr->GetIndex() == Register::ZeroIndex) {
// Writing to Register::ZeroIndex is a no op
@ -1009,26 +1066,12 @@ private:
target = GetRegister(gpr->GetIndex());
} else if (const auto abuf = std::get_if<AbufNode>(&*dest)) {
UNIMPLEMENTED_IF(abuf->IsPhysicalBuffer());
target = [&]() -> std::string {
switch (const auto attribute = abuf->GetIndex(); abuf->GetIndex()) {
case Attribute::Index::Position:
return "gl_Position"s + GetSwizzle(abuf->GetElement());
case Attribute::Index::PointSize:
return "gl_PointSize";
case Attribute::Index::ClipDistances0123:
return fmt::format("gl_ClipDistance[{}]", abuf->GetElement());
case Attribute::Index::ClipDistances4567:
return fmt::format("gl_ClipDistance[{}]", abuf->GetElement() + 4);
default:
if (IsGenericAttribute(attribute)) {
return GetOutputAttribute(attribute) + GetSwizzle(abuf->GetElement());
}
UNIMPLEMENTED_MSG("Unhandled output attribute: {}",
static_cast<u32>(attribute));
return "0";
}
}();
const auto result = GetOutputAttribute(abuf);
if (!result) {
return {};
}
target = result->first;
is_integer = result->second;
} else if (const auto lmem = std::get_if<LmemNode>(&*dest)) {
target = fmt::format("{}[ftou({}) / 4]", GetLocalMemory(), Visit(lmem->GetAddress()));
} else if (const auto gmem = std::get_if<GmemNode>(&*dest)) {
@ -1040,7 +1083,11 @@ private:
UNREACHABLE_MSG("Assign called without a proper target");
}
code.AddLine("{} = {};", target, Visit(src));
if (is_integer) {
code.AddLine("{} = ftoi({});", target, Visit(src));
} else {
code.AddLine("{} = {};", target, Visit(src));
}
return {};
}

View file

@ -78,6 +78,7 @@ struct ShaderEntries {
std::vector<ImageEntry> images;
std::vector<GlobalMemoryEntry> global_memory_entries;
std::array<bool, Maxwell::NumClipDistances> clip_distances{};
bool shader_viewport_layer_array{};
std::size_t shader_length{};
};

View file

@ -373,6 +373,12 @@ std::optional<ShaderDiskCacheDecompiled> ShaderDiskCacheOpenGL::LoadDecompiledEn
}
}
bool shader_viewport_layer_array{};
if (!LoadObjectFromPrecompiled(shader_viewport_layer_array)) {
return {};
}
entry.entries.shader_viewport_layer_array = shader_viewport_layer_array;
u64 shader_length{};
if (!LoadObjectFromPrecompiled(shader_length)) {
return {};
@ -445,6 +451,10 @@ bool ShaderDiskCacheOpenGL::SaveDecompiledFile(u64 unique_identifier, const std:
}
}
if (!SaveObjectToPrecompiled(entries.shader_viewport_layer_array)) {
return false;
}
if (!SaveObjectToPrecompiled(static_cast<u64>(entries.shader_length))) {
return false;
}