Skip to content

Commit 8aaa6f1

Browse files
committed
[SPIR-V] Wrap 4-operand ops and 1-3-operand GLSL std calls
1 parent 19d5600 commit 8aaa6f1

File tree

7 files changed

+721
-947
lines changed

7 files changed

+721
-947
lines changed

src/xenia/gpu/spirv_builder.cc

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/**
2+
******************************************************************************
3+
* Xenia : Xbox 360 Emulator Research Project *
4+
******************************************************************************
5+
* Copyright 2023 Ben Vanik. All rights reserved. *
6+
* Released under the BSD license - see LICENSE in the root for more details. *
7+
******************************************************************************
8+
*/
9+
10+
#include "xenia/gpu/spirv_builder.h"
11+
12+
#include <memory>
13+
#include <utility>
14+
#include <vector>
15+
16+
namespace xe {
17+
namespace gpu {
18+
19+
spv::Id SpirvBuilder::createQuadOp(spv::Op op_code, spv::Id type_id,
20+
spv::Id operand1, spv::Id operand2,
21+
spv::Id operand3, spv::Id operand4) {
22+
if (generatingOpCodeForSpecConst) {
23+
std::vector<spv::Id> operands(4);
24+
operands[0] = operand1;
25+
operands[1] = operand2;
26+
operands[2] = operand3;
27+
operands[3] = operand4;
28+
return createSpecConstantOp(op_code, type_id, operands,
29+
std::vector<spv::Id>());
30+
}
31+
std::unique_ptr<spv::Instruction> op =
32+
std::make_unique<spv::Instruction>(getUniqueId(), type_id, op_code);
33+
op->addIdOperand(operand1);
34+
op->addIdOperand(operand2);
35+
op->addIdOperand(operand3);
36+
op->addIdOperand(operand4);
37+
spv::Id result = op->getResultId();
38+
buildPoint->addInstruction(std::move(op));
39+
return result;
40+
}
41+
42+
spv::Id SpirvBuilder::createNoContractionUnaryOp(spv::Op op_code,
43+
spv::Id type_id,
44+
spv::Id operand) {
45+
spv::Id result = createUnaryOp(op_code, type_id, operand);
46+
addDecoration(result, spv::DecorationNoContraction);
47+
return result;
48+
}
49+
50+
spv::Id SpirvBuilder::createNoContractionBinOp(spv::Op op_code, spv::Id type_id,
51+
spv::Id operand1,
52+
spv::Id operand2) {
53+
spv::Id result = createBinOp(op_code, type_id, operand1, operand2);
54+
addDecoration(result, spv::DecorationNoContraction);
55+
return result;
56+
}
57+
58+
spv::Id SpirvBuilder::createUnaryBuiltinCall(spv::Id result_type,
59+
spv::Id builtins, int entry_point,
60+
spv::Id operand) {
61+
std::unique_ptr<spv::Instruction> instruction =
62+
std::make_unique<spv::Instruction>(getUniqueId(), result_type,
63+
spv::OpExtInst);
64+
instruction->addIdOperand(builtins);
65+
instruction->addImmediateOperand(entry_point);
66+
instruction->addIdOperand(operand);
67+
spv::Id result = instruction->getResultId();
68+
getBuildPoint()->addInstruction(std::move(instruction));
69+
return result;
70+
}
71+
72+
spv::Id SpirvBuilder::createBinBuiltinCall(spv::Id result_type,
73+
spv::Id builtins, int entry_point,
74+
spv::Id operand1, spv::Id operand2) {
75+
std::unique_ptr<spv::Instruction> instruction =
76+
std::make_unique<spv::Instruction>(getUniqueId(), result_type,
77+
spv::OpExtInst);
78+
instruction->addIdOperand(builtins);
79+
instruction->addImmediateOperand(entry_point);
80+
instruction->addIdOperand(operand1);
81+
instruction->addIdOperand(operand2);
82+
spv::Id result = instruction->getResultId();
83+
getBuildPoint()->addInstruction(std::move(instruction));
84+
return result;
85+
}
86+
87+
spv::Id SpirvBuilder::createTriBuiltinCall(spv::Id result_type,
88+
spv::Id builtins, int entry_point,
89+
spv::Id operand1, spv::Id operand2,
90+
spv::Id operand3) {
91+
std::unique_ptr<spv::Instruction> instruction =
92+
std::make_unique<spv::Instruction>(getUniqueId(), result_type,
93+
spv::OpExtInst);
94+
instruction->addIdOperand(builtins);
95+
instruction->addImmediateOperand(entry_point);
96+
instruction->addIdOperand(operand1);
97+
instruction->addIdOperand(operand2);
98+
instruction->addIdOperand(operand3);
99+
spv::Id result = instruction->getResultId();
100+
getBuildPoint()->addInstruction(std::move(instruction));
101+
return result;
102+
}
103+
104+
} // namespace gpu
105+
} // namespace xe

