2021-02-08 05:54:35 +00:00
|
|
|
// Copyright 2021 yuzu Emulator Project
|
|
|
|
// Licensed under GPLv2 or any later version
|
|
|
|
// Refer to the license.txt file included.
|
|
|
|
|
2021-02-16 07:10:22 +00:00
|
|
|
#include <bit>
|
|
|
|
|
2021-02-08 05:54:35 +00:00
|
|
|
#include "shader_recompiler/backend/spirv/emit_spirv.h"
|
|
|
|
|
|
|
|
namespace Shader::Backend::SPIRV {
|
2021-03-20 22:11:56 +00:00
|
|
|
namespace {
|
|
|
|
Id StorageIndex(EmitContext& ctx, const IR::Value& offset, size_t element_size) {
|
2021-02-16 07:10:22 +00:00
|
|
|
if (offset.IsImmediate()) {
|
|
|
|
const u32 imm_offset{static_cast<u32>(offset.U32() / element_size)};
|
2021-04-19 01:47:31 +01:00
|
|
|
return ctx.Const(imm_offset);
|
2021-02-16 07:10:22 +00:00
|
|
|
}
|
|
|
|
const u32 shift{static_cast<u32>(std::countr_zero(element_size))};
|
|
|
|
const Id index{ctx.Def(offset)};
|
|
|
|
if (shift == 0) {
|
|
|
|
return index;
|
|
|
|
}
|
2021-04-19 01:47:31 +01:00
|
|
|
const Id shift_id{ctx.Const(shift)};
|
2021-02-16 07:10:22 +00:00
|
|
|
return ctx.OpShiftRightLogical(ctx.U32[1], index, shift_id);
|
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
Id StoragePointer(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
const StorageTypeDefinition& type_def, size_t element_size,
|
|
|
|
Id StorageDefinitions::*member_ptr) {
|
2021-03-20 22:11:56 +00:00
|
|
|
if (!binding.IsImmediate()) {
|
|
|
|
throw NotImplementedException("Dynamic storage buffer indexing");
|
|
|
|
}
|
2021-04-13 09:32:21 +01:00
|
|
|
const Id ssbo{ctx.ssbos[binding.U32()].*member_ptr};
|
|
|
|
const Id index{StorageIndex(ctx, offset, element_size)};
|
|
|
|
return ctx.OpAccessChain(type_def.element, ssbo, ctx.u32_zero_value, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
Id LoadStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id result_type,
|
|
|
|
const StorageTypeDefinition& type_def, size_t element_size,
|
|
|
|
Id StorageDefinitions::*member_ptr) {
|
|
|
|
const Id pointer{StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr)};
|
|
|
|
return ctx.OpLoad(result_type, pointer);
|
|
|
|
}
|
|
|
|
|
|
|
|
void WriteStorage(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset, Id value,
|
|
|
|
const StorageTypeDefinition& type_def, size_t element_size,
|
|
|
|
Id StorageDefinitions::*member_ptr) {
|
|
|
|
const Id pointer{StoragePointer(ctx, binding, offset, type_def, element_size, member_ptr)};
|
|
|
|
ctx.OpStore(pointer, value);
|
2021-03-20 22:11:56 +00:00
|
|
|
}
|
|
|
|
} // Anonymous namespace
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitLoadGlobalU8(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitLoadGlobalS8(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitLoadGlobalU16(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitLoadGlobalS16(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
Id EmitLoadGlobal32(EmitContext& ctx, Id address) {
|
|
|
|
return ctx.OpFunctionCall(ctx.U32[1], ctx.load_global_func_u32, address);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
Id EmitLoadGlobal64(EmitContext& ctx, Id address) {
|
|
|
|
return ctx.OpFunctionCall(ctx.U32[2], ctx.load_global_func_u32x2, address);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
Id EmitLoadGlobal128(EmitContext& ctx, Id address) {
|
|
|
|
return ctx.OpFunctionCall(ctx.U32[4], ctx.load_global_func_u32x4, address);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitWriteGlobalU8(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitWriteGlobalS8(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitWriteGlobalU16(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-02-17 03:59:28 +00:00
|
|
|
void EmitWriteGlobalS16(EmitContext&) {
|
2021-02-08 05:54:35 +00:00
|
|
|
throw NotImplementedException("SPIR-V Instruction");
|
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
void EmitWriteGlobal32(EmitContext& ctx, Id address, Id value) {
|
|
|
|
ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32, address, value);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
void EmitWriteGlobal64(EmitContext& ctx, Id address, Id value) {
|
|
|
|
ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32x2, address, value);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-19 20:33:23 +01:00
|
|
|
void EmitWriteGlobal128(EmitContext& ctx, Id address, Id value) {
|
|
|
|
ctx.OpFunctionCall(ctx.void_id, ctx.write_global_func_u32x4, address, value);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
Id EmitLoadStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
|
|
|
return ctx.OpUConvert(ctx.U32[1],
|
|
|
|
LoadStorage(ctx, binding, offset, ctx.U8, ctx.storage_types.U8,
|
|
|
|
sizeof(u8), &StorageDefinitions::U8));
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
Id EmitLoadStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
|
|
|
return ctx.OpSConvert(ctx.U32[1],
|
|
|
|
LoadStorage(ctx, binding, offset, ctx.S8, ctx.storage_types.S8,
|
|
|
|
sizeof(s8), &StorageDefinitions::S8));
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
Id EmitLoadStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
|
|
|
return ctx.OpUConvert(ctx.U32[1],
|
|
|
|
LoadStorage(ctx, binding, offset, ctx.U16, ctx.storage_types.U16,
|
|
|
|
sizeof(u16), &StorageDefinitions::U16));
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
Id EmitLoadStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
|
|
|
return ctx.OpSConvert(ctx.U32[1],
|
|
|
|
LoadStorage(ctx, binding, offset, ctx.S16, ctx.storage_types.S16,
|
|
|
|
sizeof(s16), &StorageDefinitions::S16));
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 21:10:18 +00:00
|
|
|
Id EmitLoadStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
2021-04-13 09:32:21 +01:00
|
|
|
return LoadStorage(ctx, binding, offset, ctx.U32[1], ctx.storage_types.U32, sizeof(u32),
|
|
|
|
&StorageDefinitions::U32);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 22:11:56 +00:00
|
|
|
Id EmitLoadStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
2021-04-13 09:32:21 +01:00
|
|
|
return LoadStorage(ctx, binding, offset, ctx.U32[2], ctx.storage_types.U32x2, sizeof(u32[2]),
|
|
|
|
&StorageDefinitions::U32x2);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-20 22:11:56 +00:00
|
|
|
Id EmitLoadStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset) {
|
2021-04-13 09:32:21 +01:00
|
|
|
return LoadStorage(ctx, binding, offset, ctx.U32[4], ctx.storage_types.U32x4, sizeof(u32[4]),
|
|
|
|
&StorageDefinitions::U32x4);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
void EmitWriteStorageU8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
|
|
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U8, value), ctx.storage_types.U8,
|
|
|
|
sizeof(u8), &StorageDefinitions::U8);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
void EmitWriteStorageS8(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
|
|
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S8, value), ctx.storage_types.S8,
|
|
|
|
sizeof(s8), &StorageDefinitions::S8);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
void EmitWriteStorageU16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
|
|
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.U16, value), ctx.storage_types.U16,
|
|
|
|
sizeof(u16), &StorageDefinitions::U16);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-04-13 09:32:21 +01:00
|
|
|
void EmitWriteStorageS16(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
|
|
|
WriteStorage(ctx, binding, offset, ctx.OpSConvert(ctx.S16, value), ctx.storage_types.S16,
|
|
|
|
sizeof(s16), &StorageDefinitions::S16);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 21:10:18 +00:00
|
|
|
void EmitWriteStorage32(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
2021-04-13 09:32:21 +01:00
|
|
|
WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32, sizeof(u32),
|
|
|
|
&StorageDefinitions::U32);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-02-19 21:10:18 +00:00
|
|
|
void EmitWriteStorage64(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
2021-04-13 09:32:21 +01:00
|
|
|
WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x2, sizeof(u32[2]),
|
|
|
|
&StorageDefinitions::U32x2);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
2021-03-08 21:31:53 +00:00
|
|
|
void EmitWriteStorage128(EmitContext& ctx, const IR::Value& binding, const IR::Value& offset,
|
|
|
|
Id value) {
|
2021-04-13 09:32:21 +01:00
|
|
|
WriteStorage(ctx, binding, offset, value, ctx.storage_types.U32x4, sizeof(u32[4]),
|
|
|
|
&StorageDefinitions::U32x4);
|
2021-02-08 05:54:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Shader::Backend::SPIRV
|