shader: Primitive Vulkan integration
This commit is contained in:
parent
c67d64365a
commit
85cce78583
43 changed files with 1003 additions and 3036 deletions
|
@ -1,4 +1,4 @@
|
||||||
add_executable(shader_recompiler
|
add_library(shader_recompiler STATIC
|
||||||
backend/spirv/emit_context.cpp
|
backend/spirv/emit_context.cpp
|
||||||
backend/spirv/emit_context.h
|
backend/spirv/emit_context.h
|
||||||
backend/spirv/emit_spirv.cpp
|
backend/spirv/emit_spirv.cpp
|
||||||
|
@ -85,13 +85,19 @@ add_executable(shader_recompiler
|
||||||
ir_opt/passes.h
|
ir_opt/passes.h
|
||||||
ir_opt/ssa_rewrite_pass.cpp
|
ir_opt/ssa_rewrite_pass.cpp
|
||||||
ir_opt/verification_pass.cpp
|
ir_opt/verification_pass.cpp
|
||||||
main.cpp
|
|
||||||
object_pool.h
|
object_pool.h
|
||||||
|
profile.h
|
||||||
|
recompiler.cpp
|
||||||
|
recompiler.h
|
||||||
shader_info.h
|
shader_info.h
|
||||||
)
|
)
|
||||||
|
|
||||||
target_include_directories(video_core PRIVATE sirit)
|
target_include_directories(shader_recompiler PRIVATE sirit)
|
||||||
target_link_libraries(shader_recompiler PRIVATE fmt::fmt sirit)
|
target_link_libraries(shader_recompiler PRIVATE fmt::fmt sirit)
|
||||||
|
target_link_libraries(shader_recompiler INTERFACE fmt::fmt sirit)
|
||||||
|
|
||||||
|
add_executable(shader_util main.cpp)
|
||||||
|
target_link_libraries(shader_util PRIVATE shader_recompiler)
|
||||||
|
|
||||||
if (MSVC)
|
if (MSVC)
|
||||||
target_compile_options(shader_recompiler PRIVATE
|
target_compile_options(shader_recompiler PRIVATE
|
||||||
|
@ -121,3 +127,4 @@ else()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
create_target_directory_groups(shader_recompiler)
|
create_target_directory_groups(shader_recompiler)
|
||||||
|
create_target_directory_groups(shader_util)
|
||||||
|
|
|
@ -115,6 +115,7 @@ void EmitContext::DefineConstantBuffers(const Info& info) {
|
||||||
for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
|
for (const Info::ConstantBufferDescriptor& desc : info.constant_buffer_descriptors) {
|
||||||
const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
|
const Id id{AddGlobalVariable(uniform_type, spv::StorageClass::Uniform)};
|
||||||
Decorate(id, spv::Decoration::Binding, binding);
|
Decorate(id, spv::Decoration::Binding, binding);
|
||||||
|
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||||
Name(id, fmt::format("c{}", desc.index));
|
Name(id, fmt::format("c{}", desc.index));
|
||||||
std::fill_n(cbufs.data() + desc.index, desc.count, id);
|
std::fill_n(cbufs.data() + desc.index, desc.count, id);
|
||||||
binding += desc.count;
|
binding += desc.count;
|
||||||
|
@ -143,6 +144,7 @@ void EmitContext::DefineStorageBuffers(const Info& info) {
|
||||||
for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
|
for (const Info::StorageBufferDescriptor& desc : info.storage_buffers_descriptors) {
|
||||||
const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
|
const Id id{AddGlobalVariable(storage_type, spv::StorageClass::StorageBuffer)};
|
||||||
Decorate(id, spv::Decoration::Binding, binding);
|
Decorate(id, spv::Decoration::Binding, binding);
|
||||||
|
Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||||
Name(id, fmt::format("ssbo{}", binding));
|
Name(id, fmt::format("ssbo{}", binding));
|
||||||
std::fill_n(ssbos.data() + binding, desc.count, id);
|
std::fill_n(ssbos.data() + binding, desc.count, id);
|
||||||
binding += desc.count;
|
binding += desc.count;
|
||||||
|
|
|
@ -2,8 +2,11 @@
|
||||||
// Licensed under GPLv2 or any later version
|
// Licensed under GPLv2 or any later version
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <numeric>
|
#include <span>
|
||||||
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||||
#include "shader_recompiler/frontend/ir/basic_block.h"
|
#include "shader_recompiler/frontend/ir/basic_block.h"
|
||||||
|
@ -14,10 +17,10 @@
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
namespace {
|
namespace {
|
||||||
template <class Func>
|
template <class Func>
|
||||||
struct FuncTraits : FuncTraits<decltype(&Func::operator())> {};
|
struct FuncTraits : FuncTraits<Func> {};
|
||||||
|
|
||||||
template <class ClassType, class ReturnType_, class... Args>
|
template <class ReturnType_, class... Args>
|
||||||
struct FuncTraits<ReturnType_ (ClassType::*)(Args...)> {
|
struct FuncTraits<ReturnType_ (*)(Args...)> {
|
||||||
using ReturnType = ReturnType_;
|
using ReturnType = ReturnType_;
|
||||||
|
|
||||||
static constexpr size_t NUM_ARGS = sizeof...(Args);
|
static constexpr size_t NUM_ARGS = sizeof...(Args);
|
||||||
|
@ -26,15 +29,15 @@ struct FuncTraits<ReturnType_ (ClassType::*)(Args...)> {
|
||||||
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
|
using ArgType = std::tuple_element_t<I, std::tuple<Args...>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <auto method, typename... Args>
|
template <auto func, typename... Args>
|
||||||
void SetDefinition(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst, Args... args) {
|
void SetDefinition(EmitContext& ctx, IR::Inst* inst, Args... args) {
|
||||||
const Id forward_id{inst->Definition<Id>()};
|
const Id forward_id{inst->Definition<Id>()};
|
||||||
const bool has_forward_id{Sirit::ValidId(forward_id)};
|
const bool has_forward_id{Sirit::ValidId(forward_id)};
|
||||||
Id current_id{};
|
Id current_id{};
|
||||||
if (has_forward_id) {
|
if (has_forward_id) {
|
||||||
current_id = ctx.ExchangeCurrentId(forward_id);
|
current_id = ctx.ExchangeCurrentId(forward_id);
|
||||||
}
|
}
|
||||||
const Id new_id{(emit.*method)(ctx, std::forward<Args>(args)...)};
|
const Id new_id{func(ctx, std::forward<Args>(args)...)};
|
||||||
if (has_forward_id) {
|
if (has_forward_id) {
|
||||||
ctx.ExchangeCurrentId(current_id);
|
ctx.ExchangeCurrentId(current_id);
|
||||||
} else {
|
} else {
|
||||||
|
@ -55,42 +58,62 @@ ArgType Arg(EmitContext& ctx, const IR::Value& arg) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <auto method, bool is_first_arg_inst, size_t... I>
|
template <auto func, bool is_first_arg_inst, size_t... I>
|
||||||
void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) {
|
void Invoke(EmitContext& ctx, IR::Inst* inst, std::index_sequence<I...>) {
|
||||||
using Traits = FuncTraits<decltype(method)>;
|
using Traits = FuncTraits<decltype(func)>;
|
||||||
if constexpr (std::is_same_v<Traits::ReturnType, Id>) {
|
if constexpr (std::is_same_v<Traits::ReturnType, Id>) {
|
||||||
if constexpr (is_first_arg_inst) {
|
if constexpr (is_first_arg_inst) {
|
||||||
SetDefinition<method>(emit, ctx, inst, inst,
|
SetDefinition<func>(ctx, inst, inst, Arg<Traits::ArgType<I + 2>>(ctx, inst->Arg(I))...);
|
||||||
Arg<Traits::ArgType<I + 2>>(ctx, inst->Arg(I))...);
|
|
||||||
} else {
|
} else {
|
||||||
SetDefinition<method>(emit, ctx, inst,
|
SetDefinition<func>(ctx, inst, Arg<Traits::ArgType<I + 1>>(ctx, inst->Arg(I))...);
|
||||||
Arg<Traits::ArgType<I + 1>>(ctx, inst->Arg(I))...);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if constexpr (is_first_arg_inst) {
|
if constexpr (is_first_arg_inst) {
|
||||||
(emit.*method)(ctx, inst, Arg<Traits::ArgType<I + 2>>(ctx, inst->Arg(I))...);
|
func(ctx, inst, Arg<Traits::ArgType<I + 2>>(ctx, inst->Arg(I))...);
|
||||||
} else {
|
} else {
|
||||||
(emit.*method)(ctx, Arg<Traits::ArgType<I + 1>>(ctx, inst->Arg(I))...);
|
func(ctx, Arg<Traits::ArgType<I + 1>>(ctx, inst->Arg(I))...);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <auto method>
|
template <auto func>
|
||||||
void Invoke(EmitSPIRV& emit, EmitContext& ctx, IR::Inst* inst) {
|
void Invoke(EmitContext& ctx, IR::Inst* inst) {
|
||||||
using Traits = FuncTraits<decltype(method)>;
|
using Traits = FuncTraits<decltype(func)>;
|
||||||
static_assert(Traits::NUM_ARGS >= 1, "Insufficient arguments");
|
static_assert(Traits::NUM_ARGS >= 1, "Insufficient arguments");
|
||||||
if constexpr (Traits::NUM_ARGS == 1) {
|
if constexpr (Traits::NUM_ARGS == 1) {
|
||||||
Invoke<method, false>(emit, ctx, inst, std::make_index_sequence<0>{});
|
Invoke<func, false>(ctx, inst, std::make_index_sequence<0>{});
|
||||||
} else {
|
} else {
|
||||||
using FirstArgType = typename Traits::template ArgType<1>;
|
using FirstArgType = typename Traits::template ArgType<1>;
|
||||||
static constexpr bool is_first_arg_inst = std::is_same_v<FirstArgType, IR::Inst*>;
|
static constexpr bool is_first_arg_inst = std::is_same_v<FirstArgType, IR::Inst*>;
|
||||||
using Indices = std::make_index_sequence<Traits::NUM_ARGS - (is_first_arg_inst ? 2 : 1)>;
|
using Indices = std::make_index_sequence<Traits::NUM_ARGS - (is_first_arg_inst ? 2 : 1)>;
|
||||||
Invoke<method, is_first_arg_inst>(emit, ctx, inst, Indices{});
|
Invoke<func, is_first_arg_inst>(ctx, inst, Indices{});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EmitInst(EmitContext& ctx, IR::Inst* inst) {
|
||||||
|
switch (inst->Opcode()) {
|
||||||
|
#define OPCODE(name, result_type, ...) \
|
||||||
|
case IR::Opcode::name: \
|
||||||
|
return Invoke<&Emit##name>(ctx, inst);
|
||||||
|
#include "shader_recompiler/frontend/ir/opcodes.inc"
|
||||||
|
#undef OPCODE
|
||||||
|
}
|
||||||
|
throw LogicError("Invalid opcode {}", inst->Opcode());
|
||||||
|
}
|
||||||
|
|
||||||
|
Id TypeId(const EmitContext& ctx, IR::Type type) {
|
||||||
|
switch (type) {
|
||||||
|
case IR::Type::U1:
|
||||||
|
return ctx.U1;
|
||||||
|
case IR::Type::U32:
|
||||||
|
return ctx.U32[1];
|
||||||
|
default:
|
||||||
|
throw NotImplementedException("Phi node type {}", type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
EmitSPIRV::EmitSPIRV(IR::Program& program) {
|
std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program) {
|
||||||
EmitContext ctx{program};
|
EmitContext ctx{program};
|
||||||
const Id void_function{ctx.TypeFunction(ctx.void_id)};
|
const Id void_function{ctx.TypeFunction(ctx.void_id)};
|
||||||
// FIXME: Forward declare functions (needs sirit support)
|
// FIXME: Forward declare functions (needs sirit support)
|
||||||
|
@ -112,43 +135,17 @@ EmitSPIRV::EmitSPIRV(IR::Program& program) {
|
||||||
if (program.info.uses_local_invocation_id) {
|
if (program.info.uses_local_invocation_id) {
|
||||||
interfaces.push_back(ctx.local_invocation_id);
|
interfaces.push_back(ctx.local_invocation_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::span interfaces_span(interfaces.data(), interfaces.size());
|
const std::span interfaces_span(interfaces.data(), interfaces.size());
|
||||||
ctx.AddEntryPoint(spv::ExecutionModel::Fragment, func, "main", interfaces_span);
|
ctx.AddEntryPoint(spv::ExecutionModel::GLCompute, func, "main", interfaces_span);
|
||||||
ctx.AddExecutionMode(func, spv::ExecutionMode::OriginUpperLeft);
|
|
||||||
|
|
||||||
std::vector<u32> result{ctx.Assemble()};
|
const std::array<u32, 3> workgroup_size{env.WorkgroupSize()};
|
||||||
std::FILE* file{std::fopen("D:\\shader.spv", "wb")};
|
ctx.AddExecutionMode(func, spv::ExecutionMode::LocalSize, workgroup_size[0], workgroup_size[1],
|
||||||
std::fwrite(result.data(), sizeof(u32), result.size(), file);
|
workgroup_size[2]);
|
||||||
std::fclose(file);
|
|
||||||
std::system("spirv-dis D:\\shader.spv") == 0 &&
|
return ctx.Assemble();
|
||||||
std::system("spirv-val --uniform-buffer-standard-layout D:\\shader.spv") == 0 &&
|
|
||||||
std::system("spirv-cross -V D:\\shader.spv") == 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitInst(EmitContext& ctx, IR::Inst* inst) {
|
Id EmitPhi(EmitContext& ctx, IR::Inst* inst) {
|
||||||
switch (inst->Opcode()) {
|
|
||||||
#define OPCODE(name, result_type, ...) \
|
|
||||||
case IR::Opcode::name: \
|
|
||||||
return Invoke<&EmitSPIRV::Emit##name>(*this, ctx, inst);
|
|
||||||
#include "shader_recompiler/frontend/ir/opcodes.inc"
|
|
||||||
#undef OPCODE
|
|
||||||
}
|
|
||||||
throw LogicError("Invalid opcode {}", inst->Opcode());
|
|
||||||
}
|
|
||||||
|
|
||||||
static Id TypeId(const EmitContext& ctx, IR::Type type) {
|
|
||||||
switch (type) {
|
|
||||||
case IR::Type::U1:
|
|
||||||
return ctx.U1;
|
|
||||||
case IR::Type::U32:
|
|
||||||
return ctx.U32[1];
|
|
||||||
default:
|
|
||||||
throw NotImplementedException("Phi node type {}", type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) {
|
|
||||||
const size_t num_args{inst->NumArgs()};
|
const size_t num_args{inst->NumArgs()};
|
||||||
boost::container::small_vector<Id, 32> operands;
|
boost::container::small_vector<Id, 32> operands;
|
||||||
operands.reserve(num_args * 2);
|
operands.reserve(num_args * 2);
|
||||||
|
@ -178,25 +175,25 @@ Id EmitSPIRV::EmitPhi(EmitContext& ctx, IR::Inst* inst) {
|
||||||
return ctx.OpPhi(result_type, std::span(operands.data(), operands.size()));
|
return ctx.OpPhi(result_type, std::span(operands.data(), operands.size()));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitVoid(EmitContext&) {}
|
void EmitVoid(EmitContext&) {}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitIdentity(EmitContext& ctx, const IR::Value& value) {
|
Id EmitIdentity(EmitContext& ctx, const IR::Value& value) {
|
||||||
return ctx.Def(value);
|
return ctx.Def(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetZeroFromOp(EmitContext&) {
|
void EmitGetZeroFromOp(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetSignFromOp(EmitContext&) {
|
void EmitGetSignFromOp(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetCarryFromOp(EmitContext&) {
|
void EmitGetCarryFromOp(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetOverflowFromOp(EmitContext&) {
|
void EmitGetOverflowFromOp(EmitContext&) {
|
||||||
throw LogicError("Unreachable instruction");
|
throw LogicError("Unreachable instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,17 +8,13 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "shader_recompiler/backend/spirv/emit_context.h"
|
#include "shader_recompiler/backend/spirv/emit_context.h"
|
||||||
|
#include "shader_recompiler/environment.h"
|
||||||
#include "shader_recompiler/frontend/ir/microinstruction.h"
|
#include "shader_recompiler/frontend/ir/microinstruction.h"
|
||||||
#include "shader_recompiler/frontend/ir/program.h"
|
#include "shader_recompiler/frontend/ir/program.h"
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
class EmitSPIRV {
|
[[nodiscard]] std::vector<u32> EmitSPIRV(Environment& env, IR::Program& program);
|
||||||
public:
|
|
||||||
explicit EmitSPIRV(IR::Program& program);
|
|
||||||
|
|
||||||
private:
|
|
||||||
void EmitInst(EmitContext& ctx, IR::Inst* inst);
|
|
||||||
|
|
||||||
// Microinstruction emitters
|
// Microinstruction emitters
|
||||||
Id EmitPhi(EmitContext& ctx, IR::Inst* inst);
|
Id EmitPhi(EmitContext& ctx, IR::Inst* inst);
|
||||||
|
@ -225,6 +221,5 @@ private:
|
||||||
void EmitConvertU64F64(EmitContext& ctx);
|
void EmitConvertU64F64(EmitContext& ctx);
|
||||||
void EmitConvertU64U32(EmitContext& ctx);
|
void EmitConvertU64U32(EmitContext& ctx);
|
||||||
void EmitConvertU32U64(EmitContext& ctx);
|
void EmitConvertU32U64(EmitContext& ctx);
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace Shader::Backend::SPIRV
|
} // namespace Shader::Backend::SPIRV
|
||||||
|
|
|
@ -6,51 +6,51 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitCastU16F16(EmitContext&) {
|
void EmitBitCastU16F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitBitCastU32F32(EmitContext& ctx, Id value) {
|
Id EmitBitCastU32F32(EmitContext& ctx, Id value) {
|
||||||
return ctx.OpBitcast(ctx.U32[1], value);
|
return ctx.OpBitcast(ctx.U32[1], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitCastU64F64(EmitContext&) {
|
void EmitBitCastU64F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitCastF16U16(EmitContext&) {
|
void EmitBitCastF16U16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitBitCastF32U32(EmitContext& ctx, Id value) {
|
Id EmitBitCastF32U32(EmitContext& ctx, Id value) {
|
||||||
return ctx.OpBitcast(ctx.F32[1], value);
|
return ctx.OpBitcast(ctx.F32[1], value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitCastF64U64(EmitContext&) {
|
void EmitBitCastF64U64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitPackUint2x32(EmitContext&) {
|
void EmitPackUint2x32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitUnpackUint2x32(EmitContext&) {
|
void EmitUnpackUint2x32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitPackFloat2x16(EmitContext&) {
|
void EmitPackFloat2x16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitUnpackFloat2x16(EmitContext&) {
|
void EmitUnpackFloat2x16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitPackDouble2x32(EmitContext&) {
|
void EmitPackDouble2x32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitUnpackDouble2x32(EmitContext&) {
|
void EmitUnpackDouble2x32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,99 +6,99 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructU32x2(EmitContext&) {
|
void EmitCompositeConstructU32x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructU32x3(EmitContext&) {
|
void EmitCompositeConstructU32x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructU32x4(EmitContext&) {
|
void EmitCompositeConstructU32x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractU32x2(EmitContext&) {
|
void EmitCompositeExtractU32x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index) {
|
Id EmitCompositeExtractU32x3(EmitContext& ctx, Id vector, u32 index) {
|
||||||
return ctx.OpCompositeExtract(ctx.U32[1], vector, index);
|
return ctx.OpCompositeExtract(ctx.U32[1], vector, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractU32x4(EmitContext&) {
|
void EmitCompositeExtractU32x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF16x2(EmitContext&) {
|
void EmitCompositeConstructF16x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF16x3(EmitContext&) {
|
void EmitCompositeConstructF16x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF16x4(EmitContext&) {
|
void EmitCompositeConstructF16x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF16x2(EmitContext&) {
|
void EmitCompositeExtractF16x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF16x3(EmitContext&) {
|
void EmitCompositeExtractF16x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF16x4(EmitContext&) {
|
void EmitCompositeExtractF16x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF32x2(EmitContext&) {
|
void EmitCompositeConstructF32x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF32x3(EmitContext&) {
|
void EmitCompositeConstructF32x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF32x4(EmitContext&) {
|
void EmitCompositeConstructF32x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF32x2(EmitContext&) {
|
void EmitCompositeExtractF32x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF32x3(EmitContext&) {
|
void EmitCompositeExtractF32x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF32x4(EmitContext&) {
|
void EmitCompositeExtractF32x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF64x2(EmitContext&) {
|
void EmitCompositeConstructF64x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF64x3(EmitContext&) {
|
void EmitCompositeConstructF64x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeConstructF64x4(EmitContext&) {
|
void EmitCompositeConstructF64x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF64x2(EmitContext&) {
|
void EmitCompositeExtractF64x2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF64x3(EmitContext&) {
|
void EmitCompositeExtractF64x3(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitCompositeExtractF64x4(EmitContext&) {
|
void EmitCompositeExtractF64x4(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,31 +6,31 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetRegister(EmitContext&) {
|
void EmitGetRegister(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetRegister(EmitContext&) {
|
void EmitSetRegister(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetPred(EmitContext&) {
|
void EmitGetPred(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetPred(EmitContext&) {
|
void EmitSetPred(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetGotoVariable(EmitContext&) {
|
void EmitSetGotoVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetGotoVariable(EmitContext&) {
|
void EmitGetGotoVariable(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
Id EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
||||||
if (!binding.IsImmediate()) {
|
if (!binding.IsImmediate()) {
|
||||||
throw NotImplementedException("Constant buffer indexing");
|
throw NotImplementedException("Constant buffer indexing");
|
||||||
}
|
}
|
||||||
|
@ -43,59 +43,59 @@ Id EmitSPIRV::EmitGetCbuf(EmitContext& ctx, const IR::Value& binding, const IR::
|
||||||
return ctx.OpLoad(ctx.U32[1], access_chain);
|
return ctx.OpLoad(ctx.U32[1], access_chain);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetAttribute(EmitContext&) {
|
void EmitGetAttribute(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetAttribute(EmitContext&) {
|
void EmitSetAttribute(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetAttributeIndexed(EmitContext&) {
|
void EmitGetAttributeIndexed(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetAttributeIndexed(EmitContext&) {
|
void EmitSetAttributeIndexed(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetZFlag(EmitContext&) {
|
void EmitGetZFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetSFlag(EmitContext&) {
|
void EmitGetSFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetCFlag(EmitContext&) {
|
void EmitGetCFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitGetOFlag(EmitContext&) {
|
void EmitGetOFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetZFlag(EmitContext&) {
|
void EmitSetZFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetSFlag(EmitContext&) {
|
void EmitSetSFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetCFlag(EmitContext&) {
|
void EmitSetCFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSetOFlag(EmitContext&) {
|
void EmitSetOFlag(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitWorkgroupId(EmitContext& ctx) {
|
Id EmitWorkgroupId(EmitContext& ctx) {
|
||||||
return ctx.OpLoad(ctx.U32[3], ctx.workgroup_id);
|
return ctx.OpLoad(ctx.U32[3], ctx.workgroup_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitLocalInvocationId(EmitContext& ctx) {
|
Id EmitLocalInvocationId(EmitContext& ctx) {
|
||||||
return ctx.OpLoad(ctx.U32[3], ctx.local_invocation_id);
|
return ctx.OpLoad(ctx.U32[3], ctx.local_invocation_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,25 +6,25 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitBranch(EmitContext& ctx, IR::Block* label) {
|
void EmitBranch(EmitContext& ctx, IR::Block* label) {
|
||||||
ctx.OpBranch(label->Definition<Id>());
|
ctx.OpBranch(label->Definition<Id>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBranchConditional(EmitContext& ctx, Id condition, IR::Block* true_label,
|
void EmitBranchConditional(EmitContext& ctx, Id condition, IR::Block* true_label,
|
||||||
IR::Block* false_label) {
|
IR::Block* false_label) {
|
||||||
ctx.OpBranchConditional(condition, true_label->Definition<Id>(), false_label->Definition<Id>());
|
ctx.OpBranchConditional(condition, true_label->Definition<Id>(), false_label->Definition<Id>());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoopMerge(EmitContext& ctx, IR::Block* merge_label, IR::Block* continue_label) {
|
void EmitLoopMerge(EmitContext& ctx, IR::Block* merge_label, IR::Block* continue_label) {
|
||||||
ctx.OpLoopMerge(merge_label->Definition<Id>(), continue_label->Definition<Id>(),
|
ctx.OpLoopMerge(merge_label->Definition<Id>(), continue_label->Definition<Id>(),
|
||||||
spv::LoopControlMask::MaskNone);
|
spv::LoopControlMask::MaskNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSelectionMerge(EmitContext& ctx, IR::Block* merge_label) {
|
void EmitSelectionMerge(EmitContext& ctx, IR::Block* merge_label) {
|
||||||
ctx.OpSelectionMerge(merge_label->Definition<Id>(), spv::SelectionControlMask::MaskNone);
|
ctx.OpSelectionMerge(merge_label->Definition<Id>(), spv::SelectionControlMask::MaskNone);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitReturn(EmitContext& ctx) {
|
void EmitReturn(EmitContext& ctx) {
|
||||||
ctx.OpReturn();
|
ctx.OpReturn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,187 +33,187 @@ Id Decorate(EmitContext& ctx, IR::Inst* inst, Id op) {
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPAbs16(EmitContext&) {
|
void EmitFPAbs16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPAbs32(EmitContext&) {
|
void EmitFPAbs32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPAbs64(EmitContext&) {
|
void EmitFPAbs64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F16[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F32[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPAdd64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFAdd(ctx.F64[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma16(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
return Decorate(ctx, inst, ctx.OpFma(ctx.F16[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma32(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
return Decorate(ctx, inst, ctx.OpFma(ctx.F32[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
Id EmitFPFma64(EmitContext& ctx, IR::Inst* inst, Id a, Id b, Id c) {
|
||||||
return Decorate(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
return Decorate(ctx, inst, ctx.OpFma(ctx.F64[1], a, b, c));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPMax32(EmitContext&) {
|
void EmitFPMax32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPMax64(EmitContext&) {
|
void EmitFPMax64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPMin32(EmitContext&) {
|
void EmitFPMin32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPMin64(EmitContext&) {
|
void EmitFPMin64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul16(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFMul(ctx.F16[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFMul(ctx.F32[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitFPMul64(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
return Decorate(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
return Decorate(ctx, inst, ctx.OpFMul(ctx.F64[1], a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPNeg16(EmitContext&) {
|
void EmitFPNeg16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPNeg32(EmitContext&) {
|
void EmitFPNeg32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPNeg64(EmitContext&) {
|
void EmitFPNeg64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRecip32(EmitContext&) {
|
void EmitFPRecip32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRecip64(EmitContext&) {
|
void EmitFPRecip64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRecipSqrt32(EmitContext&) {
|
void EmitFPRecipSqrt32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRecipSqrt64(EmitContext&) {
|
void EmitFPRecipSqrt64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSqrt(EmitContext&) {
|
void EmitFPSqrt(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSin(EmitContext&) {
|
void EmitFPSin(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSinNotReduced(EmitContext&) {
|
void EmitFPSinNotReduced(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPExp2(EmitContext&) {
|
void EmitFPExp2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPExp2NotReduced(EmitContext&) {
|
void EmitFPExp2NotReduced(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPCos(EmitContext&) {
|
void EmitFPCos(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPCosNotReduced(EmitContext&) {
|
void EmitFPCosNotReduced(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPLog2(EmitContext&) {
|
void EmitFPLog2(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSaturate16(EmitContext&) {
|
void EmitFPSaturate16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSaturate32(EmitContext&) {
|
void EmitFPSaturate32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPSaturate64(EmitContext&) {
|
void EmitFPSaturate64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRoundEven16(EmitContext&) {
|
void EmitFPRoundEven16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRoundEven32(EmitContext&) {
|
void EmitFPRoundEven32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPRoundEven64(EmitContext&) {
|
void EmitFPRoundEven64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPFloor16(EmitContext&) {
|
void EmitFPFloor16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPFloor32(EmitContext&) {
|
void EmitFPFloor32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPFloor64(EmitContext&) {
|
void EmitFPFloor64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPCeil16(EmitContext&) {
|
void EmitFPCeil16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPCeil32(EmitContext&) {
|
void EmitFPCeil32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPCeil64(EmitContext&) {
|
void EmitFPCeil64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPTrunc16(EmitContext&) {
|
void EmitFPTrunc16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPTrunc32(EmitContext&) {
|
void EmitFPTrunc32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitFPTrunc64(EmitContext&) {
|
void EmitFPTrunc64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,126 +6,126 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
Id EmitSPIRV::EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
Id EmitIAdd32(EmitContext& ctx, IR::Inst* inst, Id a, Id b) {
|
||||||
if (inst->HasAssociatedPseudoOperation()) {
|
if (inst->HasAssociatedPseudoOperation()) {
|
||||||
throw NotImplementedException("Pseudo-operations on IAdd32");
|
throw NotImplementedException("Pseudo-operations on IAdd32");
|
||||||
}
|
}
|
||||||
return ctx.OpIAdd(ctx.U32[1], a, b);
|
return ctx.OpIAdd(ctx.U32[1], a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitIAdd64(EmitContext&) {
|
void EmitIAdd64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitISub32(EmitContext& ctx, Id a, Id b) {
|
Id EmitISub32(EmitContext& ctx, Id a, Id b) {
|
||||||
return ctx.OpISub(ctx.U32[1], a, b);
|
return ctx.OpISub(ctx.U32[1], a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitISub64(EmitContext&) {
|
void EmitISub64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitIMul32(EmitContext& ctx, Id a, Id b) {
|
Id EmitIMul32(EmitContext& ctx, Id a, Id b) {
|
||||||
return ctx.OpIMul(ctx.U32[1], a, b);
|
return ctx.OpIMul(ctx.U32[1], a, b);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitINeg32(EmitContext&) {
|
void EmitINeg32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitIAbs32(EmitContext&) {
|
void EmitIAbs32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) {
|
Id EmitShiftLeftLogical32(EmitContext& ctx, Id base, Id shift) {
|
||||||
return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift);
|
return ctx.OpShiftLeftLogical(ctx.U32[1], base, shift);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitShiftRightLogical32(EmitContext&) {
|
void EmitShiftRightLogical32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitShiftRightArithmetic32(EmitContext&) {
|
void EmitShiftRightArithmetic32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitwiseAnd32(EmitContext&) {
|
void EmitBitwiseAnd32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitwiseOr32(EmitContext&) {
|
void EmitBitwiseOr32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitwiseXor32(EmitContext&) {
|
void EmitBitwiseXor32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitFieldInsert(EmitContext&) {
|
void EmitBitFieldInsert(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitBitFieldSExtract(EmitContext&) {
|
void EmitBitFieldSExtract(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitBitFieldUExtract(EmitContext& ctx, Id base, Id offset, Id count) {
|
Id EmitBitFieldUExtract(EmitContext& ctx, Id base, Id offset, Id count) {
|
||||||
return ctx.OpBitFieldUExtract(ctx.U32[1], base, offset, count);
|
return ctx.OpBitFieldUExtract(ctx.U32[1], base, offset, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitSLessThan(EmitContext& ctx, Id lhs, Id rhs) {
|
Id EmitSLessThan(EmitContext& ctx, Id lhs, Id rhs) {
|
||||||
return ctx.OpSLessThan(ctx.U1, lhs, rhs);
|
return ctx.OpSLessThan(ctx.U1, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitULessThan(EmitContext&) {
|
void EmitULessThan(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitIEqual(EmitContext&) {
|
void EmitIEqual(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSLessThanEqual(EmitContext&) {
|
void EmitSLessThanEqual(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitULessThanEqual(EmitContext&) {
|
void EmitULessThanEqual(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitSGreaterThan(EmitContext& ctx, Id lhs, Id rhs) {
|
Id EmitSGreaterThan(EmitContext& ctx, Id lhs, Id rhs) {
|
||||||
return ctx.OpSGreaterThan(ctx.U1, lhs, rhs);
|
return ctx.OpSGreaterThan(ctx.U1, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitUGreaterThan(EmitContext&) {
|
void EmitUGreaterThan(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitINotEqual(EmitContext&) {
|
void EmitINotEqual(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSGreaterThanEqual(EmitContext&) {
|
void EmitSGreaterThanEqual(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
|
Id EmitUGreaterThanEqual(EmitContext& ctx, Id lhs, Id rhs) {
|
||||||
return ctx.OpUGreaterThanEqual(ctx.U1, lhs, rhs);
|
return ctx.OpUGreaterThanEqual(ctx.U1, lhs, rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLogicalOr(EmitContext&) {
|
void EmitLogicalOr(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLogicalAnd(EmitContext&) {
|
void EmitLogicalAnd(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLogicalXor(EmitContext&) {
|
void EmitLogicalXor(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLogicalNot(EmitContext&) {
|
void EmitLogicalNot(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,83 +6,83 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS16F16(EmitContext&) {
|
void EmitConvertS16F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS16F32(EmitContext&) {
|
void EmitConvertS16F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS16F64(EmitContext&) {
|
void EmitConvertS16F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS32F16(EmitContext&) {
|
void EmitConvertS32F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS32F32(EmitContext&) {
|
void EmitConvertS32F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS32F64(EmitContext&) {
|
void EmitConvertS32F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS64F16(EmitContext&) {
|
void EmitConvertS64F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS64F32(EmitContext&) {
|
void EmitConvertS64F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertS64F64(EmitContext&) {
|
void EmitConvertS64F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU16F16(EmitContext&) {
|
void EmitConvertU16F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU16F32(EmitContext&) {
|
void EmitConvertU16F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU16F64(EmitContext&) {
|
void EmitConvertU16F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU32F16(EmitContext&) {
|
void EmitConvertU32F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU32F32(EmitContext&) {
|
void EmitConvertU32F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU32F64(EmitContext&) {
|
void EmitConvertU32F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU64F16(EmitContext&) {
|
void EmitConvertU64F16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU64F32(EmitContext&) {
|
void EmitConvertU64F32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU64F64(EmitContext&) {
|
void EmitConvertU64F64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU64U32(EmitContext&) {
|
void EmitConvertU64U32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitConvertU32U64(EmitContext&) {
|
void EmitConvertU32U64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,79 +22,79 @@ static Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element
|
||||||
return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id);
|
return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobalU8(EmitContext&) {
|
void EmitLoadGlobalU8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobalS8(EmitContext&) {
|
void EmitLoadGlobalS8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobalU16(EmitContext&) {
|
void EmitLoadGlobalU16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobalS16(EmitContext&) {
|
void EmitLoadGlobalS16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobal32(EmitContext&) {
|
void EmitLoadGlobal32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobal64(EmitContext&) {
|
void EmitLoadGlobal64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadGlobal128(EmitContext&) {
|
void EmitLoadGlobal128(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobalU8(EmitContext&) {
|
void EmitWriteGlobalU8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobalS8(EmitContext&) {
|
void EmitWriteGlobalS8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobalU16(EmitContext&) {
|
void EmitWriteGlobalU16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobalS16(EmitContext&) {
|
void EmitWriteGlobalS16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobal32(EmitContext&) {
|
void EmitWriteGlobal32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobal64(EmitContext&) {
|
void EmitWriteGlobal64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteGlobal128(EmitContext&) {
|
void EmitWriteGlobal128(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorageU8(EmitContext&) {
|
void EmitLoadStorageU8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorageS8(EmitContext&) {
|
void EmitLoadStorageS8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorageU16(EmitContext&) {
|
void EmitLoadStorageU16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorageS16(EmitContext&) {
|
void EmitLoadStorageS16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding,
|
Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding,
|
||||||
const IR::Value& offset) {
|
const IR::Value& offset) {
|
||||||
if (!binding.IsImmediate()) {
|
if (!binding.IsImmediate()) {
|
||||||
throw NotImplementedException("Dynamic storage buffer indexing");
|
throw NotImplementedException("Dynamic storage buffer indexing");
|
||||||
|
@ -105,31 +105,31 @@ Id EmitSPIRV::EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding,
|
||||||
return ctx.OpLoad(ctx.U32[1], pointer);
|
return ctx.OpLoad(ctx.U32[1], pointer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorage64(EmitContext&) {
|
void EmitLoadStorage64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitLoadStorage128(EmitContext&) {
|
void EmitLoadStorage128(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorageU8(EmitContext&) {
|
void EmitWriteStorageU8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorageS8(EmitContext&) {
|
void EmitWriteStorageS8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorageU16(EmitContext&) {
|
void EmitWriteStorageU16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorageS16(EmitContext&) {
|
void EmitWriteStorageS16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
|
void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
|
||||||
const IR::Value& offset, Id value) {
|
const IR::Value& offset, Id value) {
|
||||||
if (!binding.IsImmediate()) {
|
if (!binding.IsImmediate()) {
|
||||||
throw NotImplementedException("Dynamic storage buffer indexing");
|
throw NotImplementedException("Dynamic storage buffer indexing");
|
||||||
|
@ -140,11 +140,11 @@ void EmitSPIRV::EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding,
|
||||||
ctx.OpStore(pointer, value);
|
ctx.OpStore(pointer, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorage64(EmitContext&) {
|
void EmitWriteStorage64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitWriteStorage128(EmitContext&) {
|
void EmitWriteStorage128(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,19 +6,19 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
void EmitSPIRV::EmitSelect8(EmitContext&) {
|
void EmitSelect8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSelect16(EmitContext&) {
|
void EmitSelect16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSelect32(EmitContext&) {
|
void EmitSelect32(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmitSPIRV::EmitSelect64(EmitContext&) {
|
void EmitSelect64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,23 +6,23 @@
|
||||||
|
|
||||||
namespace Shader::Backend::SPIRV {
|
namespace Shader::Backend::SPIRV {
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUndefU1(EmitContext& ctx) {
|
Id EmitUndefU1(EmitContext& ctx) {
|
||||||
return ctx.OpUndef(ctx.U1);
|
return ctx.OpUndef(ctx.U1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUndefU8(EmitContext&) {
|
Id EmitUndefU8(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUndefU16(EmitContext&) {
|
Id EmitUndefU16(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUndefU32(EmitContext& ctx) {
|
Id EmitUndefU32(EmitContext& ctx) {
|
||||||
return ctx.OpUndef(ctx.U32[1]);
|
return ctx.OpUndef(ctx.U32[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitSPIRV::EmitUndefU64(EmitContext&) {
|
Id EmitUndefU64(EmitContext&) {
|
||||||
throw NotImplementedException("SPIR-V Instruction");
|
throw NotImplementedException("SPIR-V Instruction");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
namespace Shader {
|
namespace Shader {
|
||||||
|
@ -8,7 +10,9 @@ class Environment {
|
||||||
public:
|
public:
|
||||||
virtual ~Environment() = default;
|
virtual ~Environment() = default;
|
||||||
|
|
||||||
[[nodiscard]] virtual u64 ReadInstruction(u32 address) const = 0;
|
[[nodiscard]] virtual u64 ReadInstruction(u32 address) = 0;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual std::array<u32, 3> WorkgroupSize() = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Shader
|
} // namespace Shader
|
||||||
|
|
|
@ -29,7 +29,7 @@ FileEnvironment::FileEnvironment(const char* path) {
|
||||||
|
|
||||||
FileEnvironment::~FileEnvironment() = default;
|
FileEnvironment::~FileEnvironment() = default;
|
||||||
|
|
||||||
u64 FileEnvironment::ReadInstruction(u32 offset) const {
|
u64 FileEnvironment::ReadInstruction(u32 offset) {
|
||||||
if (offset % 8 != 0) {
|
if (offset % 8 != 0) {
|
||||||
throw InvalidArgument("offset={} is not aligned to 8", offset);
|
throw InvalidArgument("offset={} is not aligned to 8", offset);
|
||||||
}
|
}
|
||||||
|
@ -39,4 +39,8 @@ u64 FileEnvironment::ReadInstruction(u32 offset) const {
|
||||||
return data[offset / 8];
|
return data[offset / 8];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::array<u32, 3> FileEnvironment::WorkgroupSize() {
|
||||||
|
return {1, 1, 1};
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Shader
|
} // namespace Shader
|
||||||
|
|
|
@ -12,7 +12,9 @@ public:
|
||||||
explicit FileEnvironment(const char* path);
|
explicit FileEnvironment(const char* path);
|
||||||
~FileEnvironment() override;
|
~FileEnvironment() override;
|
||||||
|
|
||||||
u64 ReadInstruction(u32 offset) const override;
|
u64 ReadInstruction(u32 offset) override;
|
||||||
|
|
||||||
|
std::array<u32, 3> WorkgroupSize() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<u64> data;
|
std::vector<u64> data;
|
||||||
|
|
|
@ -127,6 +127,8 @@ static std::string ArgToIndex(const std::map<const Block*, size_t>& block_to_ind
|
||||||
return fmt::format("#{}", arg.U32());
|
return fmt::format("#{}", arg.U32());
|
||||||
case Type::U64:
|
case Type::U64:
|
||||||
return fmt::format("#{}", arg.U64());
|
return fmt::format("#{}", arg.U64());
|
||||||
|
case Type::F32:
|
||||||
|
return fmt::format("#{}", arg.F32());
|
||||||
case Type::Reg:
|
case Type::Reg:
|
||||||
return fmt::format("{}", arg.Reg());
|
return fmt::format("{}", arg.Reg());
|
||||||
case Type::Pred:
|
case Type::Pred:
|
||||||
|
|
|
@ -28,7 +28,7 @@ BlockList PostOrder(const BlockList& blocks) {
|
||||||
if (!visited.insert(branch).second) {
|
if (!visited.insert(branch).second) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// Calling push_back twice is faster than insert on msvc
|
// Calling push_back twice is faster than insert on MSVC
|
||||||
block_stack.push_back(block);
|
block_stack.push_back(block);
|
||||||
block_stack.push_back(branch);
|
block_stack.push_back(branch);
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -69,7 +69,7 @@ IR::Program TranslateProgram(ObjectPool<IR::Inst>& inst_pool, ObjectPool<IR::Blo
|
||||||
Optimization::VerificationPass(function);
|
Optimization::VerificationPass(function);
|
||||||
}
|
}
|
||||||
Optimization::CollectShaderInfoPass(program);
|
Optimization::CollectShaderInfoPass(program);
|
||||||
//*/
|
fmt::print(stdout, "{}\n", IR::DumpProgram(program));
|
||||||
return program;
|
return program;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,14 @@ void TranslatorVisitor::F(IR::Reg dest_reg, const IR::F32& value) {
|
||||||
X(dest_reg, ir.BitCast<IR::U32>(value));
|
X(dest_reg, ir.BitCast<IR::U32>(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IR::U32 TranslatorVisitor::GetReg8(u64 insn) {
|
||||||
|
union {
|
||||||
|
u64 raw;
|
||||||
|
BitField<8, 8, IR::Reg> index;
|
||||||
|
} const reg{insn};
|
||||||
|
return X(reg.index);
|
||||||
|
}
|
||||||
|
|
||||||
IR::U32 TranslatorVisitor::GetReg20(u64 insn) {
|
IR::U32 TranslatorVisitor::GetReg20(u64 insn) {
|
||||||
union {
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
|
|
|
@ -301,6 +301,7 @@ public:
|
||||||
void X(IR::Reg dest_reg, const IR::U32& value);
|
void X(IR::Reg dest_reg, const IR::U32& value);
|
||||||
void F(IR::Reg dest_reg, const IR::F32& value);
|
void F(IR::Reg dest_reg, const IR::F32& value);
|
||||||
|
|
||||||
|
[[nodiscard]] IR::U32 GetReg8(u64 insn);
|
||||||
[[nodiscard]] IR::U32 GetReg20(u64 insn);
|
[[nodiscard]] IR::U32 GetReg20(u64 insn);
|
||||||
[[nodiscard]] IR::U32 GetReg39(u64 insn);
|
[[nodiscard]] IR::U32 GetReg39(u64 insn);
|
||||||
[[nodiscard]] IR::F32 GetReg20F(u64 insn);
|
[[nodiscard]] IR::F32 GetReg20F(u64 insn);
|
||||||
|
|
|
@ -10,36 +10,35 @@
|
||||||
|
|
||||||
namespace Shader::Maxwell {
|
namespace Shader::Maxwell {
|
||||||
namespace {
|
namespace {
|
||||||
union MOV {
|
void MOV(TranslatorVisitor& v, u64 insn, const IR::U32& src, bool is_mov32i = false) {
|
||||||
|
union {
|
||||||
u64 raw;
|
u64 raw;
|
||||||
BitField<0, 8, IR::Reg> dest_reg;
|
BitField<0, 8, IR::Reg> dest_reg;
|
||||||
BitField<20, 8, IR::Reg> src_reg;
|
|
||||||
BitField<39, 4, u64> mask;
|
BitField<39, 4, u64> mask;
|
||||||
};
|
BitField<12, 4, u64> mov32i_mask;
|
||||||
|
} const mov{insn};
|
||||||
|
|
||||||
void CheckMask(MOV mov) {
|
if ((is_mov32i ? mov.mov32i_mask : mov.mask) != 0xf) {
|
||||||
if (mov.mask != 0xf) {
|
|
||||||
throw NotImplementedException("Non-full move mask");
|
throw NotImplementedException("Non-full move mask");
|
||||||
}
|
}
|
||||||
|
v.X(mov.dest_reg, src);
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
void TranslatorVisitor::MOV_reg(u64 insn) {
|
void TranslatorVisitor::MOV_reg(u64 insn) {
|
||||||
const MOV mov{insn};
|
MOV(*this, insn, GetReg8(insn));
|
||||||
CheckMask(mov);
|
|
||||||
X(mov.dest_reg, X(mov.src_reg));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::MOV_cbuf(u64 insn) {
|
void TranslatorVisitor::MOV_cbuf(u64 insn) {
|
||||||
const MOV mov{insn};
|
MOV(*this, insn, GetCbuf(insn));
|
||||||
CheckMask(mov);
|
|
||||||
X(mov.dest_reg, GetCbuf(insn));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::MOV_imm(u64 insn) {
|
void TranslatorVisitor::MOV_imm(u64 insn) {
|
||||||
const MOV mov{insn};
|
MOV(*this, insn, GetImm20(insn));
|
||||||
CheckMask(mov);
|
}
|
||||||
X(mov.dest_reg, GetImm20(insn));
|
|
||||||
|
void TranslatorVisitor::MOV32I(u64 insn) {
|
||||||
|
MOV(*this, insn, GetImm32(insn), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Shader::Maxwell
|
} // namespace Shader::Maxwell
|
||||||
|
|
|
@ -617,10 +617,6 @@ void TranslatorVisitor::MEMBAR(u64) {
|
||||||
ThrowNotImplemented(Opcode::MEMBAR);
|
ThrowNotImplemented(Opcode::MEMBAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TranslatorVisitor::MOV32I(u64) {
|
|
||||||
ThrowNotImplemented(Opcode::MOV32I);
|
|
||||||
}
|
|
||||||
|
|
||||||
void TranslatorVisitor::NOP(u64) {
|
void TranslatorVisitor::NOP(u64) {
|
||||||
ThrowNotImplemented(Opcode::NOP);
|
ThrowNotImplemented(Opcode::NOP);
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,5 +76,5 @@ int main() {
|
||||||
fmt::print(stdout, "{}\n", cfg.Dot());
|
fmt::print(stdout, "{}\n", cfg.Dot());
|
||||||
IR::Program program{TranslateProgram(inst_pool, block_pool, env, cfg)};
|
IR::Program program{TranslateProgram(inst_pool, block_pool, env, cfg)};
|
||||||
fmt::print(stdout, "{}\n", IR::DumpProgram(program));
|
fmt::print(stdout, "{}\n", IR::DumpProgram(program));
|
||||||
Backend::SPIRV::EmitSPIRV spirv{program};
|
void(Backend::SPIRV::EmitSPIRV(env, program));
|
||||||
}
|
}
|
||||||
|
|
13
src/shader_recompiler/profile.h
Normal file
13
src/shader_recompiler/profile.h
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace Shader {
|
||||||
|
|
||||||
|
struct Profile {
|
||||||
|
bool unified_descriptor_binding;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Shader
|
27
src/shader_recompiler/recompiler.cpp
Normal file
27
src/shader_recompiler/recompiler.cpp
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
||||||
|
#include "shader_recompiler/environment.h"
|
||||||
|
#include "shader_recompiler/frontend/maxwell/control_flow.h"
|
||||||
|
#include "shader_recompiler/frontend/maxwell/program.h"
|
||||||
|
#include "shader_recompiler/object_pool.h"
|
||||||
|
#include "shader_recompiler/recompiler.h"
|
||||||
|
|
||||||
|
namespace Shader {
|
||||||
|
|
||||||
|
std::pair<Info, std::vector<u32>> RecompileSPIRV(Environment& env, u32 start_address) {
|
||||||
|
ObjectPool<Maxwell::Flow::Block> flow_block_pool;
|
||||||
|
ObjectPool<IR::Inst> inst_pool;
|
||||||
|
ObjectPool<IR::Block> block_pool;
|
||||||
|
|
||||||
|
Maxwell::Flow::CFG cfg{env, flow_block_pool, start_address};
|
||||||
|
IR::Program program{Maxwell::TranslateProgram(inst_pool, block_pool, env, cfg)};
|
||||||
|
return {std::move(program.info), Backend::SPIRV::EmitSPIRV(env, program)};
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace Shader
|
18
src/shader_recompiler/recompiler.h
Normal file
18
src/shader_recompiler/recompiler.h
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// Copyright 2021 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "common/common_types.h"
|
||||||
|
#include "shader_recompiler/environment.h"
|
||||||
|
#include "shader_recompiler/shader_info.h"
|
||||||
|
|
||||||
|
namespace Shader {
|
||||||
|
|
||||||
|
[[nodiscard]] std::pair<Info, std::vector<u32>> RecompileSPIRV(Environment& env, u32 start_address);
|
||||||
|
|
||||||
|
} // namespace Shader
|
|
@ -43,9 +43,6 @@ add_library(video_core STATIC
|
||||||
engines/maxwell_3d.h
|
engines/maxwell_3d.h
|
||||||
engines/maxwell_dma.cpp
|
engines/maxwell_dma.cpp
|
||||||
engines/maxwell_dma.h
|
engines/maxwell_dma.h
|
||||||
engines/shader_bytecode.h
|
|
||||||
engines/shader_header.h
|
|
||||||
engines/shader_type.h
|
|
||||||
framebuffer_config.h
|
framebuffer_config.h
|
||||||
macro/macro.cpp
|
macro/macro.cpp
|
||||||
macro/macro.h
|
macro/macro.h
|
||||||
|
@ -123,6 +120,7 @@ add_library(video_core STATIC
|
||||||
renderer_vulkan/vk_master_semaphore.h
|
renderer_vulkan/vk_master_semaphore.h
|
||||||
renderer_vulkan/vk_pipeline_cache.cpp
|
renderer_vulkan/vk_pipeline_cache.cpp
|
||||||
renderer_vulkan/vk_pipeline_cache.h
|
renderer_vulkan/vk_pipeline_cache.h
|
||||||
|
renderer_vulkan/vk_pipeline.h
|
||||||
renderer_vulkan/vk_query_cache.cpp
|
renderer_vulkan/vk_query_cache.cpp
|
||||||
renderer_vulkan/vk_query_cache.h
|
renderer_vulkan/vk_query_cache.h
|
||||||
renderer_vulkan/vk_rasterizer.cpp
|
renderer_vulkan/vk_rasterizer.cpp
|
||||||
|
@ -201,7 +199,7 @@ add_library(video_core STATIC
|
||||||
create_target_directory_groups(video_core)
|
create_target_directory_groups(video_core)
|
||||||
|
|
||||||
target_link_libraries(video_core PUBLIC common core)
|
target_link_libraries(video_core PUBLIC common core)
|
||||||
target_link_libraries(video_core PRIVATE glad xbyak)
|
target_link_libraries(video_core PRIVATE glad shader_recompiler xbyak)
|
||||||
|
|
||||||
if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
|
if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
|
||||||
add_dependencies(video_core ffmpeg-build)
|
add_dependencies(video_core ffmpeg-build)
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/engines/engine_interface.h"
|
#include "video_core/engines/engine_interface.h"
|
||||||
#include "video_core/engines/engine_upload.h"
|
#include "video_core/engines/engine_upload.h"
|
||||||
#include "video_core/engines/shader_type.h"
|
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
#include "video_core/textures/texture.h"
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,158 +0,0 @@
|
||||||
// Copyright 2018 yuzu Emulator Project
|
|
||||||
// Licensed under GPLv2 or any later version
|
|
||||||
// Refer to the license.txt file included.
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <optional>
|
|
||||||
|
|
||||||
#include "common/bit_field.h"
|
|
||||||
#include "common/common_funcs.h"
|
|
||||||
#include "common/common_types.h"
|
|
||||||
|
|
||||||
namespace Tegra::Shader {
|
|
||||||
|
|
||||||
enum class OutputTopology : u32 {
|
|
||||||
PointList = 1,
|
|
||||||
LineStrip = 6,
|
|
||||||
TriangleStrip = 7,
|
|
||||||
};
|
|
||||||
|
|
||||||
enum class PixelImap : u8 {
|
|
||||||
Unused = 0,
|
|
||||||
Constant = 1,
|
|
||||||
Perspective = 2,
|
|
||||||
ScreenLinear = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Documentation in:
|
|
||||||
// http://download.nvidia.com/open-gpu-doc/Shader-Program-Header/1/Shader-Program-Header.html
|
|
||||||
struct Header {
|
|
||||||
union {
|
|
||||||
BitField<0, 5, u32> sph_type;
|
|
||||||
BitField<5, 5, u32> version;
|
|
||||||
BitField<10, 4, u32> shader_type;
|
|
||||||
BitField<14, 1, u32> mrt_enable;
|
|
||||||
BitField<15, 1, u32> kills_pixels;
|
|
||||||
BitField<16, 1, u32> does_global_store;
|
|
||||||
BitField<17, 4, u32> sass_version;
|
|
||||||
BitField<21, 5, u32> reserved;
|
|
||||||
BitField<26, 1, u32> does_load_or_store;
|
|
||||||
BitField<27, 1, u32> does_fp64;
|
|
||||||
BitField<28, 4, u32> stream_out_mask;
|
|
||||||
} common0;
|
|
||||||
|
|
||||||
union {
|
|
||||||
BitField<0, 24, u32> shader_local_memory_low_size;
|
|
||||||
BitField<24, 8, u32> per_patch_attribute_count;
|
|
||||||
} common1;
|
|
||||||
|
|
||||||
union {
|
|
||||||
BitField<0, 24, u32> shader_local_memory_high_size;
|
|
||||||
BitField<24, 8, u32> threads_per_input_primitive;
|
|
||||||
} common2;
|
|
||||||
|
|
||||||
union {
|
|
||||||
BitField<0, 24, u32> shader_local_memory_crs_size;
|
|
||||||
BitField<24, 4, OutputTopology> output_topology;
|
|
||||||
BitField<28, 4, u32> reserved;
|
|
||||||
} common3;
|
|
||||||
|
|
||||||
union {
|
|
||||||
BitField<0, 12, u32> max_output_vertices;
|
|
||||||
BitField<12, 8, u32> store_req_start; // NOTE: not used by geometry shaders.
|
|
||||||
BitField<20, 4, u32> reserved;
|
|
||||||
BitField<24, 8, u32> store_req_end; // NOTE: not used by geometry shaders.
|
|
||||||
} common4;
|
|
||||||
|
|
||||||
union {
|
|
||||||
struct {
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(16); // ImapGenericVector[32]
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // ImapColor
|
|
||||||
union {
|
|
||||||
BitField<0, 8, u16> clip_distances;
|
|
||||||
BitField<8, 1, u16> point_sprite_s;
|
|
||||||
BitField<9, 1, u16> point_sprite_t;
|
|
||||||
BitField<10, 1, u16> fog_coordinate;
|
|
||||||
BitField<12, 1, u16> tessellation_eval_point_u;
|
|
||||||
BitField<13, 1, u16> tessellation_eval_point_v;
|
|
||||||
BitField<14, 1, u16> instance_id;
|
|
||||||
BitField<15, 1, u16> vertex_id;
|
|
||||||
};
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10]
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(16); // OmapGenericVector[32]
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // OmapColor
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // OmapSystemValuesC
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10]
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved
|
|
||||||
} vtg;
|
|
||||||
|
|
||||||
struct {
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB
|
|
||||||
|
|
||||||
union {
|
|
||||||
BitField<0, 2, PixelImap> x;
|
|
||||||
BitField<2, 2, PixelImap> y;
|
|
||||||
BitField<4, 2, PixelImap> z;
|
|
||||||
BitField<6, 2, PixelImap> w;
|
|
||||||
u8 raw;
|
|
||||||
} imap_generic_vector[32];
|
|
||||||
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // ImapColor
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // ImapSystemValuesC
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(10); // ImapFixedFncTexture[10]
|
|
||||||
INSERT_PADDING_BYTES_NOINIT(2); // ImapReserved
|
|
||||||
|
|
||||||
struct {
|
|
||||||
u32 target;
|
|
||||||
union {
|
|
||||||
BitField<0, 1, u32> sample_mask;
|
|
||||||
BitField<1, 1, u32> depth;
|
|
||||||
BitField<2, 30, u32> reserved;
|
|
||||||
};
|
|
||||||
} omap;
|
|
||||||
|
|
||||||
bool IsColorComponentOutputEnabled(u32 render_target, u32 component) const {
|
|
||||||
const u32 bit = render_target * 4 + component;
|
|
||||||
return omap.target & (1 << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
PixelImap GetPixelImap(u32 attribute) const {
|
|
||||||
const auto get_index = [this, attribute](u32 index) {
|
|
||||||
return static_cast<PixelImap>(
|
|
||||||
(imap_generic_vector[attribute].raw >> (index * 2)) & 3);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::optional<PixelImap> result;
|
|
||||||
for (u32 component = 0; component < 4; ++component) {
|
|
||||||
const PixelImap index = get_index(component);
|
|
||||||
if (index == PixelImap::Unused) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (result && result != index) {
|
|
||||||
LOG_CRITICAL(HW_GPU, "Generic attribute conflict in interpolation mode");
|
|
||||||
}
|
|
||||||
result = index;
|
|
||||||
}
|
|
||||||
return result.value_or(PixelImap::Unused);
|
|
||||||
}
|
|
||||||
} ps;
|
|
||||||
|
|
||||||
std::array<u32, 0xF> raw;
|
|
||||||
};
|
|
||||||
|
|
||||||
u64 GetLocalMemorySize() const {
|
|
||||||
return (common1.shader_local_memory_low_size |
|
|
||||||
(common2.shader_local_memory_high_size << 24));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static_assert(sizeof(Header) == 0x50, "Incorrect structure size");
|
|
||||||
|
|
||||||
} // namespace Tegra::Shader
|
|
|
@ -4,6 +4,9 @@
|
||||||
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
|
#include <boost/container/small_vector.hpp>
|
||||||
|
|
||||||
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
#include "video_core/renderer_vulkan/vk_compute_pipeline.h"
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||||
|
@ -13,9 +16,142 @@
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
namespace {
|
||||||
|
vk::DescriptorSetLayout CreateDescriptorSetLayout(const Device& device, const Shader::Info& info) {
|
||||||
|
boost::container::small_vector<VkDescriptorSetLayoutBinding, 24> bindings;
|
||||||
|
u32 binding{};
|
||||||
|
for ([[maybe_unused]] const auto& desc : info.constant_buffer_descriptors) {
|
||||||
|
bindings.push_back({
|
||||||
|
.binding = binding,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
});
|
||||||
|
++binding;
|
||||||
|
}
|
||||||
|
for ([[maybe_unused]] const auto& desc : info.storage_buffers_descriptors) {
|
||||||
|
bindings.push_back({
|
||||||
|
.binding = binding,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.pImmutableSamplers = nullptr,
|
||||||
|
});
|
||||||
|
++binding;
|
||||||
|
}
|
||||||
|
return device.GetLogical().CreateDescriptorSetLayout({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.bindingCount = static_cast<u32>(bindings.size()),
|
||||||
|
.pBindings = bindings.data(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
ComputePipeline::ComputePipeline() = default;
|
vk::DescriptorUpdateTemplateKHR CreateDescriptorUpdateTemplate(
|
||||||
|
const Device& device, const Shader::Info& info, VkDescriptorSetLayout descriptor_set_layout,
|
||||||
|
VkPipelineLayout pipeline_layout) {
|
||||||
|
boost::container::small_vector<VkDescriptorUpdateTemplateEntry, 24> entries;
|
||||||
|
size_t offset{};
|
||||||
|
u32 binding{};
|
||||||
|
for ([[maybe_unused]] const auto& desc : info.constant_buffer_descriptors) {
|
||||||
|
entries.push_back({
|
||||||
|
.dstBinding = binding,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER,
|
||||||
|
.offset = offset,
|
||||||
|
.stride = sizeof(DescriptorUpdateEntry),
|
||||||
|
});
|
||||||
|
++binding;
|
||||||
|
offset += sizeof(DescriptorUpdateEntry);
|
||||||
|
}
|
||||||
|
for ([[maybe_unused]] const auto& desc : info.storage_buffers_descriptors) {
|
||||||
|
entries.push_back({
|
||||||
|
.dstBinding = binding,
|
||||||
|
.dstArrayElement = 0,
|
||||||
|
.descriptorCount = 1,
|
||||||
|
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
|
||||||
|
.offset = offset,
|
||||||
|
.stride = sizeof(DescriptorUpdateEntry),
|
||||||
|
});
|
||||||
|
++binding;
|
||||||
|
offset += sizeof(DescriptorUpdateEntry);
|
||||||
|
}
|
||||||
|
return device.GetLogical().CreateDescriptorUpdateTemplateKHR({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_UPDATE_TEMPLATE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.descriptorUpdateEntryCount = static_cast<u32>(entries.size()),
|
||||||
|
.pDescriptorUpdateEntries = entries.data(),
|
||||||
|
.templateType = VK_DESCRIPTOR_UPDATE_TEMPLATE_TYPE_DESCRIPTOR_SET,
|
||||||
|
.descriptorSetLayout = descriptor_set_layout,
|
||||||
|
.pipelineBindPoint = VK_PIPELINE_BIND_POINT_COMPUTE,
|
||||||
|
.pipelineLayout = pipeline_layout,
|
||||||
|
.set = 0,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} // Anonymous namespace
|
||||||
|
|
||||||
ComputePipeline::~ComputePipeline() = default;
|
ComputePipeline::ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool,
|
||||||
|
VKUpdateDescriptorQueue& update_descriptor_queue_,
|
||||||
|
const Shader::Info& info_, vk::ShaderModule spv_module_)
|
||||||
|
: update_descriptor_queue{&update_descriptor_queue_}, info{info_},
|
||||||
|
spv_module(std::move(spv_module_)),
|
||||||
|
descriptor_set_layout(CreateDescriptorSetLayout(device, info)),
|
||||||
|
descriptor_allocator(descriptor_pool, *descriptor_set_layout),
|
||||||
|
pipeline_layout{device.GetLogical().CreatePipelineLayout({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.setLayoutCount = 1,
|
||||||
|
.pSetLayouts = descriptor_set_layout.address(),
|
||||||
|
.pushConstantRangeCount = 0,
|
||||||
|
.pPushConstantRanges = nullptr,
|
||||||
|
})},
|
||||||
|
descriptor_update_template{
|
||||||
|
CreateDescriptorUpdateTemplate(device, info, *descriptor_set_layout, *pipeline_layout)},
|
||||||
|
pipeline{device.GetLogical().CreateComputePipeline({
|
||||||
|
.sType = VK_STRUCTURE_TYPE_COMPUTE_PIPELINE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.stage{
|
||||||
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||||
|
.pNext = nullptr,
|
||||||
|
.flags = 0,
|
||||||
|
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
|
||||||
|
.module = *spv_module,
|
||||||
|
.pName = "main",
|
||||||
|
.pSpecializationInfo = nullptr,
|
||||||
|
},
|
||||||
|
.layout = *pipeline_layout,
|
||||||
|
.basePipelineHandle = 0,
|
||||||
|
.basePipelineIndex = 0,
|
||||||
|
})} {}
|
||||||
|
|
||||||
|
void ComputePipeline::ConfigureBufferCache(BufferCache& buffer_cache) {
|
||||||
|
u32 enabled_uniforms{};
|
||||||
|
for (const auto& desc : info.constant_buffer_descriptors) {
|
||||||
|
enabled_uniforms |= ((1ULL << desc.count) - 1) << desc.index;
|
||||||
|
}
|
||||||
|
buffer_cache.SetEnabledComputeUniformBuffers(enabled_uniforms);
|
||||||
|
|
||||||
|
buffer_cache.UnbindComputeStorageBuffers();
|
||||||
|
size_t index{};
|
||||||
|
for (const auto& desc : info.storage_buffers_descriptors) {
|
||||||
|
ASSERT(desc.count == 1);
|
||||||
|
buffer_cache.BindComputeStorageBuffer(index, desc.cbuf_index, desc.cbuf_offset, true);
|
||||||
|
++index;
|
||||||
|
}
|
||||||
|
buffer_cache.UpdateComputeBuffers();
|
||||||
|
buffer_cache.BindHostComputeBuffers();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDescriptorSet ComputePipeline::UpdateDescriptorSet() {
|
||||||
|
const VkDescriptorSet descriptor_set{descriptor_allocator.Commit()};
|
||||||
|
update_descriptor_queue->Send(*descriptor_update_template, descriptor_set);
|
||||||
|
return descriptor_set;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -5,19 +5,52 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "shader_recompiler/shader_info.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_pipeline.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
class Device;
|
class Device;
|
||||||
class VKScheduler;
|
|
||||||
class VKUpdateDescriptorQueue;
|
|
||||||
|
|
||||||
class ComputePipeline {
|
class ComputePipeline : public Pipeline {
|
||||||
public:
|
public:
|
||||||
explicit ComputePipeline();
|
explicit ComputePipeline() = default;
|
||||||
~ComputePipeline();
|
explicit ComputePipeline(const Device& device, VKDescriptorPool& descriptor_pool,
|
||||||
|
VKUpdateDescriptorQueue& update_descriptor_queue,
|
||||||
|
const Shader::Info& info, vk::ShaderModule spv_module);
|
||||||
|
|
||||||
|
ComputePipeline& operator=(ComputePipeline&&) noexcept = default;
|
||||||
|
ComputePipeline(ComputePipeline&&) noexcept = default;
|
||||||
|
|
||||||
|
ComputePipeline& operator=(const ComputePipeline&) = delete;
|
||||||
|
ComputePipeline(const ComputePipeline&) = delete;
|
||||||
|
|
||||||
|
void ConfigureBufferCache(BufferCache& buffer_cache);
|
||||||
|
|
||||||
|
[[nodiscard]] VkDescriptorSet UpdateDescriptorSet();
|
||||||
|
|
||||||
|
[[nodiscard]] VkPipeline Handle() const noexcept {
|
||||||
|
return *pipeline;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] VkPipelineLayout PipelineLayout() const noexcept {
|
||||||
|
return *pipeline_layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
VKUpdateDescriptorQueue* update_descriptor_queue;
|
||||||
|
Shader::Info info;
|
||||||
|
|
||||||
|
vk::ShaderModule spv_module;
|
||||||
|
vk::DescriptorSetLayout descriptor_set_layout;
|
||||||
|
DescriptorAllocator descriptor_allocator;
|
||||||
|
vk::PipelineLayout pipeline_layout;
|
||||||
|
vk::DescriptorUpdateTemplateKHR descriptor_update_template;
|
||||||
|
vk::Pipeline pipeline;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -19,9 +19,7 @@ constexpr std::size_t SETS_GROW_RATE = 0x20;
|
||||||
DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_,
|
DescriptorAllocator::DescriptorAllocator(VKDescriptorPool& descriptor_pool_,
|
||||||
VkDescriptorSetLayout layout_)
|
VkDescriptorSetLayout layout_)
|
||||||
: ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE),
|
: ResourcePool(descriptor_pool_.master_semaphore, SETS_GROW_RATE),
|
||||||
descriptor_pool{descriptor_pool_}, layout{layout_} {}
|
descriptor_pool{&descriptor_pool_}, layout{layout_} {}
|
||||||
|
|
||||||
DescriptorAllocator::~DescriptorAllocator() = default;
|
|
||||||
|
|
||||||
VkDescriptorSet DescriptorAllocator::Commit() {
|
VkDescriptorSet DescriptorAllocator::Commit() {
|
||||||
const std::size_t index = CommitResource();
|
const std::size_t index = CommitResource();
|
||||||
|
@ -29,7 +27,7 @@ VkDescriptorSet DescriptorAllocator::Commit() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) {
|
void DescriptorAllocator::Allocate(std::size_t begin, std::size_t end) {
|
||||||
descriptors_allocations.push_back(descriptor_pool.AllocateDescriptors(layout, end - begin));
|
descriptors_allocations.push_back(descriptor_pool->AllocateDescriptors(layout, end - begin));
|
||||||
}
|
}
|
||||||
|
|
||||||
VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler)
|
VKDescriptorPool::VKDescriptorPool(const Device& device_, VKScheduler& scheduler)
|
||||||
|
|
|
@ -17,8 +17,12 @@ class VKScheduler;
|
||||||
|
|
||||||
class DescriptorAllocator final : public ResourcePool {
|
class DescriptorAllocator final : public ResourcePool {
|
||||||
public:
|
public:
|
||||||
|
explicit DescriptorAllocator() = default;
|
||||||
explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout);
|
explicit DescriptorAllocator(VKDescriptorPool& descriptor_pool, VkDescriptorSetLayout layout);
|
||||||
~DescriptorAllocator() override;
|
~DescriptorAllocator() override = default;
|
||||||
|
|
||||||
|
DescriptorAllocator& operator=(DescriptorAllocator&&) noexcept = default;
|
||||||
|
DescriptorAllocator(DescriptorAllocator&&) noexcept = default;
|
||||||
|
|
||||||
DescriptorAllocator& operator=(const DescriptorAllocator&) = delete;
|
DescriptorAllocator& operator=(const DescriptorAllocator&) = delete;
|
||||||
DescriptorAllocator(const DescriptorAllocator&) = delete;
|
DescriptorAllocator(const DescriptorAllocator&) = delete;
|
||||||
|
@ -29,8 +33,8 @@ protected:
|
||||||
void Allocate(std::size_t begin, std::size_t end) override;
|
void Allocate(std::size_t begin, std::size_t end) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VKDescriptorPool& descriptor_pool;
|
VKDescriptorPool* descriptor_pool{};
|
||||||
const VkDescriptorSetLayout layout;
|
VkDescriptorSetLayout layout{};
|
||||||
|
|
||||||
std::vector<vk::DescriptorSets> descriptors_allocations;
|
std::vector<vk::DescriptorSets> descriptors_allocations;
|
||||||
};
|
};
|
||||||
|
|
36
src/video_core/renderer_vulkan/vk_pipeline.h
Normal file
36
src/video_core/renderer_vulkan/vk_pipeline.h
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
// Copyright 2019 yuzu Emulator Project
|
||||||
|
// Licensed under GPLv2 or any later version
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
namespace Vulkan {
|
||||||
|
|
||||||
|
class Pipeline {
|
||||||
|
public:
|
||||||
|
/// Add a reference count to the pipeline
|
||||||
|
void AddRef() noexcept {
|
||||||
|
++ref_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] bool RemoveRef() noexcept {
|
||||||
|
--ref_count;
|
||||||
|
return ref_count == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] u64 UsageTick() const noexcept {
|
||||||
|
return usage_tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
u64 usage_tick{};
|
||||||
|
|
||||||
|
private:
|
||||||
|
size_t ref_count{};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace Vulkan
|
|
@ -12,6 +12,8 @@
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
#include "shader_recompiler/environment.h"
|
||||||
|
#include "shader_recompiler/recompiler.h"
|
||||||
#include "video_core/engines/kepler_compute.h"
|
#include "video_core/engines/kepler_compute.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/memory_manager.h"
|
#include "video_core/memory_manager.h"
|
||||||
|
@ -22,43 +24,105 @@
|
||||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_shader_util.h"
|
||||||
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
#include "video_core/renderer_vulkan/vk_update_descriptor.h"
|
||||||
#include "video_core/shader_cache.h"
|
#include "video_core/shader_cache.h"
|
||||||
#include "video_core/shader_notify.h"
|
#include "video_core/shader_notify.h"
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
#pragma optimize("", off)
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
MICROPROFILE_DECLARE(Vulkan_PipelineCache);
|
MICROPROFILE_DECLARE(Vulkan_PipelineCache);
|
||||||
|
|
||||||
using Tegra::Engines::ShaderType;
|
using Tegra::Engines::ShaderType;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
size_t StageFromProgram(size_t program) {
|
class Environment final : public Shader::Environment {
|
||||||
return program == 0 ? 0 : program - 1;
|
public:
|
||||||
|
explicit Environment(Tegra::Engines::KeplerCompute& kepler_compute_,
|
||||||
|
Tegra::MemoryManager& gpu_memory_, GPUVAddr program_base_)
|
||||||
|
: kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, program_base{program_base_} {}
|
||||||
|
|
||||||
|
~Environment() override = default;
|
||||||
|
|
||||||
|
[[nodiscard]] std::optional<u128> Analyze(u32 start_address) {
|
||||||
|
const std::optional<u64> size{TryFindSize(start_address)};
|
||||||
|
if (!size) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
cached_lowest = start_address;
|
||||||
|
cached_highest = start_address + static_cast<u32>(*size);
|
||||||
|
return Common::CityHash128(reinterpret_cast<const char*>(code.data()), code.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderType StageFromProgram(Maxwell::ShaderProgram program) {
|
[[nodiscard]] size_t ShaderSize() const noexcept {
|
||||||
return static_cast<ShaderType>(StageFromProgram(static_cast<size_t>(program)));
|
return read_highest - read_lowest + INST_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ShaderType GetShaderType(Maxwell::ShaderProgram program) {
|
[[nodiscard]] u128 ComputeHash() const {
|
||||||
switch (program) {
|
const size_t size{ShaderSize()};
|
||||||
case Maxwell::ShaderProgram::VertexB:
|
auto data = std::make_unique<u64[]>(size);
|
||||||
return ShaderType::Vertex;
|
gpu_memory.ReadBlock(program_base + read_lowest, data.get(), size);
|
||||||
case Maxwell::ShaderProgram::TesselationControl:
|
return Common::CityHash128(reinterpret_cast<const char*>(data.get()), size);
|
||||||
return ShaderType::TesselationControl;
|
}
|
||||||
case Maxwell::ShaderProgram::TesselationEval:
|
|
||||||
return ShaderType::TesselationEval;
|
u64 ReadInstruction(u32 address) override {
|
||||||
case Maxwell::ShaderProgram::Geometry:
|
read_lowest = std::min(read_lowest, address);
|
||||||
return ShaderType::Geometry;
|
read_highest = std::max(read_highest, address);
|
||||||
case Maxwell::ShaderProgram::Fragment:
|
|
||||||
return ShaderType::Fragment;
|
if (address >= cached_lowest && address < cached_highest) {
|
||||||
default:
|
return code[address / INST_SIZE];
|
||||||
UNIMPLEMENTED_MSG("program={}", program);
|
}
|
||||||
return ShaderType::Vertex;
|
return gpu_memory.Read<u64>(program_base + address);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<u32, 3> WorkgroupSize() override {
|
||||||
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
|
return {qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z};
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static constexpr size_t INST_SIZE = sizeof(u64);
|
||||||
|
static constexpr size_t BLOCK_SIZE = 0x1000;
|
||||||
|
static constexpr size_t MAXIMUM_SIZE = 0x100000;
|
||||||
|
|
||||||
|
static constexpr u64 SELF_BRANCH_A = 0xE2400FFFFF87000FULL;
|
||||||
|
static constexpr u64 SELF_BRANCH_B = 0xE2400FFFFF07000FULL;
|
||||||
|
|
||||||
|
std::optional<u64> TryFindSize(u32 start_address) {
|
||||||
|
GPUVAddr guest_addr = program_base + start_address;
|
||||||
|
size_t offset = 0;
|
||||||
|
size_t size = BLOCK_SIZE;
|
||||||
|
while (size <= MAXIMUM_SIZE) {
|
||||||
|
code.resize(size / INST_SIZE);
|
||||||
|
u64* const data = code.data() + offset / INST_SIZE;
|
||||||
|
gpu_memory.ReadBlock(guest_addr, data, BLOCK_SIZE);
|
||||||
|
for (size_t i = 0; i < BLOCK_SIZE; i += INST_SIZE) {
|
||||||
|
const u64 inst = data[i / INST_SIZE];
|
||||||
|
if (inst == SELF_BRANCH_A || inst == SELF_BRANCH_B) {
|
||||||
|
return offset + i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
guest_addr += BLOCK_SIZE;
|
||||||
|
size += BLOCK_SIZE;
|
||||||
|
offset += BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
Tegra::Engines::KeplerCompute& kepler_compute;
|
||||||
|
Tegra::MemoryManager& gpu_memory;
|
||||||
|
GPUVAddr program_base;
|
||||||
|
|
||||||
|
u32 read_lowest = 0;
|
||||||
|
u32 read_highest = 0;
|
||||||
|
|
||||||
|
std::vector<u64> code;
|
||||||
|
u32 cached_lowest = std::numeric_limits<u32>::max();
|
||||||
|
u32 cached_highest = 0;
|
||||||
|
};
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
size_t ComputePipelineCacheKey::Hash() const noexcept {
|
size_t ComputePipelineCacheKey::Hash() const noexcept {
|
||||||
|
@ -70,35 +134,91 @@ bool ComputePipelineCacheKey::operator==(const ComputePipelineCacheKey& rhs) con
|
||||||
return std::memcmp(&rhs, this, sizeof *this) == 0;
|
return std::memcmp(&rhs, this, sizeof *this) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
Shader::Shader() = default;
|
|
||||||
|
|
||||||
Shader::~Shader() = default;
|
|
||||||
|
|
||||||
PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_,
|
PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::GPU& gpu_,
|
||||||
Tegra::Engines::Maxwell3D& maxwell3d_,
|
Tegra::Engines::Maxwell3D& maxwell3d_,
|
||||||
Tegra::Engines::KeplerCompute& kepler_compute_,
|
Tegra::Engines::KeplerCompute& kepler_compute_,
|
||||||
Tegra::MemoryManager& gpu_memory_, const Device& device_,
|
Tegra::MemoryManager& gpu_memory_, const Device& device_,
|
||||||
VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
|
VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_,
|
||||||
VKUpdateDescriptorQueue& update_descriptor_queue_)
|
VKUpdateDescriptorQueue& update_descriptor_queue_)
|
||||||
: VideoCommon::ShaderCache<Shader>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_},
|
: VideoCommon::ShaderCache<ShaderInfo>{rasterizer_}, gpu{gpu_}, maxwell3d{maxwell3d_},
|
||||||
kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
|
kepler_compute{kepler_compute_}, gpu_memory{gpu_memory_}, device{device_},
|
||||||
scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{
|
scheduler{scheduler_}, descriptor_pool{descriptor_pool_}, update_descriptor_queue{
|
||||||
update_descriptor_queue_} {}
|
update_descriptor_queue_} {}
|
||||||
|
|
||||||
PipelineCache::~PipelineCache() = default;
|
PipelineCache::~PipelineCache() = default;
|
||||||
|
|
||||||
ComputePipeline& PipelineCache::GetComputePipeline(const ComputePipelineCacheKey& key) {
|
ComputePipeline* PipelineCache::CurrentComputePipeline() {
|
||||||
MICROPROFILE_SCOPE(Vulkan_PipelineCache);
|
MICROPROFILE_SCOPE(Vulkan_PipelineCache);
|
||||||
|
|
||||||
const auto [pair, is_cache_miss] = compute_cache.try_emplace(key);
|
const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()};
|
||||||
auto& entry = pair->second;
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
if (!is_cache_miss) {
|
const GPUVAddr shader_addr{program_base + qmd.program_start};
|
||||||
return *entry;
|
const std::optional<VAddr> cpu_shader_addr{gpu_memory.GpuToCpuAddress(shader_addr)};
|
||||||
|
if (!cpu_shader_addr) {
|
||||||
|
return nullptr;
|
||||||
}
|
}
|
||||||
LOG_INFO(Render_Vulkan, "Compile 0x{:016X}", key.Hash());
|
ShaderInfo* const shader{TryGet(*cpu_shader_addr)};
|
||||||
throw "Bad";
|
if (!shader) {
|
||||||
|
return CreateComputePipelineWithoutShader(*cpu_shader_addr);
|
||||||
|
}
|
||||||
|
const ComputePipelineCacheKey key{MakeComputePipelineKey(shader->unique_hash)};
|
||||||
|
const auto [pair, is_new]{compute_cache.try_emplace(key)};
|
||||||
|
auto& pipeline{pair->second};
|
||||||
|
if (!is_new) {
|
||||||
|
return &pipeline;
|
||||||
|
}
|
||||||
|
pipeline = CreateComputePipeline(shader);
|
||||||
|
shader->compute_users.push_back(key);
|
||||||
|
return &pipeline;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PipelineCache::OnShaderRemoval(Shader*) {}
|
ComputePipeline PipelineCache::CreateComputePipeline(ShaderInfo* shader_info) {
|
||||||
|
const GPUVAddr program_base{kepler_compute.regs.code_loc.Address()};
|
||||||
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
|
Environment env{kepler_compute, gpu_memory, program_base};
|
||||||
|
if (const std::optional<u128> cached_hash{env.Analyze(qmd.program_start)}) {
|
||||||
|
// TODO: Load from cache
|
||||||
|
}
|
||||||
|
const auto [info, code]{Shader::RecompileSPIRV(env, qmd.program_start)};
|
||||||
|
shader_info->unique_hash = env.ComputeHash();
|
||||||
|
shader_info->size_bytes = env.ShaderSize();
|
||||||
|
return ComputePipeline{device, descriptor_pool, update_descriptor_queue, info,
|
||||||
|
BuildShader(device, code)};
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputePipeline* PipelineCache::CreateComputePipelineWithoutShader(VAddr shader_cpu_addr) {
|
||||||
|
ShaderInfo shader;
|
||||||
|
ComputePipeline pipeline{CreateComputePipeline(&shader)};
|
||||||
|
const ComputePipelineCacheKey key{MakeComputePipelineKey(shader.unique_hash)};
|
||||||
|
shader.compute_users.push_back(key);
|
||||||
|
pipeline.AddRef();
|
||||||
|
|
||||||
|
const size_t size_bytes{shader.size_bytes};
|
||||||
|
Register(std::make_unique<ShaderInfo>(std::move(shader)), shader_cpu_addr, size_bytes);
|
||||||
|
return &compute_cache.emplace(key, std::move(pipeline)).first->second;
|
||||||
|
}
|
||||||
|
|
||||||
|
ComputePipelineCacheKey PipelineCache::MakeComputePipelineKey(u128 unique_hash) const {
|
||||||
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
|
return {
|
||||||
|
.unique_hash = unique_hash,
|
||||||
|
.shared_memory_size = qmd.shared_alloc,
|
||||||
|
.workgroup_size{qmd.block_dim_x, qmd.block_dim_y, qmd.block_dim_z},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void PipelineCache::OnShaderRemoval(ShaderInfo* shader) {
|
||||||
|
for (const ComputePipelineCacheKey& key : shader->compute_users) {
|
||||||
|
const auto it = compute_cache.find(key);
|
||||||
|
ASSERT(it != compute_cache.end());
|
||||||
|
|
||||||
|
Pipeline& pipeline = it->second;
|
||||||
|
if (pipeline.RemoveRef()) {
|
||||||
|
// Wait for the pipeline to be free of GPU usage before destroying it
|
||||||
|
scheduler.Wait(pipeline.UsageTick());
|
||||||
|
compute_cache.erase(it);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -36,7 +36,7 @@ class VKUpdateDescriptorQueue;
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
struct ComputePipelineCacheKey {
|
struct ComputePipelineCacheKey {
|
||||||
GPUVAddr shader;
|
u128 unique_hash;
|
||||||
u32 shared_memory_size;
|
u32 shared_memory_size;
|
||||||
std::array<u32, 3> workgroup_size;
|
std::array<u32, 3> workgroup_size;
|
||||||
|
|
||||||
|
@ -67,13 +67,13 @@ struct hash<Vulkan::ComputePipelineCacheKey> {
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
class Shader {
|
struct ShaderInfo {
|
||||||
public:
|
u128 unique_hash{};
|
||||||
explicit Shader();
|
size_t size_bytes{};
|
||||||
~Shader();
|
std::vector<ComputePipelineCacheKey> compute_users;
|
||||||
};
|
};
|
||||||
|
|
||||||
class PipelineCache final : public VideoCommon::ShaderCache<Shader> {
|
class PipelineCache final : public VideoCommon::ShaderCache<ShaderInfo> {
|
||||||
public:
|
public:
|
||||||
explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
|
explicit PipelineCache(RasterizerVulkan& rasterizer, Tegra::GPU& gpu,
|
||||||
Tegra::Engines::Maxwell3D& maxwell3d,
|
Tegra::Engines::Maxwell3D& maxwell3d,
|
||||||
|
@ -83,12 +83,18 @@ public:
|
||||||
VKUpdateDescriptorQueue& update_descriptor_queue);
|
VKUpdateDescriptorQueue& update_descriptor_queue);
|
||||||
~PipelineCache() override;
|
~PipelineCache() override;
|
||||||
|
|
||||||
ComputePipeline& GetComputePipeline(const ComputePipelineCacheKey& key);
|
[[nodiscard]] ComputePipeline* CurrentComputePipeline();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void OnShaderRemoval(Shader* shader) final;
|
void OnShaderRemoval(ShaderInfo* shader) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
ComputePipeline CreateComputePipeline(ShaderInfo* shader);
|
||||||
|
|
||||||
|
ComputePipeline* CreateComputePipelineWithoutShader(VAddr shader_cpu_addr);
|
||||||
|
|
||||||
|
ComputePipelineCacheKey MakeComputePipelineKey(u128 unique_hash) const;
|
||||||
|
|
||||||
Tegra::GPU& gpu;
|
Tegra::GPU& gpu;
|
||||||
Tegra::Engines::Maxwell3D& maxwell3d;
|
Tegra::Engines::Maxwell3D& maxwell3d;
|
||||||
Tegra::Engines::KeplerCompute& kepler_compute;
|
Tegra::Engines::KeplerCompute& kepler_compute;
|
||||||
|
@ -99,13 +105,7 @@ private:
|
||||||
VKDescriptorPool& descriptor_pool;
|
VKDescriptorPool& descriptor_pool;
|
||||||
VKUpdateDescriptorQueue& update_descriptor_queue;
|
VKUpdateDescriptorQueue& update_descriptor_queue;
|
||||||
|
|
||||||
std::unique_ptr<Shader> null_shader;
|
std::unordered_map<ComputePipelineCacheKey, ComputePipeline> compute_cache;
|
||||||
std::unique_ptr<Shader> null_kernel;
|
|
||||||
|
|
||||||
std::array<Shader*, Maxwell::MaxShaderProgram> last_shaders{};
|
|
||||||
|
|
||||||
std::mutex pipeline_cache;
|
|
||||||
std::unordered_map<ComputePipelineCacheKey, std::unique_ptr<ComputePipeline>> compute_cache;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace Vulkan
|
} // namespace Vulkan
|
||||||
|
|
|
@ -36,6 +36,8 @@
|
||||||
#include "video_core/vulkan_common/vulkan_device.h"
|
#include "video_core/vulkan_common/vulkan_device.h"
|
||||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||||
|
|
||||||
|
#pragma optimize("", off)
|
||||||
|
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
@ -237,7 +239,26 @@ void RasterizerVulkan::Clear() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::DispatchCompute() {
|
void RasterizerVulkan::DispatchCompute() {
|
||||||
UNREACHABLE_MSG("Not implemented");
|
ComputePipeline* const pipeline{pipeline_cache.CurrentComputePipeline()};
|
||||||
|
if (!pipeline) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
std::scoped_lock lock{buffer_cache.mutex};
|
||||||
|
update_descriptor_queue.Acquire();
|
||||||
|
pipeline->ConfigureBufferCache(buffer_cache);
|
||||||
|
const VkDescriptorSet descriptor_set{pipeline->UpdateDescriptorSet()};
|
||||||
|
|
||||||
|
const auto& qmd{kepler_compute.launch_description};
|
||||||
|
const std::array<u32, 3> dim{qmd.grid_dim_x, qmd.grid_dim_y, qmd.grid_dim_z};
|
||||||
|
const VkPipeline pipeline_handle{pipeline->Handle()};
|
||||||
|
const VkPipelineLayout pipeline_layout{pipeline->PipelineLayout()};
|
||||||
|
scheduler.Record(
|
||||||
|
[pipeline_handle, pipeline_layout, dim, descriptor_set](vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_handle);
|
||||||
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline_layout, 0,
|
||||||
|
descriptor_set, nullptr);
|
||||||
|
cmdbuf.Dispatch(dim[0], dim[1], dim[2]);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) {
|
void RasterizerVulkan::ResetCounter(VideoCore::QueryType type) {
|
||||||
|
|
|
@ -21,7 +21,6 @@
|
||||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||||
#include "video_core/renderer_vulkan/vk_fence_manager.h"
|
#include "video_core/renderer_vulkan/vk_fence_manager.h"
|
||||||
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
|
||||||
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_query_cache.h"
|
#include "video_core/renderer_vulkan/vk_query_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
|
@ -150,8 +149,6 @@ private:
|
||||||
BlitImageHelper blit_image;
|
BlitImageHelper blit_image;
|
||||||
ASTCDecoderPass astc_decoder_pass;
|
ASTCDecoderPass astc_decoder_pass;
|
||||||
|
|
||||||
GraphicsPipelineCacheKey graphics_key;
|
|
||||||
|
|
||||||
TextureCacheRuntime texture_cache_runtime;
|
TextureCacheRuntime texture_cache_runtime;
|
||||||
TextureCache texture_cache;
|
TextureCache texture_cache;
|
||||||
BufferCacheRuntime buffer_cache_runtime;
|
BufferCacheRuntime buffer_cache_runtime;
|
||||||
|
|
|
@ -10,18 +10,16 @@
|
||||||
namespace Vulkan {
|
namespace Vulkan {
|
||||||
|
|
||||||
ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_)
|
ResourcePool::ResourcePool(MasterSemaphore& master_semaphore_, size_t grow_step_)
|
||||||
: master_semaphore{master_semaphore_}, grow_step{grow_step_} {}
|
: master_semaphore{&master_semaphore_}, grow_step{grow_step_} {}
|
||||||
|
|
||||||
ResourcePool::~ResourcePool() = default;
|
|
||||||
|
|
||||||
size_t ResourcePool::CommitResource() {
|
size_t ResourcePool::CommitResource() {
|
||||||
// Refresh semaphore to query updated results
|
// Refresh semaphore to query updated results
|
||||||
master_semaphore.Refresh();
|
master_semaphore->Refresh();
|
||||||
const u64 gpu_tick = master_semaphore.KnownGpuTick();
|
const u64 gpu_tick = master_semaphore->KnownGpuTick();
|
||||||
const auto search = [this, gpu_tick](size_t begin, size_t end) -> std::optional<size_t> {
|
const auto search = [this, gpu_tick](size_t begin, size_t end) -> std::optional<size_t> {
|
||||||
for (size_t iterator = begin; iterator < end; ++iterator) {
|
for (size_t iterator = begin; iterator < end; ++iterator) {
|
||||||
if (gpu_tick >= ticks[iterator]) {
|
if (gpu_tick >= ticks[iterator]) {
|
||||||
ticks[iterator] = master_semaphore.CurrentTick();
|
ticks[iterator] = master_semaphore->CurrentTick();
|
||||||
return iterator;
|
return iterator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -36,7 +34,7 @@ size_t ResourcePool::CommitResource() {
|
||||||
// Both searches failed, the pool is full; handle it.
|
// Both searches failed, the pool is full; handle it.
|
||||||
const size_t free_resource = ManageOverflow();
|
const size_t free_resource = ManageOverflow();
|
||||||
|
|
||||||
ticks[free_resource] = master_semaphore.CurrentTick();
|
ticks[free_resource] = master_semaphore->CurrentTick();
|
||||||
found = free_resource;
|
found = free_resource;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,8 +18,16 @@ class MasterSemaphore;
|
||||||
*/
|
*/
|
||||||
class ResourcePool {
|
class ResourcePool {
|
||||||
public:
|
public:
|
||||||
|
explicit ResourcePool() = default;
|
||||||
explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step);
|
explicit ResourcePool(MasterSemaphore& master_semaphore, size_t grow_step);
|
||||||
virtual ~ResourcePool();
|
|
||||||
|
virtual ~ResourcePool() = default;
|
||||||
|
|
||||||
|
ResourcePool& operator=(ResourcePool&&) noexcept = default;
|
||||||
|
ResourcePool(ResourcePool&&) noexcept = default;
|
||||||
|
|
||||||
|
ResourcePool& operator=(const ResourcePool&) = default;
|
||||||
|
ResourcePool(const ResourcePool&) = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
size_t CommitResource();
|
size_t CommitResource();
|
||||||
|
@ -34,7 +42,7 @@ private:
|
||||||
/// Allocates a new page of resources.
|
/// Allocates a new page of resources.
|
||||||
void Grow();
|
void Grow();
|
||||||
|
|
||||||
MasterSemaphore& master_semaphore;
|
MasterSemaphore* master_semaphore{};
|
||||||
size_t grow_step = 0; ///< Number of new resources created after an overflow
|
size_t grow_step = 0; ///< Number of new resources created after an overflow
|
||||||
size_t hint_iterator = 0; ///< Hint to where the next free resources is likely to be found
|
size_t hint_iterator = 0; ///< Hint to where the next free resources is likely to be found
|
||||||
std::vector<u64> ticks; ///< Ticks for each resource
|
std::vector<u64> ticks; ///< Ticks for each resource
|
||||||
|
|
Loading…
Reference in a new issue