src/xenia/gpu/spirv_builder.h

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,19 +26,22 @@ class SpirvBuilder : public spv::Builder {
2626
// Make public rather than protected.
2727
using spv::Builder::createSelectionMerge;
2828

29-
spv::Id createNoContractionUnaryOp(spv::Op op_code, spv::Id type_id,
30-
spv::Id operand) {
31-
spv::Id result = createUnaryOp(op_code, type_id, operand);
32-
addDecoration(result, spv::DecorationNoContraction);
33-
return result;
34-
}
29+
spv::Id createQuadOp(spv::Op op_code, spv::Id type_id, spv::Id operand1,
30+
spv::Id operand2, spv::Id operand3, spv::Id operand4);
3531

32+
spv::Id createNoContractionUnaryOp(spv::Op op_code, spv::Id type_id,
33+
spv::Id operand);
3634
spv::Id createNoContractionBinOp(spv::Op op_code, spv::Id type_id,
37-
spv::Id operand1, spv::Id operand2) {
38-
spv::Id result = createBinOp(op_code, type_id, operand1, operand2);
39-
addDecoration(result, spv::DecorationNoContraction);
40-
return result;
41-
}
35+
spv::Id operand1, spv::Id operand2);
36+
37+
spv::Id createUnaryBuiltinCall(spv::Id result_type, spv::Id builtins,
38+
int entry_point, spv::Id operand);
39+
spv::Id createBinBuiltinCall(spv::Id result_type, spv::Id builtins,
40+
int entry_point, spv::Id operand1,
41+
spv::Id operand2);
42+
spv::Id createTriBuiltinCall(spv::Id result_type, spv::Id builtins,
43+
int entry_point, spv::Id operand1,
44+
spv::Id operand2, spv::Id operand3);
4245
};
4346

4447
} // namespace gpu

src/xenia/gpu/spirv_shader_translator.cc

