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.key,
FloatSetting.SECOND_SCREEN_OPACITY.defaultValue, FloatSetting.SECOND_SCREEN_OPACITY.defaultValue,
// TODO: Remove graphics API check when #895 is merged isEnabled = IntSetting.SCREEN_LAYOUT.int == 5
isEnabled = IntSetting.SCREEN_LAYOUT.int == 5 && IntSetting.GRAPHICS_API.int == 1
) )
) )
add(HeaderSetting(R.string.bg_color, R.string.bg_color_description)) add(HeaderSetting(R.string.bg_color, R.string.bg_color_description))

View File

@ -170,7 +170,7 @@ bg_red =
bg_blue = bg_blue =
bg_green = 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 = custom_second_layer_opacity =
# Whether and how Stereoscopic 3D should be rendered # Whether and how Stereoscopic 3D should be rendered

View File

@ -455,7 +455,7 @@
<string name="bg_red">Red</string> <string name="bg_red">Red</string>
<string name="bg_green">Green</string> <string name="bg_green">Green</string>
<string name="bg_blue">Blue</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="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="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> <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> <item>
<widget class="QLabel" name="lb_opacity_second_layer"> <widget class="QLabel" name="lb_opacity_second_layer">
<property name="text"> <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> </property>
</widget> </widget>
</item> </item>

View File

@ -376,7 +376,13 @@ void RendererVulkan::BuildPipelines() {
}; };
const vk::PipelineColorBlendAttachmentState colorblend_attachment = { 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 | .colorWriteMask = vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG |
vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA, vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA,
}; };
@ -385,7 +391,6 @@ void RendererVulkan::BuildPipelines() {
.logicOpEnable = false, .logicOpEnable = false,
.attachmentCount = 1, .attachmentCount = 1,
.pAttachments = &colorblend_attachment, .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}; 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 = { const std::array dynamic_states = {
vk::DynamicState::eBlendConstants,
vk::DynamicState::eViewport, vk::DynamicState::eViewport,
vk::DynamicState::eScissor, 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, void RendererVulkan::DrawTopScreen(const Layout::FramebufferLayout& layout,
const Common::Rectangle<u32>& top_screen) { const Common::Rectangle<u32>& top_screen) {
if (!layout.top_screen_enabled) { 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.modelview = MakeOrthographicMatrix(layout.width, layout.height);
draw_info.layer = 0; 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()) { if (!Settings::values.swap_screen.GetValue()) {
DrawTopScreen(layout, top_screen); DrawTopScreen(layout, top_screen);
draw_info.layer = 0; draw_info.layer = 0;
if (use_custom_opacity) {
ApplySecondLayerOpacity(second_alpha);
}
DrawBottomScreen(layout, bottom_screen); DrawBottomScreen(layout, bottom_screen);
} else { } else {
DrawBottomScreen(layout, bottom_screen); DrawBottomScreen(layout, bottom_screen);
draw_info.layer = 0; draw_info.layer = 0;
if (use_custom_opacity) {
ApplySecondLayerOpacity(second_alpha);
}
DrawTopScreen(layout, top_screen); DrawTopScreen(layout, top_screen);
} }

View File

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