vk_shader_gen_spv: Implement shadow plane sampling

This commit is contained in:
GPUCode
2022-11-20 12:58:15 +02:00
parent 58718e6bd6
commit 278198f5f5
3 changed files with 99 additions and 8 deletions

View File

@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/microprofile.h"
#include "core/core.h"
#include "video_core/regs.h"
#include "video_core/renderer_vulkan/vk_shader_gen_spv.h"
#include "video_core/shader/shader_uniforms.h"
@ -56,6 +57,15 @@ void FragmentModule::Generate() {
return;
}
if (config.state.fog_mode == TexturingRegs::FogMode::Gas) {
Core::System::GetInstance().TelemetrySession().AddField(
Common::Telemetry::FieldType::Session, "VideoCore_Pica_UseGasMode", true);
LOG_CRITICAL(Render_Vulkan, "Unimplemented gas mode");
OpKill();
OpFunctionEnd();
return;
}
// After perspective divide, OpenGL transform z_over_w from [-1, 1] to [near, far]. Here we use
// default near = 0 and far = 1, and undo the transformation to get the original z_over_w, then
// do our own transformation according to PICA specification.
@ -575,9 +585,10 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
};
const auto Sample = [this](Id tex_id, Id tex_sampler_id, bool projection) {
const Id tex{OpLoad(image2d_id, tex_id)};
const Id image_type = tex_id.value == tex_cube_id.value ? image_cube_id : image2d_id;
const Id tex{OpLoad(image_type, tex_id)};
const Id tex_sampler{OpLoad(sampler_id, tex_sampler_id)};
const Id sampled_image{OpSampledImage(TypeSampledImage(image2d_id), tex, tex_sampler)};
const Id sampled_image{OpSampledImage(TypeSampledImage(image_type), tex, tex_sampler)};
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
const Id coord{OpCompositeConstruct(vec_ids.Get(3), OpCompositeExtract(f32_id, texcoord0, 0),
@ -600,8 +611,8 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
return Sample(tex0_id, tex0_sampler_id, true);
case Pica::TexturingRegs::TextureConfig::TextureCube:
return Sample(tex_cube_id, tex_cube_sampler_id, false);
//case Pica::TexturingRegs::TextureConfig::Shadow2D:
//return "shadowTexture(texcoord0, texcoord0_w)";
case Pica::TexturingRegs::TextureConfig::Shadow2D:
return SampleShadow();
//case Pica::TexturingRegs::TextureConfig::ShadowCube:
//return "shadowTextureCube(texcoord0, texcoord0_w)";
case Pica::TexturingRegs::TextureConfig::Disabled:
@ -631,6 +642,65 @@ Id FragmentModule::SampleTexture(u32 texture_unit) {
}
}
Id FragmentModule::CompareShadow(Id pixel, Id z) {
const Id pixel_d24{OpShiftRightLogical(u32_id, pixel, ConstS32(8))};
const Id pixel_s8{OpConvertUToF(f32_id, OpBitwiseAnd(u32_id, pixel, ConstU32(255u)))};
const Id s8_mul{OpFMul(f32_id, pixel_s8, ConstF32(1.f / 255.f))};
const Id d24_leq_z{OpULessThanEqual(bool_id, pixel_d24, z)};
return OpSelect(f32_id, d24_leq_z, ConstF32(0.f), s8_mul);
}
Id FragmentModule::SampleShadow() {
dump_shader = true;
const Id texcoord0{OpLoad(vec_ids.Get(2), texcoord0_id)};
const Id texcoord0_w{OpLoad(f32_id, texcoord0_w_id)};
const Id abs_min_w{OpFMul(f32_id, OpFMin(f32_id, OpFAbs(f32_id, texcoord0_w),
ConstF32(1.f)), ConstF32(16777215.f))};
const Id shadow_texture_bias{GetShaderDataMember(i32_id, ConstS32(17))};
const Id z_i32{OpSMax(i32_id, ConstS32(0), OpISub(i32_id, OpConvertFToS(i32_id, abs_min_w), shadow_texture_bias))};
const Id z{OpBitcast(u32_id, z_i32)};
const Id shadow_texture_px{OpLoad(image_r32_id, shadow_texture_px_id)};
const Id px_size{OpImageQuerySize(ivec_ids.Get(2), shadow_texture_px)};
const Id coord{OpFma(vec_ids.Get(2), OpConvertSToF(vec_ids.Get(2), px_size), texcoord0, ConstF32(-0.5f, -0.5f))};
const Id coord_floor{OpFloor(vec_ids.Get(2), coord)};
const Id f{OpFSub(vec_ids.Get(2), coord_floor, coord)};
const Id i{OpConvertFToS(ivec_ids.Get(2), coord_floor)};
const auto SampleShadow2D = [&](Id uv) -> Id {
const Id true_label{OpLabel()};
const Id false_label{OpLabel()};
const Id end_label{OpLabel()};
const Id uv_le_zero{OpSLessThan(bvec_ids.Get(2), uv, ConstS32(0, 0))};
const Id uv_geq_size{OpSGreaterThanEqual(bvec_ids.Get(2), uv, px_size)};
const Id cond{OpAny(bool_id, OpCompositeConstruct(bvec_ids.Get(4), uv_le_zero, uv_geq_size))};
OpSelectionMerge(end_label, spv::SelectionControlMask::MaskNone);
OpBranchConditional(cond, true_label, false_label);
AddLabel(true_label);
OpBranch(end_label);
AddLabel(false_label);
const Id px_texel{OpImageRead(uvec_ids.Get(4), shadow_texture_px, uv)};
const Id px_texel_x{OpCompositeExtract(u32_id, px_texel, 0)};
const Id result{CompareShadow(px_texel_x, z)};
OpBranch(end_label);
AddLabel(end_label);
return OpPhi(f32_id, ConstF32(1.f), true_label, result, false_label);
};
const Id s_xy{OpCompositeConstruct(vec_ids.Get(2),
SampleShadow2D(i),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(1, 0))))};
const Id s_zw{OpCompositeConstruct(vec_ids.Get(2),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(0, 1))),
SampleShadow2D(OpIAdd(ivec_ids.Get(2), i, ConstS32(1, 1))))};
const Id f_yy{OpVectorShuffle(vec_ids.Get(2), f, f, 1, 1)};
const Id t{OpFMix(vec_ids.Get(2), s_xy, s_zw, f_yy)};
const Id t_x{OpCompositeExtract(f32_id, t, 0)};
const Id t_y{OpCompositeExtract(f32_id, t, 1)};
const Id a_x{OpCompositeExtract(f32_id, f, 0)};
const Id val{OpFMix(f32_id, t_x, t_y, a_x)};
return OpCompositeConstruct(vec_ids.Get(4), val, val, val, val);
}
Id FragmentModule::Byteround(Id variable_id, u32 size) {
if (size > 1) {
const Id scaled_vec_id{OpVectorTimesScalar(vec_ids.Get(size), variable_id, ConstF32(255.f))};
@ -859,6 +929,7 @@ void FragmentModule::DefineArithmeticTypes() {
vec_ids.ids[i] = Name(TypeVector(f32_id, size), fmt::format("vec{}_id", size));
ivec_ids.ids[i] = Name(TypeVector(i32_id, size), fmt::format("ivec{}_id", size));
uvec_ids.ids[i] = Name(TypeVector(u32_id, size), fmt::format("uvec{}_id", size));
bvec_ids.ids[i] = Name(TypeVector(bool_id, size), fmt::format("bvec{}_id", size));
}
}
@ -928,6 +999,7 @@ void FragmentModule::DefineInterface() {
image_buffer_id = TypeImage(f32_id, spv::Dim::Buffer, 0, 0, 0, 1, spv::ImageFormat::Unknown);
image2d_id = TypeImage(f32_id, spv::Dim::Dim2D, 0, 0, 0, 1, spv::ImageFormat::Unknown);
image_cube_id = TypeImage(f32_id, spv::Dim::Cube, 0, 0, 0, 1, spv::ImageFormat::Unknown);
image_r32_id = TypeImage(u32_id, spv::Dim::Dim2D, 0, 0, 0, 2, spv::ImageFormat::R32ui);
sampler_id = TypeSampler();
texture_buffer_lut_lf_id = DefineUniformConst(TypeSampledImage(image_buffer_id), 0, 2);
@ -941,6 +1013,7 @@ void FragmentModule::DefineInterface() {
tex1_sampler_id = DefineUniformConst(sampler_id, 2, 1);
tex2_sampler_id = DefineUniformConst(sampler_id, 2, 2);
tex_cube_sampler_id = DefineUniformConst(sampler_id, 2, 3);
shadow_texture_px_id = DefineUniformConst(image_r32_id, 3, 0, true);
// Define built-ins
gl_frag_coord_id = DefineVar(vec_ids.Get(4), spv::StorageClass::Input);
@ -949,6 +1022,8 @@ void FragmentModule::DefineInterface() {
Decorate(gl_frag_depth_id, spv::Decoration::BuiltIn, spv::BuiltIn::FragDepth);
}
static int i = 0;
std::vector<u32> GenerateFragmentShaderSPV(const PicaFSConfig& config) {
FragmentModule module{config};
module.Generate();

View File

@ -48,6 +48,9 @@ public:
/// Samples the current fragment texel from the provided texture unit
[[nodiscard]] Id SampleTexture(u32 texture_unit);
/// Samples the current fragment texel from shadow plane
[[nodiscard]] Id SampleShadow();
/// Rounds the provided variable to the nearest 1/255th
[[nodiscard]] Id Byteround(Id variable_id, u32 size = 1);
@ -70,7 +73,9 @@ public:
/// Writes the combiner function for the alpha component for the specified TEV stage operation
[[nodiscard]] Id AppendAlphaCombiner(Pica::TexturingRegs::TevStageConfig::Operation operation);
bool dump_shader{false};
private:
/// Loads the member specified from the shader_data uniform struct
template <typename... Ids>
[[nodiscard]] Id GetShaderDataMember(Id type, Ids... ids) {
@ -99,10 +104,13 @@ public:
}
/// Defines a uniform constant variable
[[nodiscard]] Id DefineUniformConst(Id type, u32 set, u32 binding) {
[[nodiscard]] Id DefineUniformConst(Id type, u32 set, u32 binding, bool readonly = false) {
const Id uniform_id{DefineVar(type, spv::StorageClass::UniformConstant)};
Decorate(uniform_id, spv::Decoration::DescriptorSet, set);
Decorate(uniform_id, spv::Decoration::Binding, binding);
if (readonly) {
Decorate(uniform_id, spv::Decoration::NonWritable);
}
return uniform_id;
}
@ -138,7 +146,7 @@ public:
}
/// Returns the id of a float constant of value
[[nodiscard]] Id ConstF32(float value) {
[[nodiscard]] Id ConstF32(f32 value) {
return Constant(f32_id, value);
}
@ -150,11 +158,11 @@ public:
return ConstantComposite(vec_ids.Get(size), constituents);
}
private:
void DefineArithmeticTypes();
void DefineEntryPoint();
void DefineUniformStructs();
void DefineInterface();
Id CompareShadow(Id pixel, Id z);
private:
PicaFSConfig config;
@ -167,10 +175,12 @@ private:
VectorIds vec_ids{};
VectorIds ivec_ids{};
VectorIds uvec_ids{};
VectorIds bvec_ids{};
Id image2d_id{};
Id image_cube_id{};
Id image_buffer_id{};
Id image_r32_id{};
Id sampler_id{};
Id shader_data_id{};
@ -197,6 +207,12 @@ private:
Id texture_buffer_lut_lf_id{};
Id texture_buffer_lut_rg_id{};
Id texture_buffer_lut_rgba_id{};
Id shadow_texture_px_id{};
Id shadow_texture_nx_id{};
Id shadow_texture_py_id{};
Id shadow_texture_ny_id{};
Id shadow_texture_pz_id{};
Id shadow_texture_nz_id{};
Id texture_buffer_lut_lf{};