Lines changed: 60 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2037,19 +2037,15 @@ void SpirvShaderTranslator::StartFragmentShaderInMain() {
20372037
assert_true(input_fragment_coordinates_ != spv::NoResult);
20382038
id_vector_temp_.clear();
20392039
id_vector_temp_.push_back(const_int_0_);
2040-
spv::Id param_gen_x =
2041-
builder_->createLoad(builder_->createAccessChain(
2042-
spv::StorageClassInput,
2043-
input_fragment_coordinates_, id_vector_temp_),
2044-
spv::NoPrecision);
2045-
id_vector_temp_.clear();
2046-
id_vector_temp_.push_back(param_gen_x);
2047-
param_gen_x = builder_->createBuiltinCall(
2048-
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor, id_vector_temp_);
2049-
id_vector_temp_.clear();
2050-
id_vector_temp_.push_back(param_gen_x);
2051-
param_gen_x = builder_->createBuiltinCall(
2052-
type_float_, ext_inst_glsl_std_450_, GLSLstd450FAbs, id_vector_temp_);
2040+
spv::Id param_gen_x = builder_->createUnaryBuiltinCall(
2041+
type_float_, ext_inst_glsl_std_450_, GLSLstd450FAbs,
2042+
builder_->createUnaryBuiltinCall(
2043+
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor,
2044+
builder_->createLoad(
2045+
builder_->createAccessChain(spv::StorageClassInput,
2046+
input_fragment_coordinates_,
2047+
id_vector_temp_),
2048+
spv::NoPrecision)));
20532049
if (!modification.pixel.param_gen_point) {
20542050
assert_true(input_front_facing_ != spv::NoResult);
20552051
param_gen_x = builder_->createTriOp(
@@ -2076,19 +2072,15 @@ void SpirvShaderTranslator::StartFragmentShaderInMain() {
20762072
// Y - pixel Y .0 in the magnitude, is point in the sign bit.
20772073
id_vector_temp_.clear();
20782074
id_vector_temp_.push_back(builder_->makeIntConstant(1));
2079-
spv::Id param_gen_y =
2080-
builder_->createLoad(builder_->createAccessChain(
2081-
spv::StorageClassInput,
2082-
input_fragment_coordinates_, id_vector_temp_),
2083-
spv::NoPrecision);
2084-
id_vector_temp_.clear();
2085-
id_vector_temp_.push_back(param_gen_y);
2086-
param_gen_y = builder_->createBuiltinCall(
2087-
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor, id_vector_temp_);
2088-
id_vector_temp_.clear();
2089-
id_vector_temp_.push_back(param_gen_y);
2090-
param_gen_y = builder_->createBuiltinCall(
2091-
type_float_, ext_inst_glsl_std_450_, GLSLstd450FAbs, id_vector_temp_);
2075+
spv::Id param_gen_y = builder_->createUnaryBuiltinCall(
2076+
type_float_, ext_inst_glsl_std_450_, GLSLstd450FAbs,
2077+
builder_->createUnaryBuiltinCall(
2078+
type_float_, ext_inst_glsl_std_450_, GLSLstd450Floor,
2079+
builder_->createLoad(
2080+
builder_->createAccessChain(spv::StorageClassInput,
2081+
input_fragment_coordinates_,
2082+
id_vector_temp_),
2083+
spv::NoPrecision)));
20922084
if (modification.pixel.param_gen_point) {
20932085
param_gen_y = builder_->createUnaryOp(
20942086
spv::OpBitcast, type_float_,
@@ -2104,14 +2096,10 @@ void SpirvShaderTranslator::StartFragmentShaderInMain() {
21042096
assert_true(input_point_coordinates_ != spv::NoResult);
21052097
// Saturate to avoid negative point coordinates if the center of the pixel
21062098
// is not covered, and extrapolation is done.
2107-
id_vector_temp_.clear();
2108-
id_vector_temp_.push_back(
2109-
builder_->createLoad(input_point_coordinates_, spv::NoPrecision));
2110-
id_vector_temp_.push_back(const_float2_0_);
2111-
id_vector_temp_.push_back(const_float2_1_);
2112-
spv::Id param_gen_point_coordinates =
2113-
builder_->createBuiltinCall(type_float2_, ext_inst_glsl_std_450_,
2114-
GLSLstd450NClamp, id_vector_temp_);
2099+
spv::Id param_gen_point_coordinates = builder_->createTriBuiltinCall(
2100+
type_float2_, ext_inst_glsl_std_450_, GLSLstd450NClamp,
2101+
builder_->createLoad(input_point_coordinates_, spv::NoPrecision),
2102+
const_float2_0_, const_float2_1_);
21152103
param_gen_z = builder_->createCompositeExtract(
21162104
param_gen_point_coordinates, type_float_, 0);
21172105
param_gen_w = builder_->createCompositeExtract(
@@ -2397,10 +2385,8 @@ spv::Id SpirvShaderTranslator::ApplyOperandModifiers(
23972385
}
23982386
if (original_operand.is_absolute_value || force_absolute) {
23992387
EnsureBuildPointAvailable();
2400-
id_vector_temp_util_.clear();
2401-
id_vector_temp_util_.push_back(operand_value);
2402-
operand_value = builder_->createBuiltinCall(
2403-
type, ext_inst_glsl_std_450_, GLSLstd450FAbs, id_vector_temp_util_);
2388+
operand_value = builder_->createUnaryBuiltinCall(
2389+
type, ext_inst_glsl_std_450_, GLSLstd450FAbs, operand_value);
24042390
}
24052391
if (original_operand.is_negated != invert_negate) {
24062392
EnsureBuildPointAvailable();
@@ -2464,11 +2450,9 @@ spv::Id SpirvShaderTranslator::GetAbsoluteOperand(
24642450
return operand_storage;
24652451
}
24662452
EnsureBuildPointAvailable();
2467-
id_vector_temp_util_.clear();
2468-
id_vector_temp_util_.push_back(operand_storage);
2469-
return builder_->createBuiltinCall(builder_->getTypeId(operand_storage),
2470-
ext_inst_glsl_std_450_, GLSLstd450FAbs,
2471-
id_vector_temp_util_);
2453+
return builder_->createUnaryBuiltinCall(builder_->getTypeId(operand_storage),
2454+
ext_inst_glsl_std_450_,
2455+
GLSLstd450FAbs, operand_storage);
24722456
}
24732457

24742458
void SpirvShaderTranslator::StoreResult(const InstructionResult& result,
@@ -2557,15 +2541,11 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result,
25572541

25582542
if (result.is_clamped && non_constant_components) {
25592543
// Apply the saturation modifier to the result.
2560-
id_vector_temp_util_.clear();
2561-
id_vector_temp_util_.push_back(value);
2562-
id_vector_temp_util_.push_back(
2563-
const_float_vectors_0_[value_num_components - 1]);
2564-
id_vector_temp_util_.push_back(
2565-
const_float_vectors_1_[value_num_components - 1]);
2566-
value = builder_->createBuiltinCall(
2544+
value = builder_->createTriBuiltinCall(
25672545
type_float_vectors_[value_num_components - 1], ext_inst_glsl_std_450_,
2568-
GLSLstd450NClamp, id_vector_temp_util_);
2546+
GLSLstd450NClamp, value,
2547+
const_float_vectors_0_[value_num_components - 1],
2548+
const_float_vectors_1_[value_num_components - 1]);
25692549
}
25702550

25712551
// The value contains either result.GetUsedResultComponents() in a condensed
@@ -2783,12 +2763,9 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result,
27832763
uniform_system_constants_,
27842764
id_vector_temp_util_),
27852765
spv::NoPrecision));
2786-
id_vector_temp_util_.clear();
2787-
id_vector_temp_util_.push_back(point_vertex_diameter_min);
2788-
id_vector_temp_util_.push_back(point_size);
2789-
point_size =
2790-
builder_->createBuiltinCall(type_int_, ext_inst_glsl_std_450_,
2791-
GLSLstd450SMax, id_vector_temp_util_);
2766+
point_size = builder_->createBinBuiltinCall(
2767+
type_int_, ext_inst_glsl_std_450_, GLSLstd450SMax,
2768+
point_vertex_diameter_min, point_size);
27922769
id_vector_temp_util_.clear();
27932770
id_vector_temp_util_.push_back(
27942771
builder_->makeIntConstant(kSystemConstantPointVertexDiameterMax));
@@ -2799,12 +2776,9 @@ void SpirvShaderTranslator::StoreResult(const InstructionResult& result,
27992776
uniform_system_constants_,
28002777
id_vector_temp_util_),
28012778
spv::NoPrecision));
2802-
id_vector_temp_util_.clear();
2803-
id_vector_temp_util_.push_back(point_vertex_diameter_max);
2804-
id_vector_temp_util_.push_back(point_size);
2805-
point_size =
2806-
builder_->createBuiltinCall(type_int_, ext_inst_glsl_std_450_,
2807-
GLSLstd450SMin, id_vector_temp_util_);
2779+
point_size = builder_->createBinBuiltinCall(
2780+
type_int_, ext_inst_glsl_std_450_, GLSLstd450SMin,
2781+
point_vertex_diameter_max, point_size);
28082782
value_to_store = builder_->createCompositeInsert(
28092783
builder_->createUnaryOp(spv::OpBitcast, type_float_, point_size),
28102784
value_to_store, type_float3_, 0);
@@ -2902,14 +2876,11 @@ spv::Id SpirvShaderTranslator::EndianSwap32Uint(spv::Id value, spv::Id endian) {
29022876
builder_->createConditionalBranch(is_8in32_or_16in32, &block_16in32,
29032877
&block_16in32_merge);
29042878
builder_->setBuildPoint(&block_16in32);
2905-
id_vector_temp_.clear();
2906-
id_vector_temp_.push_back(builder_->createBinOp(
2907-
spv::OpShiftRightLogical, type, value, const_uint_16_typed));
2908-
id_vector_temp_.push_back(value);
2909-
id_vector_temp_.insert(id_vector_temp_.cend(), 2,
2910-
builder_->makeIntConstant(16));
2911-
spv::Id swapped_16in32 =
2912-
builder_->createOp(spv::OpBitFieldInsert, type, id_vector_temp_);
2879+
spv::Id swapped_16in32 = builder_->createQuadOp(
2880+
spv::OpBitFieldInsert, type,
2881+
builder_->createBinOp(spv::OpShiftRightLogical, type, value,
2882+
const_uint_16_typed),
2883+
value, builder_->makeIntConstant(16), builder_->makeIntConstant(16));
29132884
builder_->createBranch(&block_16in32_merge);
29142885
builder_->setBuildPoint(&block_16in32_merge);
29152886
{
@@ -3021,12 +2992,9 @@ spv::Id SpirvShaderTranslator::PWLGammaToLinear(spv::Id gamma,
30212992

30222993
if (!gamma_pre_saturated) {
30232994
// Saturate, flushing NaN to 0.
3024-
id_vector_temp_.clear();
3025-
id_vector_temp_.push_back(gamma);
3026-
id_vector_temp_.push_back(const_vector_0);
3027-
id_vector_temp_.push_back(const_vector_1);
3028-
gamma = builder_->createBuiltinCall(value_type, ext_inst_glsl_std_450_,
3029-
GLSLstd450NClamp, id_vector_temp_);
2995+
gamma = builder_->createTriBuiltinCall(value_type, ext_inst_glsl_std_450_,
2996+
GLSLstd450NClamp, gamma,
2997+
const_vector_0, const_vector_1);
30302998
}
30312999

30323000
spv::Id is_piece_at_least_3 = builder_->createBinOp(
@@ -3086,14 +3054,12 @@ spv::Id SpirvShaderTranslator::PWLGammaToLinear(spv::Id gamma,
30863054
scale),
30873055
offset);
30883056
// linear += trunc(linear * scale)
3089-
spv::Id linear_integer_term = builder_->createNoContractionBinOp(
3090-
spv::OpFMul, value_type, linear, scale);
3091-
id_vector_temp_.clear();
3092-
id_vector_temp_.push_back(linear_integer_term);
3093-
linear_integer_term = builder_->createBuiltinCall(
3094-
value_type, ext_inst_glsl_std_450_, GLSLstd450Trunc, id_vector_temp_);
3095-
linear = builder_->createNoContractionBinOp(spv::OpFAdd, value_type, linear,
3096-
linear_integer_term);
3057+
linear = builder_->createNoContractionBinOp(
3058+
spv::OpFAdd, value_type, linear,
3059+
builder_->createUnaryBuiltinCall(
3060+
value_type, ext_inst_glsl_std_450_, GLSLstd450Trunc,
3061+
builder_->createNoContractionBinOp(spv::OpFMul, value_type, linear,
3062+
scale)));
30973063
// linear *= 1.0f / 1023.0f
30983064
linear = builder_->createNoContractionBinOp(
30993065
value_times_scalar_opcode, value_type, linear,
@@ -3117,12 +3083,9 @@ spv::Id SpirvShaderTranslator::LinearToPWLGamma(spv::Id linear,
31173083

31183084
if (!linear_pre_saturated) {
31193085
// Saturate, flushing NaN to 0.
3120-
id_vector_temp_.clear();
3121-
id_vector_temp_.push_back(linear);
3122-
id_vector_temp_.push_back(const_vector_0);
3123-
id_vector_temp_.push_back(const_vector_1);
3124-
linear = builder_->createBuiltinCall(value_type, ext_inst_glsl_std_450_,
3125-
GLSLstd450NClamp, id_vector_temp_);
3086+
linear = builder_->createTriBuiltinCall(value_type, ext_inst_glsl_std_450_,
3087+
GLSLstd450NClamp, linear,
3088+
const_vector_0, const_vector_1);
31263089
}
31273090

31283091
spv::Id is_piece_at_least_3 = builder_->createBinOp(
@@ -3170,19 +3133,16 @@ spv::Id SpirvShaderTranslator::LinearToPWLGamma(spv::Id linear,
31703133
offset_3_or_2, offset_1_or_0);
31713134

31723135
// gamma = trunc(linear * scale) * (1.0f / 255.0f) + offset
3173-
spv::Id gamma = builder_->createNoContractionBinOp(spv::OpFMul, value_type,
3174-
linear, scale);
3175-
id_vector_temp_.clear();
3176-
id_vector_temp_.push_back(gamma);
3177-
gamma = builder_->createBuiltinCall(value_type, ext_inst_glsl_std_450_,
3178-
GLSLstd450Trunc, id_vector_temp_);
3179-
gamma = builder_->createNoContractionBinOp(
3136+
return builder_->createNoContractionBinOp(
31803137
spv::OpFAdd, value_type,
31813138
builder_->createNoContractionBinOp(
3182-
is_vector ? spv::OpVectorTimesScalar : spv::OpFMul, value_type, gamma,
3139+
is_vector ? spv::OpVectorTimesScalar : spv::OpFMul, value_type,
3140+
builder_->createUnaryBuiltinCall(
3141+
value_type, ext_inst_glsl_std_450_, GLSLstd450Trunc,
3142+
builder_->createNoContractionBinOp(spv::OpFMul, value_type,
3143+
linear, scale)),
31833144
builder_->makeFloatConstant(1.0f / 255.0f)),
31843145
offset);
3185-
return gamma;
31863146
}
31873147

31883148
} // namespace gpu

0 commit comments

Comments
 (0)