mirror of
https://github.com/azahar-emu/azahar
synced 2025-11-14 19:09:57 +01:00
Implement framebuffer vertical flip flag (#699)
* Implement framebuffer vertical flip flag * Make VerticalMirror const
This commit is contained in:
parent
411abde5d1
commit
643f53f5f2
@ -1,4 +1,8 @@
|
||||
// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -23,6 +27,12 @@ struct Rectangle {
|
||||
constexpr Rectangle(T left, T top, T right, T bottom)
|
||||
: left(left), top(top), right(right), bottom(bottom) {}
|
||||
|
||||
template <typename U>
|
||||
operator Rectangle<U>() const {
|
||||
return Rectangle<U>{static_cast<U>(left), static_cast<U>(top), static_cast<U>(right),
|
||||
static_cast<U>(bottom)};
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool operator==(const Rectangle<T>& rhs) const {
|
||||
return (left == rhs.left) && (top == rhs.top) && (right == rhs.right) &&
|
||||
(bottom == rhs.bottom);
|
||||
@ -55,6 +65,9 @@ struct Rectangle {
|
||||
return Rectangle{left, top, static_cast<T>(left + GetWidth() * s),
|
||||
static_cast<T>(top + GetHeight() * s)};
|
||||
}
|
||||
[[nodiscard]] Rectangle<T> VerticalMirror(T ref_height) const {
|
||||
return Rectangle{left, ref_height - bottom, right, ref_height - top};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -233,6 +233,7 @@ struct FramebufferRegs {
|
||||
// GetWidth() and GetHeight() instead.
|
||||
BitField<0, 11, u32> width;
|
||||
BitField<12, 10, u32> height;
|
||||
BitField<24, 1, u32> flip;
|
||||
};
|
||||
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
@ -251,6 +252,10 @@ struct FramebufferRegs {
|
||||
inline u32 GetHeight() const {
|
||||
return height + 1;
|
||||
}
|
||||
|
||||
inline bool IsFlipped() const {
|
||||
return !flip.Value();
|
||||
}
|
||||
} framebuffer;
|
||||
|
||||
// Returns the number of bytes in the specified depth format
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2017 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -29,11 +29,13 @@ struct RasterizerRegs {
|
||||
|
||||
BitField<0, 24, u32> viewport_size_x;
|
||||
|
||||
INSERT_PADDING_WORDS(0x1);
|
||||
BitField<1, 31, u32> viewport_size_x_inv;
|
||||
|
||||
BitField<0, 24, u32> viewport_size_y;
|
||||
|
||||
INSERT_PADDING_WORDS(0x3);
|
||||
BitField<1, 31, u32> viewport_size_y_inv;
|
||||
|
||||
INSERT_PADDING_WORDS(0x2);
|
||||
|
||||
BitField<0, 1, u32> clip_enable;
|
||||
BitField<0, 24, u32> clip_coef[4]; // float24
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -138,7 +138,7 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
static constexpr u32 MASK = (1 << (M + E + 1)) - 1;
|
||||
static constexpr u32 MASK = static_cast<u32>(1 << (M + E + 1)) - 1;
|
||||
static constexpr u32 MANTISSA_MASK = (1 << M) - 1;
|
||||
static constexpr u32 EXPONENT_MASK = (1 << E) - 1;
|
||||
|
||||
@ -153,6 +153,7 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
using f31 = Pica::Float<23, 7>;
|
||||
using f24 = Pica::Float<16, 7>;
|
||||
using f20 = Pica::Float<12, 7>;
|
||||
using f16 = Pica::Float<10, 5>;
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -846,7 +846,7 @@ void RasterizerAccelerated::SyncTextureBorderColor(int tex_index) {
|
||||
}
|
||||
|
||||
void RasterizerAccelerated::SyncClipPlane() {
|
||||
const u32 enable_clip1 = regs.rasterizer.clip_enable != 0;
|
||||
const bool enable_clip1 = regs.rasterizer.clip_enable != 0;
|
||||
const auto raw_clip_coef = regs.rasterizer.GetClipCoef();
|
||||
const Common::Vec4f new_clip_coef = {raw_clip_coef.x.ToFloat32(), raw_clip_coef.y.ToFloat32(),
|
||||
raw_clip_coef.z.ToFloat32(), raw_clip_coef.w.ToFloat32()};
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -65,13 +65,18 @@ template <class T>
|
||||
class FramebufferHelper {
|
||||
public:
|
||||
explicit FramebufferHelper(RasterizerCache<T>* res_cache_, typename T::Framebuffer* fb_,
|
||||
const Pica::RasterizerRegs& regs,
|
||||
bool flip_rect, const Pica::RasterizerRegs& regs,
|
||||
Common::Rectangle<u32> surfaces_rect)
|
||||
: res_cache{res_cache_}, fb{fb_} {
|
||||
const u32 res_scale = fb->Scale();
|
||||
const u32 height = surfaces_rect.GetHeight() / res_scale;
|
||||
|
||||
// Determine the draw rectangle (render area + scissor)
|
||||
const Common::Rectangle viewport_rect = regs.GetViewportRect();
|
||||
Common::Rectangle viewport_rect = regs.GetViewportRect();
|
||||
if (flip_rect) {
|
||||
viewport_rect = viewport_rect.VerticalMirror(height);
|
||||
}
|
||||
|
||||
draw_rect.left =
|
||||
std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left * res_scale,
|
||||
surfaces_rect.left, surfaces_rect.right);
|
||||
@ -103,6 +108,10 @@ public:
|
||||
static_cast<s32>(surfaces_rect.left + (regs.scissor_test.x2 + 1) * res_scale);
|
||||
scissor_rect.top =
|
||||
static_cast<s32>(surfaces_rect.bottom + (regs.scissor_test.y2 + 1) * res_scale);
|
||||
|
||||
if (flip_rect) {
|
||||
scissor_rect = scissor_rect.VerticalMirror(height);
|
||||
}
|
||||
}
|
||||
|
||||
~FramebufferHelper() {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright Citra Emulator Project / Lime3DS Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -765,7 +765,8 @@ FramebufferHelper<T> RasterizerCache<T>::GetFramebufferSurfaces(bool using_color
|
||||
it->second = slot_framebuffers.insert(runtime, fb_params, color_surface, depth_surface);
|
||||
}
|
||||
|
||||
return FramebufferHelper<T>{this, &slot_framebuffers[it->second], regs.rasterizer, fb_rect};
|
||||
return FramebufferHelper<T>{this, &slot_framebuffers[it->second],
|
||||
regs.framebuffer.framebuffer.IsFlipped(), regs.rasterizer, fb_rect};
|
||||
}
|
||||
|
||||
template <class T>
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2022 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -409,6 +409,12 @@ bool RasterizerOpenGL::Draw(bool accelerate, bool is_indexed) {
|
||||
state.viewport.width = static_cast<GLsizei>(viewport.width);
|
||||
state.viewport.height = static_cast<GLsizei>(viewport.height);
|
||||
|
||||
// If the framebuffer is flipped, request vertex shader to flip vertex y
|
||||
const bool is_flipped = regs.framebuffer.framebuffer.IsFlipped();
|
||||
vs_uniform_block_data.dirty |= vs_uniform_block_data.data.flip_viewport != is_flipped;
|
||||
vs_uniform_block_data.data.flip_viewport = is_flipped;
|
||||
state.cull.mode = is_flipped && state.cull.enabled ? GL_FRONT : GL_BACK;
|
||||
|
||||
// Viewport can have negative offsets or larger dimensions than our framebuffer sub-rect.
|
||||
// Enable scissor test to prevent drawing outside of the framebuffer region
|
||||
const auto draw_rect = fb_helper.DrawRect();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -177,13 +177,13 @@ inline vk::PrimitiveTopology PrimitiveTopology(Pica::PipelineRegs::TriangleTopol
|
||||
return vk::PrimitiveTopology::eTriangleList;
|
||||
}
|
||||
|
||||
inline vk::CullModeFlags CullMode(Pica::RasterizerRegs::CullMode mode) {
|
||||
inline vk::CullModeFlags CullMode(Pica::RasterizerRegs::CullMode mode, bool flip_viewport) {
|
||||
switch (mode) {
|
||||
case Pica::RasterizerRegs::CullMode::KeepAll:
|
||||
return vk::CullModeFlagBits::eNone;
|
||||
case Pica::RasterizerRegs::CullMode::KeepClockWise:
|
||||
case Pica::RasterizerRegs::CullMode::KeepCounterClockWise:
|
||||
return vk::CullModeFlagBits::eBack;
|
||||
return flip_viewport ? vk::CullModeFlagBits::eFront : vk::CullModeFlagBits::eBack;
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown cull mode {}", mode);
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -147,7 +147,8 @@ bool GraphicsPipeline::Build(bool fail_on_compile_required) {
|
||||
const vk::PipelineRasterizationStateCreateInfo raster_state = {
|
||||
.depthClampEnable = false,
|
||||
.rasterizerDiscardEnable = false,
|
||||
.cullMode = PicaToVK::CullMode(info.rasterization.cull_mode),
|
||||
.cullMode =
|
||||
PicaToVK::CullMode(info.rasterization.cull_mode, info.rasterization.flip_viewport),
|
||||
.frontFace = PicaToVK::FrontFace(info.rasterization.cull_mode),
|
||||
.depthBiasEnable = false,
|
||||
.lineWidth = 1.0f,
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -54,6 +54,7 @@ union RasterizationState {
|
||||
u8 value = 0;
|
||||
BitField<0, 2, Pica::PipelineRegs::TriangleTopology> topology;
|
||||
BitField<4, 2, Pica::RasterizerRegs::CullMode> cull_mode;
|
||||
BitField<6, 1, u8> flip_viewport;
|
||||
};
|
||||
|
||||
union DepthStencilState {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -271,8 +271,12 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) {
|
||||
}
|
||||
|
||||
if (instance.IsExtendedDynamicStateSupported()) {
|
||||
if (rasterization.cull_mode != current_rasterization.cull_mode || is_dirty) {
|
||||
cmdbuf.setCullModeEXT(PicaToVK::CullMode(rasterization.cull_mode));
|
||||
const bool needs_flip =
|
||||
rasterization.flip_viewport != current_rasterization.flip_viewport;
|
||||
if (rasterization.cull_mode != current_rasterization.cull_mode || needs_flip ||
|
||||
is_dirty) {
|
||||
cmdbuf.setCullModeEXT(
|
||||
PicaToVK::CullMode(rasterization.cull_mode, rasterization.flip_viewport));
|
||||
cmdbuf.setFrontFaceEXT(PicaToVK::FrontFace(rasterization.cull_mode));
|
||||
}
|
||||
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -509,6 +509,12 @@ bool RasterizerVulkan::Draw(bool accelerate, bool is_indexed) {
|
||||
shader_dirty = false;
|
||||
}
|
||||
|
||||
// If the framebuffer is flipped, request to also flip vulkan viewport
|
||||
const bool is_flipped = regs.framebuffer.framebuffer.IsFlipped();
|
||||
vs_uniform_block_data.dirty |= vs_uniform_block_data.data.flip_viewport != is_flipped;
|
||||
vs_uniform_block_data.data.flip_viewport = is_flipped;
|
||||
pipeline_info.rasterization.flip_viewport.Assign(is_flipped);
|
||||
|
||||
// Sync the LUTs within the texture buffer
|
||||
SyncAndUploadLUTs();
|
||||
SyncAndUploadLUTsLF();
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -37,6 +37,7 @@ layout (set = 0, binding = 1, std140) uniform vs_data {
|
||||
layout (binding = 1, std140) uniform vs_data {
|
||||
#endif
|
||||
bool enable_clip1;
|
||||
bool flip_viewport;
|
||||
vec4 clip_coef;
|
||||
};
|
||||
|
||||
@ -123,6 +124,9 @@ void main() {
|
||||
normquat = vert_normquat;
|
||||
view = vert_view;
|
||||
vec4 vtx_pos = SanitizeVertex(vert_position);
|
||||
if (flip_viewport) {
|
||||
vtx_pos.y = -vtx_pos.y;
|
||||
}
|
||||
gl_Position = vec4(vtx_pos.x, vtx_pos.y, -vtx_pos.z, vtx_pos.w);
|
||||
)";
|
||||
if (use_clip_planes) {
|
||||
@ -238,6 +242,9 @@ std::string GenerateVertexShader(const ShaderSetup& setup, const PicaVSConfig& c
|
||||
semantic(VSOutputAttributes::POSITION_Z) + ", " +
|
||||
semantic(VSOutputAttributes::POSITION_W) + ");\n";
|
||||
out += " vtx_pos = SanitizeVertex(vtx_pos);\n";
|
||||
out += " if (flip_viewport) {\n";
|
||||
out += " vtx_pos.y = -vtx_pos.y;\n";
|
||||
out += " }\n";
|
||||
out += " gl_Position = vec4(vtx_pos.x, vtx_pos.y, -vtx_pos.z, vtx_pos.w);\n";
|
||||
if (config.state.use_clip_planes) {
|
||||
out += " gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0
|
||||
@ -332,6 +339,9 @@ struct Vertex {
|
||||
semantic(VSOutputAttributes::POSITION_Z) + ", " +
|
||||
semantic(VSOutputAttributes::POSITION_W) + ");\n";
|
||||
out += " vtx_pos = SanitizeVertex(vtx_pos);\n";
|
||||
out += " if (flip_viewport) {\n";
|
||||
out += " vtx_pos.y = -vtx_pos.y;\n";
|
||||
out += " }\n";
|
||||
out += " gl_Position = vec4(vtx_pos.x, vtx_pos.y, -vtx_pos.z, vtx_pos.w);\n";
|
||||
if (state.use_clip_planes) {
|
||||
out += " gl_ClipDistance[0] = -vtx_pos.z;\n"; // fixed PICA clipping plane z <= 0
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
// Copyright 2023 Citra Emulator Project
|
||||
// Copyright Citra Emulator Project / Azahar Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@ -86,7 +86,8 @@ struct PicaUniformsData {
|
||||
};
|
||||
|
||||
struct VSUniformData {
|
||||
u32 enable_clip1;
|
||||
alignas(4) bool enable_clip1;
|
||||
alignas(4) bool flip_viewport;
|
||||
alignas(16) Common::Vec4f clip_coef;
|
||||
};
|
||||
static_assert(sizeof(VSUniformData) == 32,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user