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
|