File: BPFunctions.h

package info (click to toggle)
dolphin-emu 2512%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid
  • size: 76,328 kB
  • sloc: cpp: 499,023; ansic: 119,674; python: 6,547; sh: 2,338; makefile: 1,093; asm: 726; pascal: 257; javascript: 183; perl: 97; objc: 75; xml: 30
file content (178 lines) | stat: -rw-r--r-- 6,966 bytes parent folder | download
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
// Copyright 2009 Dolphin Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

// ------------------------------------------
// Video backend must define these functions
// ------------------------------------------

#pragma once

#include <utility>
#include <vector>

#include "Common/MathUtil.h"
#include "VideoCommon/BPMemory.h"

class FramebufferManager;
struct Viewport;

namespace BPFunctions
{
struct ScissorRange
{
  constexpr ScissorRange() = default;
  constexpr ScissorRange(int offset_, int start_, int end_)
      : offset(offset_), start(start_), end(end_)
  {
  }
  int offset = 0;
  int start = 0;
  int end = 0;
};

struct ScissorRect
{
  constexpr ScissorRect(ScissorRange x_range, ScissorRange y_range)
      :  // Rectangle ctor takes x0, y0, x1, y1.
        rect(x_range.start, y_range.start, x_range.end, y_range.end), x_off(x_range.offset),
        y_off(y_range.offset)
  {
  }

  MathUtil::Rectangle<int> rect;
  int x_off;
  int y_off;

  int GetArea() const;
};

// Although the GameCube/Wii have only one scissor configuration and only one viewport
// configuration, some values can result in multiple parts of the screen being updated.
// This can happen if the scissor offset combined with the bottom or right coordinate ends up
// exceeding 1024; then, both sides of the screen will be drawn to, while the middle is not.
// Major Minor's Majestic March causes this to happen during loading screens and other scrolling
// effects, though it draws on top of one of them.
// This can also happen if the scissor rectangle is particularly large, but this will usually
// involve drawing content outside of the viewport, which Dolphin does not currently handle.
//
// The hardware backends can currently only use one viewport and scissor rectangle, so we need to
// pick the "best" rectangle based on how much of the viewport would be rendered to the screen.
// If we choose the wrong one, then content might not actually show up when the game is expecting it
// to.  This does happen on Major Minor's Majestic March for the final few frames of the horizontal
// scrolling animation, but it isn't that important.  Note that the assumption that a "best"
// rectangle exists is based on games only wanting to draw one rectangle, and accidentally
// configuring the scissor offset and size of the scissor rectangle such that multiple show up;
// there are no known games where this is not the case.
//
// An ImGui overlay that displays the scissor rectangle configuration as well as the generated
// rectangles is available by setting OverlayScissorStats (GFX_OVERLAY_SCISSOR_STATS)
// under [Settings] to True in GFX.ini.
struct ScissorResult
{
  ScissorResult(ScissorPos scissor_top_left, ScissorPos scissor_bottom_right,
                ScissorOffset scissor_offset, const Viewport& viewport);
  ~ScissorResult() = default;
  ScissorResult(const ScissorResult& other)
      : scissor_tl{.hex = other.scissor_tl.hex}, scissor_br{.hex = other.scissor_br.hex},
        scissor_off{.hex = other.scissor_off.hex}, viewport_left{other.viewport_left},
        viewport_right{other.viewport_right}, viewport_top{other.viewport_top},
        viewport_bottom{other.viewport_bottom}, rectangles{other.rectangles}
  {
  }
  ScissorResult& operator=(const ScissorResult& other)
  {
    if (this == &other)
      return *this;
    scissor_tl.hex = other.scissor_tl.hex;
    scissor_br.hex = other.scissor_br.hex;
    scissor_off.hex = other.scissor_off.hex;
    viewport_left = other.viewport_left;
    viewport_right = other.viewport_right;
    viewport_top = other.viewport_top;
    viewport_bottom = other.viewport_bottom;
    rectangles = other.rectangles;
    return *this;
  }
  ScissorResult(ScissorResult&& other)
      : scissor_tl{.hex = other.scissor_tl.hex}, scissor_br{.hex = other.scissor_br.hex},
        scissor_off{.hex = other.scissor_off.hex}, viewport_left{other.viewport_left},
        viewport_right{other.viewport_right}, viewport_top{other.viewport_top},
        viewport_bottom{other.viewport_bottom}, rectangles{std::move(other.rectangles)}
  {
  }
  ScissorResult& operator=(ScissorResult&& other)
  {
    if (this == &other)
      return *this;
    scissor_tl.hex = other.scissor_tl.hex;
    scissor_br.hex = other.scissor_br.hex;
    scissor_off.hex = other.scissor_off.hex;
    viewport_left = other.viewport_left;
    viewport_right = other.viewport_right;
    viewport_top = other.viewport_top;
    viewport_bottom = other.viewport_bottom;
    rectangles = std::move(other.rectangles);
    return *this;
  }

  // Input values, for use in statistics
  ScissorPos scissor_tl;
  ScissorPos scissor_br;
  ScissorOffset scissor_off;
  float viewport_left;
  float viewport_right;
  float viewport_top;
  float viewport_bottom;

  std::vector<ScissorRect> rectangles;

  ScissorRect Best() const;

  bool ScissorMatches(const ScissorResult& other) const
  {
    return scissor_tl.hex == other.scissor_tl.hex && scissor_br.hex == other.scissor_br.hex &&
           scissor_off.hex == other.scissor_off.hex;
  }
  bool ViewportMatches(const ScissorResult& other) const
  {
    return viewport_left == other.viewport_left && viewport_right == other.viewport_right &&
           viewport_top == other.viewport_top && viewport_bottom == other.viewport_bottom;
  }
  bool Matches(const ScissorResult& other, bool compare_scissor, bool compare_viewport) const
  {
    if (compare_scissor && !ScissorMatches(other))
      return false;
    if (compare_viewport && !ViewportMatches(other))
      return false;
    return true;
  }

private:
  ScissorResult(ScissorPos scissor_top_left, ScissorPos scissor_bottom_right,
                ScissorOffset scissor_offset, std::pair<float, float> viewport_x,
                std::pair<float, float> viewport_y);

  int GetViewportArea(const ScissorRect& rect) const;
  bool IsWorse(const ScissorRect& lhs, const ScissorRect& rhs) const;
};

ScissorResult ComputeScissorRects(ScissorPos scissor_top_left, ScissorPos scissor_bottom_right,
                                  ScissorOffset scissor_offset, const Viewport& viewport);

void FlushPipeline();
void SetGenerationMode();
void SetScissorAndViewport(FramebufferManager* frame_buffer_manager, ScissorPos scissor_top_left,
                           ScissorPos scissor_bottom_right, ScissorOffset scissor_offset,
                           Viewport viewport);
void SetDepthMode();
void SetBlendMode();

// Returns true if the EFB was triggered to clear
bool ClearScreen(FramebufferManager* frame_buffer_manager, const MathUtil::Rectangle<int>& rc,
                 bool color_enable, bool alpha_enable, bool z_enable, PixelFormat pixel_format,
                 u32 clear_color_ar, u32 clear_color_gb, u32 clear_z_value);

void OnPixelFormatChange(FramebufferManager* frame_buffer_manager, PixelFormat pixel_format,
                         DepthFormat z_format);
void SetInterlacingMode(const BPCmd& bp);
}  // namespace BPFunctions