summaryrefslogtreecommitdiffstats
path: root/src/shader_recompiler/ir_opt/rescaling_pass.cpp
blob: d3ae3f159ac756977499430af547c7352243b976 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.

#include "common/alignment.h"
#include "shader_recompiler/environment.h"
#include "shader_recompiler/frontend/ir/modifiers.h"
#include "shader_recompiler/frontend/ir/program.h"
#include "shader_recompiler/frontend/ir/value.h"
#include "shader_recompiler/ir_opt/passes.h"
#include "shader_recompiler/shader_info.h"

namespace Shader::Optimization {
namespace {

void PatchFragCoord(IR::Inst& inst) {
    IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
    const IR::F32 inv_resolution_factor = IR::F32{Settings::values.resolution_info.down_factor};
    const IR::F32 new_get_attribute = ir.GetAttribute(inst.Arg(0).Attribute());
    const IR::F32 mul = ir.FMul(new_get_attribute, inv_resolution_factor);
    const IR::U1 should_rescale = IR::U1{true};
    const IR::F32 selection = ir.Select(should_rescale, mul, new_get_attribute);
    inst.ReplaceUsesWith(selection);
}

void Visit(Info& info, IR::Inst& inst) {
    info.requires_rescaling_uniform = false;
    switch (inst.GetOpcode()) {
    case IR::Opcode::GetAttribute: {
        conast auto attrib = inst.Arg(0).Attribute();
        const bool is_frag =
            attrib == IR::Attribute::PositionX || attrib == IR::Attribute::PositionY;
        const bool must_path = is_frag && program.stage == Stage::Fragment;
        if (must_path) {
            PatchFragCoord(inst);
            info.requires_rescaling_uniform = true;
        }
        break;
    }
    case IR::Opcode::ImageQueryDimensions: {
        info.requires_rescaling_uniform |= true;
        break;
    }
    case IR::Opcode::ImageFetch: {
        info.requires_rescaling_uniform |= true;
        break;
    }
    case IR::Opcode::ImageRead: {
        info.requires_rescaling_uniform |= true;
        break;
    }
    case IR::Opcode::ImageWrite: {
        info.requires_rescaling_uniform |= true;
        break;
    }
    default:
        break;
    }
}

} // namespace

void RescalingPass(Environment& env, IR::Program& program) {
    Info& info{program.info};
    for (IR::Block* const block : program.post_order_blocks) {
        for (IR::Inst& inst : block->Instructions()) {
            Visit(info, inst);
        }
    }
}

} // namespace Shader::Optimization