glsl: textures wip
This commit is contained in:
		| @@ -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
	
	Block a user