renderer_vulkan: Add second screen opacity support

& Update bottom screen opacity label in UI
This commit is contained in:
Briar 2025-04-07 19:18:29 +02:00 committed by OpenSauce
parent 5c5b1cdf45
commit 64f5277789
6 changed files with 40 additions and 7 deletions

View File

@ -1185,8 +1185,7 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView)
"%",
FloatSetting.SECOND_SCREEN_OPACITY.key,
FloatSetting.SECOND_SCREEN_OPACITY.defaultValue,
// TODO: Remove graphics API check when #895 is merged
isEnabled = IntSetting.SCREEN_LAYOUT.int == 5 && IntSetting.GRAPHICS_API.int == 1
isEnabled = IntSetting.SCREEN_LAYOUT.int == 5
)
)
add(HeaderSetting(R.string.bg_color, R.string.bg_color_description))

View File

@ -170,7 +170,7 @@ bg_red =
bg_blue =
bg_green =
# Opacity of second layer when using custom layout option (bottom screen unless swapped). Useful if positioning on top of the first layer. OpenGL only.
# Opacity of second layer when using custom layout option (bottom screen unless swapped). Useful if positioning on top of the first layer.
custom_second_layer_opacity =
# Whether and how Stereoscopic 3D should be rendered

View File

@ -455,7 +455,7 @@
<string name="bg_red">Red</string>
<string name="bg_green">Green</string>
<string name="bg_blue">Blue</string>
<string name="second_screen_opacity">Custom Layout Second Screen Opacity (OpenGL Only)</string>
<string name="second_screen_opacity">Custom Layout Second Screen Opacity</string>
<string name="second_screen_opacity_description">The opacity of the second 3DS screen when using a custom screen layout. Useful if the second screen is to be positioned on top of the first screen.</string>
<string name="emulation_small_screen_position">Small Screen Position</string>
<string name="small_screen_position_description">Where should the small screen appear relative to the large one in Large Screen Layout?</string>

View File

@ -531,7 +531,7 @@
<item>
<widget class="QLabel" name="lb_opacity_second_layer">
<property name="text">
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Bottom Screen Opacity % (OpenGL Only)&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
<string>&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;Bottom Screen Opacity %&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
</widget>
</item>

View File

@ -376,7 +376,13 @@ void RendererVulkan::BuildPipelines() {
};
const vk::PipelineColorBlendAttachmentState colorblend_attachment = {
.blendEnable = false,
.blendEnable = true,
.srcColorBlendFactor = vk::BlendFactor::eConstantAlpha,
.dstColorBlendFactor = vk::BlendFactor::eOneMinusConstantAlpha,
.colorBlendOp = vk::BlendOp::eAdd,
.srcAlphaBlendFactor = vk::BlendFactor::eConstantAlpha,
.dstAlphaBlendFactor = vk::BlendFactor::eOneMinusConstantAlpha,
.alphaBlendOp = vk::BlendOp::eAdd,
.colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
};
@ -385,7 +391,6 @@ void RendererVulkan::BuildPipelines() {
.logicOpEnable = false,
.attachmentCount = 1,
.pAttachments = &colorblend_attachment,
.blendConstants = std::array{1.0f, 1.0f, 1.0f, 1.0f},
};
const vk::Viewport placeholder_viewport = vk::Viewport{0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f};
@ -398,6 +403,7 @@ void RendererVulkan::BuildPipelines() {
};
const std::array dynamic_states = {
vk::DynamicState::eBlendConstants,
vk::DynamicState::eViewport,
vk::DynamicState::eScissor,
};
@ -729,6 +735,13 @@ void RendererVulkan::DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, fl
});
}
void RendererVulkan::ApplySecondLayerOpacity(float alpha) {
scheduler.Record([alpha](vk::CommandBuffer cmdbuf) {
const std::array<float, 4> blend_constants = {0.0f, 0.0f, 0.0f, alpha};
cmdbuf.setBlendConstants(blend_constants.data());
});
}
void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
const Common::Rectangle<u32>& top_screen) {
if (!layout.top_screen_enabled) {
@ -867,13 +880,30 @@ void RendererVulkan::DrawScreens(Frame* frame, const Layout::FramebufferLayout&
draw_info.modelview = MakeOrthographicMatrix(layout.width, layout.height);
draw_info.layer = 0;
// Apply the initial default opacity value; Needed to avoid flickering
ApplySecondLayerOpacity(1.0f);
bool use_custom_opacity =
Settings::values.layout_option.GetValue() == Settings::LayoutOption::CustomLayout &&
Settings::values.custom_second_layer_opacity.GetValue() < 100;
float second_alpha = use_custom_opacity
? Settings::values.custom_second_layer_opacity.GetValue() / 100.0f
: 1.0f;
if (!Settings::values.swap_screen.GetValue()) {
DrawTopScreen(layout, top_screen);
draw_info.layer = 0;
if (use_custom_opacity) {
ApplySecondLayerOpacity(second_alpha);
}
DrawBottomScreen(layout, bottom_screen);
} else {
DrawBottomScreen(layout, bottom_screen);
draw_info.layer = 0;
if (use_custom_opacity) {
ApplySecondLayerOpacity(second_alpha);
}
DrawTopScreen(layout, top_screen);
}

View File

@ -98,12 +98,16 @@ private:
void DrawScreens(Frame* frame, const Layout::FramebufferLayout& layout, bool flipped);
void DrawBottomScreen(const Layout::FramebufferLayout& layout,
const Common::Rectangle<u32>& bottom_screen);
void DrawTopScreen(const Layout::FramebufferLayout& layout,
const Common::Rectangle<u32>& top_screen);
void DrawSingleScreen(u32 screen_id, float x, float y, float w, float h,
Layout::DisplayOrientation orientation);
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
float h, Layout::DisplayOrientation orientation);
void ApplySecondLayerOpacity(float alpha);
void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info,
bool right_eye);
void FillScreen(Common::Vec3<u8> color, const TextureInfo& texture);