glsl: textures wip
This commit is contained in:
parent
3d086e6130
commit
d171083d53
|
@ -8,9 +8,21 @@
|
|||
#include "shader_recompiler/profile.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
std::string_view InterpDecorator(Interpolation interp) {
|
||||
switch (interp) {
|
||||
case Interpolation::Smooth:
|
||||
return "";
|
||||
case Interpolation::Flat:
|
||||
return "flat";
|
||||
case Interpolation::NoPerspective:
|
||||
return "noperspective";
|
||||
}
|
||||
throw InvalidArgument("Invalid interpolation {}", interp);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindings,
|
||||
const Profile& profile_)
|
||||
EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile& profile_)
|
||||
: info{program.info}, profile{profile_} {
|
||||
std::string header = "#version 450\n";
|
||||
SetupExtensions(header);
|
||||
|
@ -49,7 +61,8 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
|
|||
for (size_t index = 0; index < info.input_generics.size(); ++index) {
|
||||
const auto& generic{info.input_generics[index]};
|
||||
if (generic.used) {
|
||||
Add("layout(location={})in vec4 in_attr{};", index, index);
|
||||
Add("layout(location={}) {} in vec4 in_attr{};", index,
|
||||
InterpDecorator(generic.interpolation), index);
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < info.stores_frag_color.size(); ++index) {
|
||||
|
@ -66,6 +79,7 @@ EmitContext::EmitContext(IR::Program& program, [[maybe_unused]] Bindings& bindin
|
|||
DefineConstantBuffers();
|
||||
DefineStorageBuffers();
|
||||
DefineHelperFunctions();
|
||||
SetupImages(bindings);
|
||||
Add("void main(){{");
|
||||
|
||||
if (stage == Stage::VertexA || stage == Stage::VertexB) {
|
||||
|
@ -102,7 +116,7 @@ void EmitContext::DefineConstantBuffers() {
|
|||
}
|
||||
u32 binding{};
|
||||
for (const auto& desc : info.constant_buffer_descriptors) {
|
||||
Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, binding,
|
||||
Add("layout(std140,binding={}) uniform cbuf_{}{{vec4 cbuf{}[{}];}};", binding, desc.index,
|
||||
desc.index, 4 * 1024);
|
||||
++binding;
|
||||
}
|
||||
|
@ -164,4 +178,36 @@ void EmitContext::DefineHelperFunctions() {
|
|||
}
|
||||
}
|
||||
|
||||
void EmitContext::SetupImages(Bindings& bindings) {
|
||||
image_buffer_bindings.reserve(info.image_buffer_descriptors.size());
|
||||
for (const auto& desc : info.image_buffer_descriptors) {
|
||||
throw NotImplementedException("image_buffer_descriptors");
|
||||
image_buffer_bindings.push_back(bindings.image);
|
||||
bindings.image += desc.count;
|
||||
}
|
||||
image_bindings.reserve(info.image_descriptors.size());
|
||||
for (const auto& desc : info.image_descriptors) {
|
||||
throw NotImplementedException("image_bindings");
|
||||
|
||||
image_bindings.push_back(bindings.image);
|
||||
bindings.image += desc.count;
|
||||
}
|
||||
texture_buffer_bindings.reserve(info.texture_buffer_descriptors.size());
|
||||
for (const auto& desc : info.texture_buffer_descriptors) {
|
||||
throw NotImplementedException("TextureType::Buffer");
|
||||
|
||||
texture_buffer_bindings.push_back(bindings.texture);
|
||||
bindings.texture += desc.count;
|
||||
}
|
||||
texture_bindings.reserve(info.texture_descriptors.size());
|
||||
for (const auto& desc : info.texture_descriptors) {
|
||||
texture_bindings.push_back(bindings.texture);
|
||||
const auto indices{bindings.texture + desc.count};
|
||||
for (u32 index = bindings.texture; index < indices; ++index) {
|
||||
Add("layout(binding={}) uniform sampler2D tex{};", bindings.texture, index);
|
||||
}
|
||||
bindings.texture += desc.count;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Shader::Backend::GLSL
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "shader_recompiler/backend/glsl/reg_alloc.h"
|
||||
|
@ -109,11 +111,17 @@ public:
|
|||
std::string_view stage_name = "invalid";
|
||||
std::string_view attrib_name = "invalid";
|
||||
|
||||
std::vector<u32> texture_buffer_bindings;
|
||||
std::vector<u32> image_buffer_bindings;
|
||||
std::vector<u32> texture_bindings;
|
||||
std::vector<u32> image_bindings;
|
||||
|
||||
private:
|
||||
void SetupExtensions(std::string& header);
|
||||
void DefineConstantBuffers();
|
||||
void DefineStorageBuffers();
|
||||
void DefineHelperFunctions();
|
||||
void SetupImages(Bindings& bindings);
|
||||
};
|
||||
|
||||
} // namespace Shader::Backend::GLSL
|
||||
|
|
|
@ -113,7 +113,7 @@ void PrecolorInst(IR::Inst& phi) {
|
|||
if (arg.IsImmediate()) {
|
||||
ir.PhiMove(phi, arg);
|
||||
} else {
|
||||
ir.PhiMove(phi, IR::Value{&RegAlloc::AliasInst(*arg.Inst())});
|
||||
ir.PhiMove(phi, IR::Value{&*arg.InstRecursive()});
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < num_args; ++i) {
|
||||
|
@ -157,7 +157,7 @@ void EmitCode(EmitContext& ctx, const IR::Program& program) {
|
|||
break;
|
||||
case IR::AbstractSyntaxNode::Type::Return:
|
||||
case IR::AbstractSyntaxNode::Type::Unreachable:
|
||||
ctx.Add("return;\n}}");
|
||||
ctx.Add("return;");
|
||||
break;
|
||||
case IR::AbstractSyntaxNode::Type::Loop:
|
||||
case IR::AbstractSyntaxNode::Type::Repeat:
|
||||
|
@ -175,6 +175,8 @@ std::string EmitGLSL(const Profile& profile, const RuntimeInfo&, IR::Program& pr
|
|||
EmitContext ctx{program, bindings, profile};
|
||||
Precolor(program);
|
||||
EmitCode(ctx, program);
|
||||
ctx.code += "}";
|
||||
fmt::print("\n{}\n", ctx.code);
|
||||
return ctx.code;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ static void Alias(IR::Inst& inst, const IR::Value& value) {
|
|||
if (value.IsImmediate()) {
|
||||
return;
|
||||
}
|
||||
IR::Inst& value_inst{RegAlloc::AliasInst(*value.Inst())};
|
||||
IR::Inst& value_inst{*value.InstRecursive()};
|
||||
value_inst.DestructiveAddUsage(inst.UseCount());
|
||||
value_inst.DestructiveRemoveUsage();
|
||||
inst.SetDefinition(value_inst.Definition<Id>());
|
||||
|
|
|
@ -6,17 +6,39 @@
|
|||
|
||||
#include "shader_recompiler/backend/glsl/emit_context.h"
|
||||
#include "shader_recompiler/backend/glsl/emit_glsl_instructions.h"
|
||||
#include "shader_recompiler/frontend/ir/modifiers.h"
|
||||
#include "shader_recompiler/frontend/ir/value.h"
|
||||
#include "shader_recompiler/profile.h"
|
||||
|
||||
namespace Shader::Backend::GLSL {
|
||||
namespace {
|
||||
std::string Texture(EmitContext& ctx, IR::TextureInstInfo info,
|
||||
[[maybe_unused]] const IR::Value& index) {
|
||||
if (info.type == TextureType::Buffer) {
|
||||
throw NotImplementedException("TextureType::Buffer");
|
||||
} else {
|
||||
return fmt::format("tex{}", ctx.texture_bindings.at(info.descriptor_index));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void EmitImageSampleImplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
[[maybe_unused]] const IR::Value& index,
|
||||
[[maybe_unused]] std::string_view coords,
|
||||
[[maybe_unused]] std::string_view bias_lc,
|
||||
[[maybe_unused]] const IR::Value& offset) {
|
||||
throw NotImplementedException("GLSL Instruction");
|
||||
const auto info{inst.Flags<IR::TextureInstInfo>()};
|
||||
if (info.has_bias) {
|
||||
throw NotImplementedException("Bias texture samples");
|
||||
}
|
||||
if (info.has_lod_clamp) {
|
||||
throw NotImplementedException("Lod clamp samples");
|
||||
}
|
||||
if (!offset.IsEmpty()) {
|
||||
throw NotImplementedException("Offset");
|
||||
}
|
||||
const auto texture{Texture(ctx, info, index)};
|
||||
ctx.AddF32x4("{}=texture({},{});", inst, texture, coords);
|
||||
}
|
||||
|
||||
void EmitImageSampleExplicitLod([[maybe_unused]] EmitContext& ctx, [[maybe_unused]] IR::Inst& inst,
|
||||
|
|
|
@ -89,11 +89,11 @@ void EmitIsHelperInvocation(EmitContext& ctx);
|
|||
void EmitYDirection(EmitContext& ctx);
|
||||
void EmitLoadLocal(EmitContext& ctx, std::string_view word_offset);
|
||||
void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_view value);
|
||||
void EmitUndefU1(EmitContext& ctx);
|
||||
void EmitUndefU8(EmitContext& ctx);
|
||||
void EmitUndefU16(EmitContext& ctx);
|
||||
void EmitUndefU32(EmitContext& ctx);
|
||||
void EmitUndefU64(EmitContext& ctx);
|
||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst);
|
||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst);
|
||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst);
|
||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst);
|
||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst);
|
||||
void EmitLoadGlobalU8(EmitContext& ctx);
|
||||
void EmitLoadGlobalS8(EmitContext& ctx);
|
||||
void EmitLoadGlobalU16(EmitContext& ctx);
|
||||
|
|
|
@ -39,17 +39,26 @@ void EmitReference(EmitContext&) {
|
|||
}
|
||||
|
||||
void EmitPhiMove(EmitContext& ctx, const IR::Value& phi_value, const IR::Value& value) {
|
||||
IR::Inst& phi{RegAlloc::AliasInst(*phi_value.Inst())};
|
||||
IR::Inst& phi{*phi_value.InstRecursive()};
|
||||
const auto phi_type{phi.Arg(0).Type()};
|
||||
if (!phi.Definition<Id>().is_valid) {
|
||||
// The phi node wasn't forward defined
|
||||
ctx.Add("{};", ctx.reg_alloc.Define(phi, phi.Arg(0).Type()));
|
||||
ctx.Add("{};", ctx.reg_alloc.Define(phi, phi_type));
|
||||
}
|
||||
const auto phi_reg{ctx.reg_alloc.Consume(IR::Value{&phi})};
|
||||
const auto val_reg{ctx.reg_alloc.Consume(value)};
|
||||
if (phi_reg == val_reg) {
|
||||
return;
|
||||
}
|
||||
ctx.Add("{}={};", phi_reg, val_reg);
|
||||
if (phi_type == value.Type()) {
|
||||
ctx.Add("{}={}; // PHI MOVE", phi_reg, val_reg);
|
||||
} else if (phi_type == IR::Type::U32 && value.Type() == IR::Type::F32) {
|
||||
ctx.Add("{}=floatBitsToUint({}); // CAST PHI MOVE", phi_reg, val_reg);
|
||||
} else {
|
||||
throw NotImplementedException("{} to {} move", phi_type, value.Type());
|
||||
const auto cast{ctx.reg_alloc.GetGlslType(phi_type)};
|
||||
ctx.Add("{}={}({}); // CAST PHI MOVE", phi_reg, cast, val_reg);
|
||||
}
|
||||
}
|
||||
|
||||
void EmitBranch(EmitContext& ctx, std::string_view label) {
|
||||
|
@ -235,23 +244,23 @@ void EmitWriteLocal(EmitContext& ctx, std::string_view word_offset, std::string_
|
|||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitUndefU1(EmitContext& ctx) {
|
||||
void EmitUndefU1(EmitContext& ctx, IR::Inst& inst) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitUndefU8(EmitContext& ctx) {
|
||||
void EmitUndefU8(EmitContext& ctx, IR::Inst& inst) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitUndefU16(EmitContext& ctx) {
|
||||
void EmitUndefU16(EmitContext& ctx, IR::Inst& inst) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
void EmitUndefU32(EmitContext& ctx) {
|
||||
NotImplemented();
|
||||
void EmitUndefU32(EmitContext& ctx, IR::Inst& inst) {
|
||||
ctx.AddU32("{}=0u;", inst);
|
||||
}
|
||||
|
||||
void EmitUndefU64(EmitContext& ctx) {
|
||||
void EmitUndefU64(EmitContext& ctx, IR::Inst& inst) {
|
||||
NotImplemented();
|
||||
}
|
||||
|
||||
|
|
|
@ -71,26 +71,17 @@ std::string RegAlloc::Define(IR::Inst& inst) {
|
|||
|
||||
std::string RegAlloc::Define(IR::Inst& inst, Type type) {
|
||||
const Id id{Alloc()};
|
||||
const auto type_str{GetType(type, id.index)};
|
||||
std::string type_str = "";
|
||||
if (!register_defined[id.index]) {
|
||||
register_defined[id.index] = true;
|
||||
type_str = GetGlslType(type);
|
||||
}
|
||||
inst.SetDefinition<Id>(id);
|
||||
return type_str + Representation(id);
|
||||
}
|
||||
|
||||
std::string RegAlloc::Define(IR::Inst& inst, IR::Type type) {
|
||||
switch (type) {
|
||||
case IR::Type::U1:
|
||||
return Define(inst, Type::U1);
|
||||
case IR::Type::U32:
|
||||
return Define(inst, Type::U32);
|
||||
case IR::Type::F32:
|
||||
return Define(inst, Type::F32);
|
||||
case IR::Type::U64:
|
||||
return Define(inst, Type::U64);
|
||||
case IR::Type::F64:
|
||||
return Define(inst, Type::F64);
|
||||
default:
|
||||
throw NotImplementedException("IR type {}", type);
|
||||
}
|
||||
return Define(inst, RegType(type));
|
||||
}
|
||||
|
||||
std::string RegAlloc::Consume(const IR::Value& value) {
|
||||
|
@ -107,11 +98,24 @@ std::string RegAlloc::Consume(IR::Inst& inst) {
|
|||
return Representation(inst.Definition<Id>());
|
||||
}
|
||||
|
||||
std::string RegAlloc::GetType(Type type, u32 index) {
|
||||
if (register_defined[index]) {
|
||||
return "";
|
||||
Type RegAlloc::RegType(IR::Type type) {
|
||||
switch (type) {
|
||||
case IR::Type::U1:
|
||||
return Type::U1;
|
||||
case IR::Type::U32:
|
||||
return Type::U32;
|
||||
case IR::Type::F32:
|
||||
return Type::F32;
|
||||
case IR::Type::U64:
|
||||
return Type::U64;
|
||||
case IR::Type::F64:
|
||||
return Type::F64;
|
||||
default:
|
||||
throw NotImplementedException("IR type {}", type);
|
||||
}
|
||||
register_defined[index] = true;
|
||||
}
|
||||
|
||||
std::string RegAlloc::GetGlslType(Type type) {
|
||||
switch (type) {
|
||||
case Type::U1:
|
||||
return "bool ";
|
||||
|
@ -144,6 +148,10 @@ std::string RegAlloc::GetType(Type type, u32 index) {
|
|||
}
|
||||
}
|
||||
|
||||
std::string RegAlloc::GetGlslType(IR::Type type) {
|
||||
return GetGlslType(RegType(type));
|
||||
}
|
||||
|
||||
Id RegAlloc::Alloc() {
|
||||
if (num_used_registers < NUM_REGS) {
|
||||
for (size_t reg = 0; reg < NUM_REGS; ++reg) {
|
||||
|
@ -170,30 +178,4 @@ void RegAlloc::Free(Id id) {
|
|||
register_use[id.index] = false;
|
||||
}
|
||||
|
||||
/*static*/ bool RegAlloc::IsAliased(const IR::Inst& inst) {
|
||||
switch (inst.GetOpcode()) {
|
||||
case IR::Opcode::Identity:
|
||||
case IR::Opcode::BitCastU16F16:
|
||||
case IR::Opcode::BitCastU32F32:
|
||||
case IR::Opcode::BitCastU64F64:
|
||||
case IR::Opcode::BitCastF16U16:
|
||||
case IR::Opcode::BitCastF32U32:
|
||||
case IR::Opcode::BitCastF64U64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*static*/ IR::Inst& RegAlloc::AliasInst(IR::Inst& inst) {
|
||||
IR::Inst* it{&inst};
|
||||
while (IsAliased(*it)) {
|
||||
const IR::Value arg{it->Arg(0)};
|
||||
if (arg.IsImmediate()) {
|
||||
break;
|
||||
}
|
||||
it = arg.InstRecursive();
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
} // namespace Shader::Backend::GLSL
|
||||
|
|
|
@ -59,20 +59,15 @@ public:
|
|||
std::string Define(IR::Inst& inst, IR::Type type);
|
||||
|
||||
std::string Consume(const IR::Value& value);
|
||||
|
||||
/// Returns true if the instruction is expected to be aliased to another
|
||||
static bool IsAliased(const IR::Inst& inst);
|
||||
|
||||
/// Returns the underlying value out of an alias sequence
|
||||
static IR::Inst& AliasInst(IR::Inst& inst);
|
||||
std::string GetGlslType(Type type);
|
||||
std::string GetGlslType(IR::Type type);
|
||||
|
||||
private:
|
||||
static constexpr size_t NUM_REGS = 4096;
|
||||
static constexpr size_t NUM_ELEMENTS = 4;
|
||||
|
||||
std::string Consume(IR::Inst& inst);
|
||||
std::string GetType(Type type, u32 index);
|
||||
|
||||
Type RegType(IR::Type type);
|
||||
Id Alloc();
|
||||
void Free(Id id);
|
||||
|
||||
|
|
Reference in New Issue