14 changed files with 482 additions and 353 deletions
-
4src/shader_recompiler/CMakeLists.txt
-
36src/shader_recompiler/backend/glsl/emit_context.h
-
29src/shader_recompiler/backend/glsl/emit_glsl.cpp
-
11src/shader_recompiler/backend/glsl/emit_glsl_atomic.cpp
-
2src/shader_recompiler/backend/glsl/emit_glsl_bitwise_conversion.cpp
-
14src/shader_recompiler/backend/glsl/emit_glsl_context_get_set.cpp
-
26src/shader_recompiler/backend/glsl/emit_glsl_image.cpp
-
10src/shader_recompiler/backend/glsl/emit_glsl_integer.cpp
-
28src/shader_recompiler/backend/glsl/emit_glsl_memory.cpp
-
10src/shader_recompiler/backend/glsl/emit_glsl_not_implemented.cpp
-
191src/shader_recompiler/backend/glsl/reg_alloc.cpp
-
84src/shader_recompiler/backend/glsl/reg_alloc.h
-
290src/shader_recompiler/backend/glsl/var_alloc.cpp
-
100src/shader_recompiler/backend/glsl/var_alloc.h
@ -1,191 +0,0 @@ |
|||
// Copyright 2021 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <string>
|
|||
#include <string_view>
|
|||
|
|||
#include <fmt/format.h>
|
|||
|
|||
#include "shader_recompiler/backend/glsl/reg_alloc.h"
|
|||
#include "shader_recompiler/exception.h"
|
|||
#include "shader_recompiler/frontend/ir/value.h"
|
|||
|
|||
namespace Shader::Backend::GLSL { |
|||
namespace { |
|||
std::string Representation(Id id) { |
|||
if (id.is_condition_code != 0) { |
|||
throw NotImplementedException("Condition code"); |
|||
} |
|||
if (id.is_spill != 0) { |
|||
throw NotImplementedException("Spilling"); |
|||
} |
|||
const u32 index{static_cast<u32>(id.index)}; |
|||
return fmt::format("R{}", index); |
|||
} |
|||
|
|||
std::string FormatFloat(std::string_view value, IR::Type type) { |
|||
// TODO: Confirm FP64 nan/inf
|
|||
if (type == IR::Type::F32) { |
|||
if (value == "nan") { |
|||
return "uintBitsToFloat(0x7fc00000)"; |
|||
} |
|||
if (value == "inf") { |
|||
return "uintBitsToFloat(0x7f800000)"; |
|||
} |
|||
if (value == "-inf") { |
|||
return "uintBitsToFloat(0xff800000)"; |
|||
} |
|||
} |
|||
if (value.find_first_of('e') != std::string_view::npos) { |
|||
// scientific notation
|
|||
const auto cast{type == IR::Type::F32 ? "float" : "double"}; |
|||
return fmt::format("{}({})", cast, value); |
|||
} |
|||
const bool needs_dot{value.find_first_of('.') == std::string_view::npos}; |
|||
const bool needs_suffix{!value.ends_with('f')}; |
|||
const auto suffix{type == IR::Type::F32 ? "f" : "lf"}; |
|||
return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : ""); |
|||
} |
|||
|
|||
std::string MakeImm(const IR::Value& value) { |
|||
switch (value.Type()) { |
|||
case IR::Type::U1: |
|||
return fmt::format("{}", value.U1() ? "true" : "false"); |
|||
case IR::Type::U32: |
|||
return fmt::format("{}u", value.U32()); |
|||
case IR::Type::F32: |
|||
return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32); |
|||
case IR::Type::U64: |
|||
return fmt::format("{}ul", value.U64()); |
|||
case IR::Type::F64: |
|||
return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64); |
|||
case IR::Type::Void: |
|||
return ""; |
|||
default: |
|||
throw NotImplementedException("Immediate type {}", value.Type()); |
|||
} |
|||
} |
|||
} // Anonymous namespace
|
|||
|
|||
std::string RegAlloc::Define(IR::Inst& inst) { |
|||
const Id id{Alloc()}; |
|||
inst.SetDefinition<Id>(id); |
|||
return Representation(id); |
|||
} |
|||
|
|||
std::string RegAlloc::Define(IR::Inst& inst, Type type) { |
|||
const Id id{Alloc()}; |
|||
std::string type_str = ""; |
|||
if (!register_defined[id.index]) { |
|||
register_defined[id.index] = true; |
|||
// type_str = GetGlslType(type);
|
|||
reg_types.push_back(GetGlslType(type)); |
|||
++num_used_registers; |
|||
} |
|||
inst.SetDefinition<Id>(id); |
|||
return type_str + Representation(id); |
|||
} |
|||
|
|||
std::string RegAlloc::Define(IR::Inst& inst, IR::Type type) { |
|||
return Define(inst, RegType(type)); |
|||
} |
|||
|
|||
std::string RegAlloc::Consume(const IR::Value& value) { |
|||
return value.IsImmediate() ? MakeImm(value) : Consume(*value.InstRecursive()); |
|||
} |
|||
|
|||
std::string RegAlloc::Consume(IR::Inst& inst) { |
|||
inst.DestructiveRemoveUsage(); |
|||
// TODO: reuse variables of same type if possible
|
|||
// if (!inst.HasUses()) {
|
|||
// Free(id);
|
|||
// }
|
|||
return Representation(inst.Definition<Id>()); |
|||
} |
|||
|
|||
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); |
|||
} |
|||
} |
|||
|
|||
std::string RegAlloc::GetGlslType(Type type) { |
|||
switch (type) { |
|||
case Type::U1: |
|||
return "bool "; |
|||
case Type::F16x2: |
|||
return "f16vec2 "; |
|||
case Type::U32: |
|||
return "uint "; |
|||
case Type::S32: |
|||
return "int "; |
|||
case Type::F32: |
|||
return "float "; |
|||
case Type::S64: |
|||
return "int64_t "; |
|||
case Type::U64: |
|||
return "uint64_t "; |
|||
case Type::F64: |
|||
return "double "; |
|||
case Type::U32x2: |
|||
return "uvec2 "; |
|||
case Type::F32x2: |
|||
return "vec2 "; |
|||
case Type::U32x3: |
|||
return "uvec3 "; |
|||
case Type::F32x3: |
|||
return "vec3 "; |
|||
case Type::U32x4: |
|||
return "uvec4 "; |
|||
case Type::F32x4: |
|||
return "vec4 "; |
|||
case Type::Void: |
|||
return ""; |
|||
default: |
|||
throw NotImplementedException("Type {}", type); |
|||
} |
|||
} |
|||
|
|||
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) { |
|||
if (register_use[reg]) { |
|||
continue; |
|||
} |
|||
register_use[reg] = true; |
|||
Id ret{}; |
|||
ret.is_valid.Assign(1); |
|||
ret.is_long.Assign(0); |
|||
ret.is_spill.Assign(0); |
|||
ret.is_condition_code.Assign(0); |
|||
ret.index.Assign(static_cast<u32>(reg)); |
|||
return ret; |
|||
} |
|||
} |
|||
throw NotImplementedException("Register spilling"); |
|||
} |
|||
|
|||
void RegAlloc::Free(Id id) { |
|||
if (id.is_spill != 0) { |
|||
throw NotImplementedException("Free spill"); |
|||
} |
|||
register_use[id.index] = false; |
|||
} |
|||
|
|||
} // namespace Shader::Backend::GLSL
|
|||
@ -1,84 +0,0 @@ |
|||
// Copyright 2021 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <bitset> |
|||
#include <vector> |
|||
|
|||
#include "common/bit_field.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Shader::IR { |
|||
class Inst; |
|||
class Value; |
|||
enum class Type; |
|||
} // namespace Shader::IR |
|||
|
|||
namespace Shader::Backend::GLSL { |
|||
enum class Type : u32 { |
|||
U1, |
|||
F16x2, |
|||
S32, |
|||
U32, |
|||
F32, |
|||
S64, |
|||
U64, |
|||
F64, |
|||
U32x2, |
|||
F32x2, |
|||
U32x3, |
|||
F32x3, |
|||
U32x4, |
|||
F32x4, |
|||
Void, |
|||
}; |
|||
|
|||
struct Id { |
|||
union { |
|||
u32 raw; |
|||
BitField<0, 1, u32> is_valid; |
|||
BitField<1, 1, u32> is_long; |
|||
BitField<2, 1, u32> is_spill; |
|||
BitField<3, 1, u32> is_condition_code; |
|||
BitField<4, 1, u32> is_null; |
|||
BitField<5, 27, u32> index; |
|||
}; |
|||
|
|||
bool operator==(Id rhs) const noexcept { |
|||
return raw == rhs.raw; |
|||
} |
|||
bool operator!=(Id rhs) const noexcept { |
|||
return !operator==(rhs); |
|||
} |
|||
}; |
|||
static_assert(sizeof(Id) == sizeof(u32)); |
|||
|
|||
class RegAlloc { |
|||
public: |
|||
std::string Define(IR::Inst& inst); |
|||
std::string Define(IR::Inst& inst, Type type); |
|||
std::string Define(IR::Inst& inst, IR::Type type); |
|||
|
|||
std::string Consume(const IR::Value& value); |
|||
std::string Consume(IR::Inst& inst); |
|||
|
|||
std::string GetGlslType(Type type); |
|||
std::string GetGlslType(IR::Type type); |
|||
|
|||
size_t num_used_registers{}; |
|||
std::vector<std::string> reg_types; |
|||
|
|||
private: |
|||
static constexpr size_t NUM_REGS = 4096; |
|||
|
|||
Type RegType(IR::Type type); |
|||
Id Alloc(); |
|||
void Free(Id id); |
|||
|
|||
std::bitset<NUM_REGS> register_use{}; |
|||
std::bitset<NUM_REGS> register_defined{}; |
|||
}; |
|||
|
|||
} // namespace Shader::Backend::GLSL |
|||
@ -0,0 +1,290 @@ |
|||
// Copyright 2021 yuzu Emulator Project
|
|||
// Licensed under GPLv2 or any later version
|
|||
// Refer to the license.txt file included.
|
|||
|
|||
#include <string>
|
|||
#include <string_view>
|
|||
|
|||
#include <fmt/format.h>
|
|||
|
|||
#include "shader_recompiler/backend/glsl/var_alloc.h"
|
|||
#include "shader_recompiler/exception.h"
|
|||
#include "shader_recompiler/frontend/ir/value.h"
|
|||
|
|||
namespace Shader::Backend::GLSL { |
|||
namespace { |
|||
std::string TypePrefix(GlslVarType type) { |
|||
switch (type) { |
|||
case GlslVarType::U1: |
|||
return "b_"; |
|||
case GlslVarType::F16x2: |
|||
return "f16x2_"; |
|||
case GlslVarType::U32: |
|||
return "u_"; |
|||
case GlslVarType::S32: |
|||
return "s_"; |
|||
case GlslVarType::F32: |
|||
return "f_"; |
|||
case GlslVarType::S64: |
|||
return "s64_"; |
|||
case GlslVarType::U64: |
|||
return "u64_"; |
|||
case GlslVarType::F64: |
|||
return "d_"; |
|||
case GlslVarType::U32x2: |
|||
return "u2_"; |
|||
case GlslVarType::F32x2: |
|||
return "f2_"; |
|||
case GlslVarType::U32x3: |
|||
return "u3_"; |
|||
case GlslVarType::F32x3: |
|||
return "f3_"; |
|||
case GlslVarType::U32x4: |
|||
return "u4_"; |
|||
case GlslVarType::F32x4: |
|||
return "f4_"; |
|||
case GlslVarType::Void: |
|||
return ""; |
|||
default: |
|||
throw NotImplementedException("Type {}", type); |
|||
} |
|||
} |
|||
|
|||
std::string FormatFloat(std::string_view value, IR::Type type) { |
|||
// TODO: Confirm FP64 nan/inf
|
|||
if (type == IR::Type::F32) { |
|||
if (value == "nan") { |
|||
return "uintBitsToFloat(0x7fc00000)"; |
|||
} |
|||
if (value == "inf") { |
|||
return "uintBitsToFloat(0x7f800000)"; |
|||
} |
|||
if (value == "-inf") { |
|||
return "uintBitsToFloat(0xff800000)"; |
|||
} |
|||
} |
|||
if (value.find_first_of('e') != std::string_view::npos) { |
|||
// scientific notation
|
|||
const auto cast{type == IR::Type::F32 ? "float" : "double"}; |
|||
return fmt::format("{}({})", cast, value); |
|||
} |
|||
const bool needs_dot{value.find_first_of('.') == std::string_view::npos}; |
|||
const bool needs_suffix{!value.ends_with('f')}; |
|||
const auto suffix{type == IR::Type::F32 ? "f" : "lf"}; |
|||
return fmt::format("{}{}{}", value, needs_dot ? "." : "", needs_suffix ? suffix : ""); |
|||
} |
|||
|
|||
std::string MakeImm(const IR::Value& value) { |
|||
switch (value.Type()) { |
|||
case IR::Type::U1: |
|||
return fmt::format("{}", value.U1() ? "true" : "false"); |
|||
case IR::Type::U32: |
|||
return fmt::format("{}u", value.U32()); |
|||
case IR::Type::F32: |
|||
return FormatFloat(fmt::format("{}", value.F32()), IR::Type::F32); |
|||
case IR::Type::U64: |
|||
return fmt::format("{}ul", value.U64()); |
|||
case IR::Type::F64: |
|||
return FormatFloat(fmt::format("{}", value.F64()), IR::Type::F64); |
|||
case IR::Type::Void: |
|||
return ""; |
|||
default: |
|||
throw NotImplementedException("Immediate type {}", value.Type()); |
|||
} |
|||
} |
|||
} // Anonymous namespace
|
|||
|
|||
std::string VarAlloc::Representation(u32 index, GlslVarType type) const { |
|||
const auto prefix{TypePrefix(type)}; |
|||
return fmt::format("{}{}", prefix, index); |
|||
} |
|||
|
|||
std::string VarAlloc::Representation(Id id) const { |
|||
return Representation(id.index, id.type); |
|||
} |
|||
|
|||
std::string VarAlloc::Define(IR::Inst& inst, GlslVarType type) { |
|||
if (inst.HasUses()) { |
|||
inst.SetDefinition<Id>(Alloc(type)); |
|||
return Representation(inst.Definition<Id>()); |
|||
} else { |
|||
Id id{}; |
|||
id.type.Assign(type); |
|||
// id.is_null.Assign(1);
|
|||
GetUseTracker(type).uses_temp = true; |
|||
inst.SetDefinition<Id>(id); |
|||
} |
|||
return Representation(inst.Definition<Id>()); |
|||
} |
|||
|
|||
std::string VarAlloc::Define(IR::Inst& inst, IR::Type type) { |
|||
return Define(inst, RegType(type)); |
|||
} |
|||
|
|||
std::string VarAlloc::Consume(const IR::Value& value) { |
|||
return value.IsImmediate() ? MakeImm(value) : ConsumeInst(*value.InstRecursive()); |
|||
} |
|||
|
|||
std::string VarAlloc::ConsumeInst(IR::Inst& inst) { |
|||
inst.DestructiveRemoveUsage(); |
|||
if (!inst.HasUses()) { |
|||
Free(inst.Definition<Id>()); |
|||
} |
|||
return Representation(inst.Definition<Id>()); |
|||
} |
|||
|
|||
std::string VarAlloc::GetGlslType(IR::Type type) const { |
|||
return GetGlslType(RegType(type)); |
|||
} |
|||
|
|||
Id VarAlloc::Alloc(GlslVarType type) { |
|||
auto& use_tracker{GetUseTracker(type)}; |
|||
if (use_tracker.num_used < NUM_VARS) { |
|||
for (size_t var = 1; var < NUM_VARS; ++var) { |
|||
if (use_tracker.var_use[var]) { |
|||
continue; |
|||
} |
|||
use_tracker.num_used = std::max(use_tracker.num_used, var + 1); |
|||
use_tracker.var_use[var] = true; |
|||
Id ret{}; |
|||
ret.is_valid.Assign(1); |
|||
ret.type.Assign(type); |
|||
ret.index.Assign(static_cast<u32>(var)); |
|||
return ret; |
|||
} |
|||
} |
|||
throw NotImplementedException("Variable spilling"); |
|||
} |
|||
|
|||
void VarAlloc::Free(Id id) { |
|||
if (id.is_valid == 0) { |
|||
// throw LogicError("Freeing invalid variable");
|
|||
return; |
|||
} |
|||
auto& use_tracker{GetUseTracker(id.type)}; |
|||
use_tracker.var_use[id.index] = false; |
|||
} |
|||
|
|||
GlslVarType VarAlloc::RegType(IR::Type type) const { |
|||
switch (type) { |
|||
case IR::Type::U1: |
|||
return GlslVarType::U1; |
|||
case IR::Type::U32: |
|||
return GlslVarType::U32; |
|||
case IR::Type::F32: |
|||
return GlslVarType::F32; |
|||
case IR::Type::U64: |
|||
return GlslVarType::U64; |
|||
case IR::Type::F64: |
|||
return GlslVarType::F64; |
|||
default: |
|||
throw NotImplementedException("IR type {}", type); |
|||
} |
|||
} |
|||
|
|||
std::string VarAlloc::GetGlslType(GlslVarType type) const { |
|||
switch (type) { |
|||
case GlslVarType::U1: |
|||
return "bool "; |
|||
case GlslVarType::F16x2: |
|||
return "f16vec2 "; |
|||
case GlslVarType::U32: |
|||
return "uint "; |
|||
case GlslVarType::S32: |
|||
return "int "; |
|||
case GlslVarType::F32: |
|||
return "float "; |
|||
case GlslVarType::S64: |
|||
return "int64_t "; |
|||
case GlslVarType::U64: |
|||
return "uint64_t "; |
|||
case GlslVarType::F64: |
|||
return "double "; |
|||
case GlslVarType::U32x2: |
|||
return "uvec2 "; |
|||
case GlslVarType::F32x2: |
|||
return "vec2 "; |
|||
case GlslVarType::U32x3: |
|||
return "uvec3 "; |
|||
case GlslVarType::F32x3: |
|||
return "vec3 "; |
|||
case GlslVarType::U32x4: |
|||
return "uvec4 "; |
|||
case GlslVarType::F32x4: |
|||
return "vec4 "; |
|||
case GlslVarType::Void: |
|||
return ""; |
|||
default: |
|||
throw NotImplementedException("Type {}", type); |
|||
} |
|||
} |
|||
|
|||
VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) { |
|||
switch (type) { |
|||
case GlslVarType::U1: |
|||
return var_bool; |
|||
case GlslVarType::U32: |
|||
return var_u32; |
|||
case GlslVarType::S32: |
|||
return var_s32; |
|||
case GlslVarType::F32: |
|||
return var_f32; |
|||
case GlslVarType::S64: |
|||
return var_s64; |
|||
case GlslVarType::U64: |
|||
return var_u64; |
|||
case GlslVarType::F64: |
|||
return var_f64; |
|||
case GlslVarType::U32x2: |
|||
return var_u32x2; |
|||
case GlslVarType::F32x2: |
|||
return var_f32x2; |
|||
case GlslVarType::U32x3: |
|||
return var_u32x3; |
|||
case GlslVarType::F32x3: |
|||
return var_f32x3; |
|||
case GlslVarType::U32x4: |
|||
return var_u32x4; |
|||
case GlslVarType::F32x4: |
|||
return var_f32x4; |
|||
default: |
|||
throw NotImplementedException("Type {}", type); |
|||
} |
|||
} |
|||
|
|||
const VarAlloc::UseTracker& VarAlloc::GetUseTracker(GlslVarType type) const { |
|||
switch (type) { |
|||
case GlslVarType::U1: |
|||
return var_bool; |
|||
case GlslVarType::F16x2: |
|||
return var_f16x2; |
|||
case GlslVarType::U32: |
|||
return var_u32; |
|||
case GlslVarType::S32: |
|||
return var_s32; |
|||
case GlslVarType::F32: |
|||
return var_f32; |
|||
case GlslVarType::S64: |
|||
return var_s64; |
|||
case GlslVarType::U64: |
|||
return var_u64; |
|||
case GlslVarType::F64: |
|||
return var_f64; |
|||
case GlslVarType::U32x2: |
|||
return var_u32x2; |
|||
case GlslVarType::F32x2: |
|||
return var_f32x2; |
|||
case GlslVarType::U32x3: |
|||
return var_u32x3; |
|||
case GlslVarType::F32x3: |
|||
return var_f32x3; |
|||
case GlslVarType::U32x4: |
|||
return var_u32x4; |
|||
case GlslVarType::F32x4: |
|||
return var_f32x4; |
|||
default: |
|||
throw NotImplementedException("Type {}", type); |
|||
} |
|||
} |
|||
|
|||
} // namespace Shader::Backend::GLSL
|
|||
@ -0,0 +1,100 @@ |
|||
// Copyright 2021 yuzu Emulator Project |
|||
// Licensed under GPLv2 or any later version |
|||
// Refer to the license.txt file included. |
|||
|
|||
#pragma once |
|||
|
|||
#include <bitset> |
|||
#include <string> |
|||
#include <vector> |
|||
|
|||
#include "common/bit_field.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Shader::IR { |
|||
class Inst; |
|||
class Value; |
|||
enum class Type; |
|||
} // namespace Shader::IR |
|||
|
|||
namespace Shader::Backend::GLSL { |
|||
enum class GlslVarType : u32 { |
|||
U1, |
|||
F16x2, |
|||
S32, |
|||
U32, |
|||
F32, |
|||
S64, |
|||
U64, |
|||
F64, |
|||
U32x2, |
|||
F32x2, |
|||
U32x3, |
|||
F32x3, |
|||
U32x4, |
|||
F32x4, |
|||
Void, |
|||
}; |
|||
|
|||
struct Id { |
|||
union { |
|||
u32 raw; |
|||
BitField<0, 1, u32> is_valid; |
|||
BitField<1, 4, GlslVarType> type; |
|||
BitField<5, 27, u32> index; |
|||
}; |
|||
|
|||
bool operator==(Id rhs) const noexcept { |
|||
return raw == rhs.raw; |
|||
} |
|||
bool operator!=(Id rhs) const noexcept { |
|||
return !operator==(rhs); |
|||
} |
|||
}; |
|||
static_assert(sizeof(Id) == sizeof(u32)); |
|||
|
|||
class VarAlloc { |
|||
public: |
|||
static constexpr size_t NUM_VARS = 511; |
|||
struct UseTracker { |
|||
size_t num_used{}; |
|||
std::bitset<NUM_VARS> var_use{}; |
|||
bool uses_temp{}; |
|||
}; |
|||
|
|||
std::string Define(IR::Inst& inst, GlslVarType type); |
|||
std::string Define(IR::Inst& inst, IR::Type type); |
|||
|
|||
std::string Consume(const IR::Value& value); |
|||
std::string ConsumeInst(IR::Inst& inst); |
|||
|
|||
std::string GetGlslType(GlslVarType type) const; |
|||
std::string GetGlslType(IR::Type type) const; |
|||
|
|||
const UseTracker& GetUseTracker(GlslVarType type) const; |
|||
std::string Representation(u32 index, GlslVarType type) const; |
|||
|
|||
private: |
|||
GlslVarType RegType(IR::Type type) const; |
|||
Id Alloc(GlslVarType type); |
|||
void Free(Id id); |
|||
UseTracker& GetUseTracker(GlslVarType type); |
|||
std::string Representation(Id id) const; |
|||
|
|||
UseTracker var_bool{}; |
|||
UseTracker var_f16x2{}; |
|||
UseTracker var_s32{}; |
|||
UseTracker var_u32{}; |
|||
UseTracker var_u32x2{}; |
|||
UseTracker var_u32x3{}; |
|||
UseTracker var_u32x4{}; |
|||
UseTracker var_f32{}; |
|||
UseTracker var_f32x2{}; |
|||
UseTracker var_f32x3{}; |
|||
UseTracker var_f32x4{}; |
|||
UseTracker var_u64{}; |
|||
UseTracker var_s64{}; |
|||
UseTracker var_f64{}; |
|||
}; |
|||
|
|||
} // namespace Shader::Backend::GLSL |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue