mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-11-24 10:23:21 +00:00
179 lines
6.8 KiB
C++
179 lines
6.8 KiB
C++
// 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
|