mirror of
https://github.com/yuzu-emu/yuzu-android.git
synced 2025-06-30 09:57:52 -05:00
Merge pull request #12756 from liamwhite/applet-multiprocess-hwc
general: applet multiprocess
This commit is contained in:
@ -18,6 +18,7 @@ add_library(video_core STATIC
|
||||
buffer_cache/usage_tracker.h
|
||||
buffer_cache/word_manager.h
|
||||
cache_types.h
|
||||
capture.h
|
||||
cdma_pusher.cpp
|
||||
cdma_pusher.h
|
||||
compatible_formats.cpp
|
||||
@ -101,6 +102,7 @@ add_library(video_core STATIC
|
||||
memory_manager.cpp
|
||||
memory_manager.h
|
||||
precompiled_headers.h
|
||||
present.h
|
||||
pte_kind.h
|
||||
query_cache/bank_base.h
|
||||
query_cache/query_base.h
|
||||
|
36
src/video_core/capture.h
Normal file
36
src/video_core/capture.h
Normal file
@ -0,0 +1,36 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/bit_util.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/frontend/framebuffer_layout.h"
|
||||
#include "video_core/surface.h"
|
||||
|
||||
namespace VideoCore::Capture {
|
||||
|
||||
constexpr u32 BlockHeight = 4;
|
||||
constexpr u32 BlockDepth = 0;
|
||||
constexpr u32 BppLog2 = 2;
|
||||
|
||||
constexpr auto PixelFormat = Surface::PixelFormat::B8G8R8A8_UNORM;
|
||||
|
||||
constexpr auto LinearWidth = Layout::ScreenUndocked::Width;
|
||||
constexpr auto LinearHeight = Layout::ScreenUndocked::Height;
|
||||
constexpr auto LinearDepth = 1U;
|
||||
constexpr auto BytesPerPixel = 4U;
|
||||
|
||||
constexpr auto TiledWidth = LinearWidth;
|
||||
constexpr auto TiledHeight = Common::AlignUpLog2(LinearHeight, BlockHeight + BlockDepth + BppLog2);
|
||||
constexpr auto TiledSize = TiledWidth * TiledHeight * (1 << BppLog2);
|
||||
|
||||
constexpr Layout::FramebufferLayout Layout{
|
||||
.width = LinearWidth,
|
||||
.height = LinearHeight,
|
||||
.screen = {0, 0, LinearWidth, LinearHeight},
|
||||
.is_srgb = false,
|
||||
};
|
||||
|
||||
} // namespace VideoCore::Capture
|
@ -11,6 +11,12 @@
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
enum class BlendMode {
|
||||
Opaque,
|
||||
Premultiplied,
|
||||
Coverage,
|
||||
};
|
||||
|
||||
/**
|
||||
* Struct describing framebuffer configuration
|
||||
*/
|
||||
@ -23,6 +29,7 @@ struct FramebufferConfig {
|
||||
Service::android::PixelFormat pixel_format{};
|
||||
Service::android::BufferTransformFlags transform_flags{};
|
||||
Common::Rectangle<int> crop_rect{};
|
||||
BlendMode blending{};
|
||||
};
|
||||
|
||||
Common::Rectangle<f32> NormalizeCrop(const FramebufferConfig& framebuffer, u32 texture_width,
|
||||
|
@ -347,6 +347,17 @@ struct GPU::Impl {
|
||||
WaitForSyncOperation(wait_fence);
|
||||
}
|
||||
|
||||
std::vector<u8> GetAppletCaptureBuffer() {
|
||||
std::vector<u8> out;
|
||||
|
||||
const auto wait_fence =
|
||||
RequestSyncOperation([&] { out = renderer->GetAppletCaptureBuffer(); });
|
||||
gpu_thread.TickGPU();
|
||||
WaitForSyncOperation(wait_fence);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
GPU& gpu;
|
||||
Core::System& system;
|
||||
Host1x::Host1x& host1x;
|
||||
@ -505,6 +516,10 @@ void GPU::RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
|
||||
impl->RequestComposite(std::move(layers), std::move(fences));
|
||||
}
|
||||
|
||||
std::vector<u8> GPU::GetAppletCaptureBuffer() {
|
||||
return impl->GetAppletCaptureBuffer();
|
||||
}
|
||||
|
||||
u64 GPU::GetTicks() const {
|
||||
return impl->GetTicks();
|
||||
}
|
||||
|
@ -215,6 +215,8 @@ public:
|
||||
void RequestComposite(std::vector<Tegra::FramebufferConfig>&& layers,
|
||||
std::vector<Service::Nvidia::NvFence>&& fences);
|
||||
|
||||
std::vector<u8> GetAppletCaptureBuffer();
|
||||
|
||||
/// Performs any additional setup necessary in order to begin GPU emulation.
|
||||
/// This can be used to launch any necessary threads and register any necessary
|
||||
/// core timing events.
|
||||
|
@ -37,6 +37,7 @@ layout(set=0,binding=0) uniform sampler2D InputTexture;
|
||||
|
||||
#define A_GPU 1
|
||||
#define A_GLSL 1
|
||||
#define FSR_RCAS_PASSTHROUGH_ALPHA 1
|
||||
|
||||
#ifndef YUZU_USE_FP16
|
||||
#include "ffx_a.h"
|
||||
@ -71,9 +72,7 @@ layout(set=0,binding=0) uniform sampler2D InputTexture;
|
||||
|
||||
#include "ffx_fsr1.h"
|
||||
|
||||
#if USE_RCAS
|
||||
layout(location = 0) in vec2 frag_texcoord;
|
||||
#endif
|
||||
layout (location = 0) in vec2 frag_texcoord;
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
void CurrFilter(AU2 pos) {
|
||||
@ -81,22 +80,22 @@ void CurrFilter(AU2 pos) {
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrEasuF(c, pos, Const0, Const1, Const2, Const3);
|
||||
frag_color = AF4(c, 1.0);
|
||||
frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
|
||||
#else
|
||||
AH3 c;
|
||||
FsrEasuH(c, pos, Const0, Const1, Const2, Const3);
|
||||
frag_color = AH4(c, 1.0);
|
||||
frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
|
||||
#endif
|
||||
#endif
|
||||
#if USE_RCAS
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrRcasF(c.r, c.g, c.b, pos, Const0);
|
||||
frag_color = AF4(c, 1.0);
|
||||
AF4 c;
|
||||
FsrRcasF(c.r, c.g, c.b, c.a, pos, Const0);
|
||||
frag_color = c;
|
||||
#else
|
||||
AH3 c;
|
||||
FsrRcasH(c.r, c.g, c.b, pos, Const0);
|
||||
frag_color = AH4(c, 1.0);
|
||||
AH4 c;
|
||||
FsrRcasH(c.r, c.g, c.b, c.a, pos, Const0);
|
||||
frag_color = c;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -71,5 +71,5 @@ vec3 FxaaPixelShader(vec4 posPos, sampler2D tex) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
frag_color = vec4(FxaaPixelShader(posPos, input_texture), 1.0);
|
||||
frag_color = vec4(FxaaPixelShader(posPos, input_texture), texture(input_texture, posPos.xy).a);
|
||||
}
|
||||
|
@ -31,6 +31,7 @@ layout (location = 0) uniform uvec4 constants[4];
|
||||
|
||||
#define A_GPU 1
|
||||
#define A_GLSL 1
|
||||
#define FSR_RCAS_PASSTHROUGH_ALPHA 1
|
||||
|
||||
#ifdef YUZU_USE_FP16
|
||||
#define A_HALF
|
||||
@ -67,9 +68,7 @@ layout (location = 0) uniform uvec4 constants[4];
|
||||
|
||||
#include "ffx_fsr1.h"
|
||||
|
||||
#if USE_RCAS
|
||||
layout(location = 0) in vec2 frag_texcoord;
|
||||
#endif
|
||||
layout (location = 0) in vec2 frag_texcoord;
|
||||
layout (location = 0) out vec4 frag_color;
|
||||
|
||||
void CurrFilter(AU2 pos)
|
||||
@ -78,22 +77,22 @@ void CurrFilter(AU2 pos)
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrEasuF(c, pos, constants[0], constants[1], constants[2], constants[3]);
|
||||
frag_color = AF4(c, 1.0);
|
||||
frag_color = AF4(c, texture(InputTexture, frag_texcoord).a);
|
||||
#else
|
||||
AH3 c;
|
||||
FsrEasuH(c, pos, constants[0], constants[1], constants[2], constants[3]);
|
||||
frag_color = AH4(c, 1.0);
|
||||
frag_color = AH4(c, texture(InputTexture, frag_texcoord).a);
|
||||
#endif
|
||||
#endif
|
||||
#if USE_RCAS
|
||||
#ifndef YUZU_USE_FP16
|
||||
AF3 c;
|
||||
FsrRcasF(c.r, c.g, c.b, pos, constants[0]);
|
||||
frag_color = AF4(c, 1.0);
|
||||
AF4 c;
|
||||
FsrRcasF(c.r, c.g, c.b, c.a, pos, constants[0]);
|
||||
frag_color = c;
|
||||
#else
|
||||
AH3 c;
|
||||
FsrRcasH(c.r, c.g, c.b, pos, constants[0]);
|
||||
frag_color = AH4(c, 1.0);
|
||||
FsrRcasH(c.r, c.g, c.b, c.a, pos, constants[0]);
|
||||
frag_color = c;
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
@ -9,5 +9,5 @@ layout (location = 0) out vec4 color;
|
||||
layout (binding = 0) uniform sampler2D color_texture;
|
||||
|
||||
void main() {
|
||||
color = vec4(texture(color_texture, frag_tex_coord).rgb, 1.0f);
|
||||
color = vec4(texture(color_texture, frag_tex_coord));
|
||||
}
|
||||
|
@ -52,5 +52,5 @@ vec4 textureBicubic( sampler2D textureSampler, vec2 texCoords ) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
color = vec4(textureBicubic(color_texture, frag_tex_coord).rgb, 1.0f);
|
||||
color = textureBicubic(color_texture, frag_tex_coord);
|
||||
}
|
||||
|
@ -46,14 +46,14 @@ vec4 blurDiagonal(sampler2D textureSampler, vec2 coord, vec2 norm) {
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 base = texture(color_texture, vec2(frag_tex_coord)).rgb * weight[0];
|
||||
vec4 base = texture(color_texture, vec2(frag_tex_coord)) * weight[0];
|
||||
vec2 tex_offset = 1.0f / textureSize(color_texture, 0);
|
||||
|
||||
// TODO(Blinkhawk): This code can be optimized through shader group instructions.
|
||||
vec3 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset).rgb;
|
||||
vec3 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset).rgb;
|
||||
vec3 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset).rgb;
|
||||
vec3 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0)).rgb;
|
||||
vec3 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
|
||||
color = vec4(combination + base, 1.0f);
|
||||
vec4 horizontal = blurHorizontal(color_texture, frag_tex_coord, tex_offset);
|
||||
vec4 vertical = blurVertical(color_texture, frag_tex_coord, tex_offset);
|
||||
vec4 diagonalA = blurDiagonal(color_texture, frag_tex_coord, tex_offset);
|
||||
vec4 diagonalB = blurDiagonal(color_texture, frag_tex_coord, tex_offset * vec2(1.0, -1.0));
|
||||
vec4 combination = mix(mix(horizontal, vertical, 0.5f), mix(diagonalA, diagonalB, 0.5f), 0.5f);
|
||||
color = combination + base;
|
||||
}
|
||||
|
@ -6,5 +6,6 @@
|
||||
|
||||
#define YUZU_USE_FP16
|
||||
#define USE_EASU 1
|
||||
#define VERSION 1
|
||||
|
||||
#include "fidelityfx_fsr.frag"
|
||||
|
@ -5,5 +5,6 @@
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define USE_EASU 1
|
||||
#define VERSION 1
|
||||
|
||||
#include "fidelityfx_fsr.frag"
|
||||
|
@ -6,5 +6,6 @@
|
||||
|
||||
#define YUZU_USE_FP16
|
||||
#define USE_RCAS 1
|
||||
#define VERSION 1
|
||||
|
||||
#include "fidelityfx_fsr.frag"
|
||||
|
@ -5,5 +5,6 @@
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define USE_RCAS 1
|
||||
#define VERSION 1
|
||||
|
||||
#include "fidelityfx_fsr.frag"
|
||||
|
@ -5,7 +5,7 @@
|
||||
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define VERSION 1
|
||||
#define VERSION 2
|
||||
#define YUZU_USE_FP16
|
||||
|
||||
#include "opengl_present_scaleforce.frag"
|
||||
|
@ -5,6 +5,6 @@
|
||||
|
||||
#extension GL_GOOGLE_include_directive : enable
|
||||
|
||||
#define VERSION 1
|
||||
#define VERSION 2
|
||||
|
||||
#include "opengl_present_scaleforce.frag"
|
||||
|
37
src/video_core/present.h
Normal file
37
src/video_core/present.h
Normal file
@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/settings.h"
|
||||
|
||||
static inline Settings::ScalingFilter GetScalingFilter() {
|
||||
return Settings::values.scaling_filter.GetValue();
|
||||
}
|
||||
|
||||
static inline Settings::AntiAliasing GetAntiAliasing() {
|
||||
return Settings::values.anti_aliasing.GetValue();
|
||||
}
|
||||
|
||||
static inline Settings::ScalingFilter GetScalingFilterForAppletCapture() {
|
||||
return Settings::ScalingFilter::Bilinear;
|
||||
}
|
||||
|
||||
static inline Settings::AntiAliasing GetAntiAliasingForAppletCapture() {
|
||||
return Settings::AntiAliasing::None;
|
||||
}
|
||||
|
||||
struct PresentFilters {
|
||||
Settings::ScalingFilter (*get_scaling_filter)();
|
||||
Settings::AntiAliasing (*get_anti_aliasing)();
|
||||
};
|
||||
|
||||
constexpr PresentFilters PresentFiltersForDisplay{
|
||||
.get_scaling_filter = &GetScalingFilter,
|
||||
.get_anti_aliasing = &GetAntiAliasing,
|
||||
};
|
||||
|
||||
constexpr PresentFilters PresentFiltersForAppletCapture{
|
||||
.get_scaling_filter = &GetScalingFilterForAppletCapture,
|
||||
.get_anti_aliasing = &GetAntiAliasingForAppletCapture,
|
||||
};
|
@ -40,6 +40,9 @@ public:
|
||||
/// Finalize rendering the guest frame and draw into the presentation texture
|
||||
virtual void Composite(std::span<const Tegra::FramebufferConfig> layers) = 0;
|
||||
|
||||
/// Get the tiled applet layer capture buffer
|
||||
virtual std::vector<u8> GetAppletCaptureBuffer() = 0;
|
||||
|
||||
[[nodiscard]] virtual RasterizerInterface* ReadRasterizer() = 0;
|
||||
|
||||
[[nodiscard]] virtual std::string GetDeviceVendor() const = 0;
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/graphics_context.h"
|
||||
#include "video_core/capture.h"
|
||||
#include "video_core/renderer_null/renderer_null.h"
|
||||
|
||||
namespace Null {
|
||||
@ -22,4 +23,8 @@ void RendererNull::Composite(std::span<const Tegra::FramebufferConfig> framebuff
|
||||
render_window.OnFrameDisplayed();
|
||||
}
|
||||
|
||||
std::vector<u8> RendererNull::GetAppletCaptureBuffer() {
|
||||
return std::vector<u8>(VideoCore::Capture::TiledSize);
|
||||
}
|
||||
|
||||
} // namespace Null
|
||||
|
@ -19,6 +19,8 @@ public:
|
||||
|
||||
void Composite(std::span<const Tegra::FramebufferConfig> framebuffer) override;
|
||||
|
||||
std::vector<u8> GetAppletCaptureBuffer() override;
|
||||
|
||||
VideoCore::RasterizerInterface* ReadRasterizer() override {
|
||||
return &m_rasterizer;
|
||||
}
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_opengl/gl_blit_screen.h"
|
||||
#include "video_core/renderer_opengl/gl_state_tracker.h"
|
||||
#include "video_core/renderer_opengl/present/filters.h"
|
||||
@ -13,14 +14,14 @@ namespace OpenGL {
|
||||
BlitScreen::BlitScreen(RasterizerOpenGL& rasterizer_,
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
StateTracker& state_tracker_, ProgramManager& program_manager_,
|
||||
Device& device_)
|
||||
Device& device_, const PresentFilters& filters_)
|
||||
: rasterizer(rasterizer_), device_memory(device_memory_), state_tracker(state_tracker_),
|
||||
program_manager(program_manager_), device(device_) {}
|
||||
program_manager(program_manager_), device(device_), filters(filters_) {}
|
||||
|
||||
BlitScreen::~BlitScreen() = default;
|
||||
|
||||
void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout) {
|
||||
const Layout::FramebufferLayout& layout, bool invert_y) {
|
||||
// TODO: Signal state tracker about these changes
|
||||
state_tracker.NotifyScreenDrawVertexArray();
|
||||
state_tracker.NotifyPolygonModes();
|
||||
@ -56,22 +57,22 @@ void BlitScreen::DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffe
|
||||
glDepthRangeIndexed(0, 0.0, 0.0);
|
||||
|
||||
while (layers.size() < framebuffers.size()) {
|
||||
layers.emplace_back(rasterizer, device_memory);
|
||||
layers.emplace_back(rasterizer, device_memory, filters);
|
||||
}
|
||||
|
||||
CreateWindowAdapt();
|
||||
window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout);
|
||||
window_adapt->DrawToFramebuffer(program_manager, layers, framebuffers, layout, invert_y);
|
||||
|
||||
// TODO
|
||||
// program_manager.RestoreGuestPipeline();
|
||||
}
|
||||
|
||||
void BlitScreen::CreateWindowAdapt() {
|
||||
if (window_adapt && Settings::values.scaling_filter.GetValue() == current_window_adapt) {
|
||||
if (window_adapt && filters.get_scaling_filter() == current_window_adapt) {
|
||||
return;
|
||||
}
|
||||
|
||||
current_window_adapt = Settings::values.scaling_filter.GetValue();
|
||||
current_window_adapt = filters.get_scaling_filter();
|
||||
switch (current_window_adapt) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
window_adapt = MakeNearestNeighbor(device);
|
||||
|
@ -15,6 +15,8 @@ namespace Layout {
|
||||
struct FramebufferLayout;
|
||||
}
|
||||
|
||||
struct PresentFilters;
|
||||
|
||||
namespace Tegra {
|
||||
struct FramebufferConfig;
|
||||
}
|
||||
@ -46,12 +48,12 @@ public:
|
||||
explicit BlitScreen(RasterizerOpenGL& rasterizer,
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory,
|
||||
StateTracker& state_tracker, ProgramManager& program_manager,
|
||||
Device& device);
|
||||
Device& device, const PresentFilters& filters);
|
||||
~BlitScreen();
|
||||
|
||||
/// Draws the emulated screens to the emulator window.
|
||||
void DrawScreen(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout);
|
||||
const Layout::FramebufferLayout& layout, bool invert_y);
|
||||
|
||||
private:
|
||||
void CreateWindowAdapt();
|
||||
@ -61,6 +63,7 @@ private:
|
||||
StateTracker& state_tracker;
|
||||
ProgramManager& program_manager;
|
||||
Device& device;
|
||||
const PresentFilters& filters;
|
||||
|
||||
Settings::ScalingFilter current_window_adapt{};
|
||||
std::unique_ptr<WindowAdaptPass> window_adapt;
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/framebuffer_config.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_opengl/gl_blit_screen.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/present/fsr.h"
|
||||
@ -14,8 +15,9 @@
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_)
|
||||
: rasterizer(rasterizer_), device_memory(device_memory_) {
|
||||
Layer::Layer(RasterizerOpenGL& rasterizer_, Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
const PresentFilters& filters_)
|
||||
: rasterizer(rasterizer_), device_memory(device_memory_), filters(filters_) {
|
||||
// Allocate textures for the screen
|
||||
framebuffer_texture.resource.Create(GL_TEXTURE_2D);
|
||||
|
||||
@ -34,12 +36,12 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
|
||||
std::array<ScreenRectVertex, 4>& out_vertices,
|
||||
ProgramManager& program_manager,
|
||||
const Tegra::FramebufferConfig& framebuffer,
|
||||
const Layout::FramebufferLayout& layout) {
|
||||
const Layout::FramebufferLayout& layout, bool invert_y) {
|
||||
FramebufferTextureInfo info = PrepareRenderTarget(framebuffer);
|
||||
auto crop = Tegra::NormalizeCrop(framebuffer, info.width, info.height);
|
||||
GLuint texture = info.display_texture;
|
||||
|
||||
auto anti_aliasing = Settings::values.anti_aliasing.GetValue();
|
||||
auto anti_aliasing = filters.get_anti_aliasing();
|
||||
if (anti_aliasing != Settings::AntiAliasing::None) {
|
||||
glEnablei(GL_SCISSOR_TEST, 0);
|
||||
auto viewport_width = Settings::values.resolution_info.ScaleUp(framebuffer_texture.width);
|
||||
@ -64,7 +66,7 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
|
||||
|
||||
glDisablei(GL_SCISSOR_TEST, 0);
|
||||
|
||||
if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
|
||||
if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
|
||||
if (!fsr || fsr->NeedsRecreation(layout.screen)) {
|
||||
fsr = std::make_unique<FSR>(layout.screen.GetWidth(), layout.screen.GetHeight());
|
||||
}
|
||||
@ -83,10 +85,15 @@ GLuint Layer::ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
|
||||
const auto w = screen.GetWidth();
|
||||
const auto h = screen.GetHeight();
|
||||
|
||||
out_vertices[0] = ScreenRectVertex(x, y, crop.left, crop.top);
|
||||
out_vertices[1] = ScreenRectVertex(x + w, y, crop.right, crop.top);
|
||||
out_vertices[2] = ScreenRectVertex(x, y + h, crop.left, crop.bottom);
|
||||
out_vertices[3] = ScreenRectVertex(x + w, y + h, crop.right, crop.bottom);
|
||||
const auto left = crop.left;
|
||||
const auto right = crop.right;
|
||||
const auto top = invert_y ? crop.bottom : crop.top;
|
||||
const auto bottom = invert_y ? crop.top : crop.bottom;
|
||||
|
||||
out_vertices[0] = ScreenRectVertex(x, y, left, top);
|
||||
out_vertices[1] = ScreenRectVertex(x + w, y, right, top);
|
||||
out_vertices[2] = ScreenRectVertex(x, y + h, left, bottom);
|
||||
out_vertices[3] = ScreenRectVertex(x + w, y + h, right, bottom);
|
||||
|
||||
return texture;
|
||||
}
|
||||
@ -131,10 +138,12 @@ FramebufferTextureInfo Layer::LoadFBToScreenInfo(const Tegra::FramebufferConfig&
|
||||
const u64 size_in_bytes{Tegra::Texture::CalculateSize(
|
||||
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
|
||||
const u8* const host_ptr{device_memory.GetPointer<u8>(framebuffer_addr)};
|
||||
const std::span<const u8> input_data(host_ptr, size_in_bytes);
|
||||
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
|
||||
framebuffer.width, framebuffer.height, 1, block_height_log2,
|
||||
0);
|
||||
if (host_ptr) {
|
||||
const std::span<const u8> input_data(host_ptr, size_in_bytes);
|
||||
Tegra::Texture::UnswizzleTexture(gl_framebuffer_data, input_data, bytes_per_pixel,
|
||||
framebuffer.width, framebuffer.height, 1,
|
||||
block_height_log2, 0);
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(framebuffer.stride));
|
||||
|
@ -13,6 +13,8 @@ namespace Layout {
|
||||
struct FramebufferLayout;
|
||||
}
|
||||
|
||||
struct PresentFilters;
|
||||
|
||||
namespace Service::android {
|
||||
enum class PixelFormat : u32;
|
||||
};
|
||||
@ -44,14 +46,15 @@ struct ScreenRectVertex;
|
||||
|
||||
class Layer {
|
||||
public:
|
||||
explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory);
|
||||
explicit Layer(RasterizerOpenGL& rasterizer, Tegra::MaxwellDeviceMemoryManager& device_memory,
|
||||
const PresentFilters& filters);
|
||||
~Layer();
|
||||
|
||||
GLuint ConfigureDraw(std::array<GLfloat, 3 * 2>& out_matrix,
|
||||
std::array<ScreenRectVertex, 4>& out_vertices,
|
||||
ProgramManager& program_manager,
|
||||
const Tegra::FramebufferConfig& framebuffer,
|
||||
const Layout::FramebufferLayout& layout);
|
||||
const Layout::FramebufferLayout& layout, bool invert_y);
|
||||
|
||||
private:
|
||||
/// Loads framebuffer from emulated memory into the active OpenGL texture.
|
||||
@ -65,6 +68,7 @@ private:
|
||||
private:
|
||||
RasterizerOpenGL& rasterizer;
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
const PresentFilters& filters;
|
||||
|
||||
/// OpenGL framebuffer data
|
||||
std::vector<u8> gl_framebuffer_data;
|
||||
|
@ -37,7 +37,7 @@ WindowAdaptPass::~WindowAdaptPass() = default;
|
||||
|
||||
void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers,
|
||||
std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout) {
|
||||
const Layout::FramebufferLayout& layout, bool invert_y) {
|
||||
GLint old_read_fb;
|
||||
GLint old_draw_fb;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
|
||||
@ -51,7 +51,7 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li
|
||||
auto layer_it = layers.begin();
|
||||
for (size_t i = 0; i < layer_count; i++) {
|
||||
textures[i] = layer_it->ConfigureDraw(matrices[i], vertices[i], program_manager,
|
||||
framebuffers[i], layout);
|
||||
framebuffers[i], layout, invert_y);
|
||||
layer_it++;
|
||||
}
|
||||
|
||||
@ -92,6 +92,21 @@ void WindowAdaptPass::DrawToFramebuffer(ProgramManager& program_manager, std::li
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
for (size_t i = 0; i < layer_count; i++) {
|
||||
switch (framebuffers[i].blending) {
|
||||
case Tegra::BlendMode::Opaque:
|
||||
default:
|
||||
glDisablei(GL_BLEND, 0);
|
||||
break;
|
||||
case Tegra::BlendMode::Premultiplied:
|
||||
glEnablei(GL_BLEND, 0);
|
||||
glBlendFuncSeparatei(0, GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
case Tegra::BlendMode::Coverage:
|
||||
glEnablei(GL_BLEND, 0);
|
||||
glBlendFuncSeparatei(0, GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ZERO);
|
||||
break;
|
||||
}
|
||||
|
||||
glBindTextureUnit(0, textures[i]);
|
||||
glProgramUniformMatrix3x2fv(vert.handle, ModelViewMatrixLocation, 1, GL_FALSE,
|
||||
matrices[i].data());
|
||||
|
@ -31,7 +31,7 @@ public:
|
||||
|
||||
void DrawToFramebuffer(ProgramManager& program_manager, std::list<Layer>& layers,
|
||||
std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout);
|
||||
const Layout::FramebufferLayout& layout, bool invert_y);
|
||||
|
||||
private:
|
||||
const Device& device;
|
||||
|
@ -16,6 +16,8 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/telemetry_session.h"
|
||||
#include "video_core/capture.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_opengl/gl_blit_screen.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
@ -120,7 +122,15 @@ RendererOpenGL::RendererOpenGL(Core::TelemetrySession& telemetry_session_,
|
||||
glEnableClientState(GL_ELEMENT_ARRAY_UNIFIED_NV);
|
||||
}
|
||||
blit_screen = std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker,
|
||||
program_manager, device);
|
||||
program_manager, device, PresentFiltersForDisplay);
|
||||
blit_applet =
|
||||
std::make_unique<BlitScreen>(rasterizer, device_memory, state_tracker, program_manager,
|
||||
device, PresentFiltersForAppletCapture);
|
||||
capture_framebuffer.Create();
|
||||
capture_renderbuffer.Create();
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, capture_renderbuffer.handle);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, VideoCore::Capture::LinearWidth,
|
||||
VideoCore::Capture::LinearHeight);
|
||||
}
|
||||
|
||||
RendererOpenGL::~RendererOpenGL() = default;
|
||||
@ -130,10 +140,11 @@ void RendererOpenGL::Composite(std::span<const Tegra::FramebufferConfig> framebu
|
||||
return;
|
||||
}
|
||||
|
||||
RenderAppletCaptureLayer(framebuffers);
|
||||
RenderScreenshot(framebuffers);
|
||||
|
||||
state_tracker.BindFramebuffer(0);
|
||||
blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout());
|
||||
blit_screen->DrawScreen(framebuffers, emu_window.GetFramebufferLayout(), false);
|
||||
|
||||
++m_current_frame;
|
||||
|
||||
@ -159,11 +170,8 @@ void RendererOpenGL::AddTelemetryFields() {
|
||||
telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string(gl_version));
|
||||
}
|
||||
|
||||
void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (!renderer_settings.screenshot_requested) {
|
||||
return;
|
||||
}
|
||||
|
||||
void RendererOpenGL::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout, void* dst) {
|
||||
GLint old_read_fb;
|
||||
GLint old_draw_fb;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
|
||||
@ -173,29 +181,86 @@ void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig>
|
||||
screenshot_framebuffer.Create();
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, screenshot_framebuffer.handle);
|
||||
|
||||
const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
|
||||
|
||||
GLuint renderbuffer;
|
||||
glGenRenderbuffers(1, &renderbuffer);
|
||||
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
|
||||
glRenderbufferStorage(GL_RENDERBUFFER, GL_SRGB8, layout.width, layout.height);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, renderbuffer);
|
||||
|
||||
blit_screen->DrawScreen(framebuffers, layout);
|
||||
blit_screen->DrawScreen(framebuffers, layout, false);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
renderer_settings.screenshot_bits);
|
||||
glReadPixels(0, 0, layout.width, layout.height, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, dst);
|
||||
|
||||
screenshot_framebuffer.Release();
|
||||
glDeleteRenderbuffers(1, &renderbuffer);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
|
||||
}
|
||||
|
||||
void RendererOpenGL::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (!renderer_settings.screenshot_requested) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderToBuffer(framebuffers, renderer_settings.screenshot_framebuffer_layout,
|
||||
renderer_settings.screenshot_bits);
|
||||
|
||||
renderer_settings.screenshot_complete_callback(true);
|
||||
renderer_settings.screenshot_requested = false;
|
||||
}
|
||||
|
||||
void RendererOpenGL::RenderAppletCaptureLayer(
|
||||
std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
GLint old_read_fb;
|
||||
GLint old_draw_fb;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
|
||||
capture_renderbuffer.handle);
|
||||
|
||||
blit_applet->DrawScreen(framebuffers, VideoCore::Capture::Layout, true);
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
|
||||
}
|
||||
|
||||
std::vector<u8> RendererOpenGL::GetAppletCaptureBuffer() {
|
||||
using namespace VideoCore::Capture;
|
||||
|
||||
std::vector<u8> linear(TiledSize);
|
||||
std::vector<u8> out(TiledSize);
|
||||
|
||||
GLint old_read_fb;
|
||||
GLint old_draw_fb;
|
||||
GLint old_pixel_pack_buffer;
|
||||
GLint old_pack_row_length;
|
||||
glGetIntegerv(GL_READ_FRAMEBUFFER_BINDING, &old_read_fb);
|
||||
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, &old_draw_fb);
|
||||
glGetIntegerv(GL_PIXEL_PACK_BUFFER_BINDING, &old_pixel_pack_buffer);
|
||||
glGetIntegerv(GL_PACK_ROW_LENGTH, &old_pack_row_length);
|
||||
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, capture_framebuffer.handle);
|
||||
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
|
||||
capture_renderbuffer.handle);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, 0);
|
||||
glReadPixels(0, 0, LinearWidth, LinearHeight, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
linear.data());
|
||||
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, old_read_fb);
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, old_draw_fb);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, old_pixel_pack_buffer);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, old_pack_row_length);
|
||||
|
||||
Tegra::Texture::SwizzleTexture(out, linear, BytesPerPixel, LinearWidth, LinearHeight,
|
||||
LinearDepth, BlockHeight, BlockDepth);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -42,6 +42,8 @@ public:
|
||||
|
||||
void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override;
|
||||
|
||||
std::vector<u8> GetAppletCaptureBuffer() override;
|
||||
|
||||
VideoCore::RasterizerInterface* ReadRasterizer() override {
|
||||
return &rasterizer;
|
||||
}
|
||||
@ -52,7 +54,11 @@ public:
|
||||
|
||||
private:
|
||||
void AddTelemetryFields();
|
||||
|
||||
void RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout, void* dst);
|
||||
void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers);
|
||||
void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers);
|
||||
|
||||
Core::TelemetrySession& telemetry_session;
|
||||
Core::Frontend::EmuWindow& emu_window;
|
||||
@ -64,8 +70,11 @@ private:
|
||||
ProgramManager program_manager;
|
||||
RasterizerOpenGL rasterizer;
|
||||
OGLFramebuffer screenshot_framebuffer;
|
||||
OGLFramebuffer capture_framebuffer;
|
||||
OGLRenderbuffer capture_renderbuffer;
|
||||
|
||||
std::unique_ptr<BlitScreen> blit_screen;
|
||||
std::unique_ptr<BlitScreen> blit_applet;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
@ -1,6 +1,7 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_vulkan/vk_rasterizer.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
@ -48,12 +49,12 @@ VkFormat GetFormat(const Tegra::FramebufferConfig& framebuffer) {
|
||||
|
||||
Layer::Layer(const Device& device_, MemoryAllocator& memory_allocator_, Scheduler& scheduler_,
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory_, size_t image_count_,
|
||||
VkExtent2D output_size, VkDescriptorSetLayout layout)
|
||||
VkExtent2D output_size, VkDescriptorSetLayout layout, const PresentFilters& filters_)
|
||||
: device(device_), memory_allocator(memory_allocator_), scheduler(scheduler_),
|
||||
device_memory(device_memory_), image_count(image_count_) {
|
||||
device_memory(device_memory_), filters(filters_), image_count(image_count_) {
|
||||
CreateDescriptorPool();
|
||||
CreateDescriptorSets(layout);
|
||||
if (Settings::values.scaling_filter.GetValue() == Settings::ScalingFilter::Fsr) {
|
||||
if (filters.get_scaling_filter() == Settings::ScalingFilter::Fsr) {
|
||||
CreateFSR(output_size);
|
||||
}
|
||||
}
|
||||
@ -171,11 +172,11 @@ void Layer::RefreshResources(const Tegra::FramebufferConfig& framebuffer) {
|
||||
}
|
||||
|
||||
void Layer::SetAntiAliasPass() {
|
||||
if (anti_alias && anti_alias_setting == Settings::values.anti_aliasing.GetValue()) {
|
||||
if (anti_alias && anti_alias_setting == filters.get_anti_aliasing()) {
|
||||
return;
|
||||
}
|
||||
|
||||
anti_alias_setting = Settings::values.anti_aliasing.GetValue();
|
||||
anti_alias_setting = filters.get_anti_aliasing();
|
||||
|
||||
const VkExtent2D render_area{
|
||||
.width = Settings::values.resolution_info.ScaleUp(raw_width),
|
||||
@ -270,9 +271,11 @@ void Layer::UpdateRawImage(const Tegra::FramebufferConfig& framebuffer, size_t i
|
||||
const u64 linear_size{GetSizeInBytes(framebuffer)};
|
||||
const u64 tiled_size{Tegra::Texture::CalculateSize(
|
||||
true, bytes_per_pixel, framebuffer.stride, framebuffer.height, 1, block_height_log2, 0)};
|
||||
Tegra::Texture::UnswizzleTexture(
|
||||
mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
|
||||
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
|
||||
if (host_ptr) {
|
||||
Tegra::Texture::UnswizzleTexture(
|
||||
mapped_span.subspan(image_offset, linear_size), std::span(host_ptr, tiled_size),
|
||||
bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0);
|
||||
}
|
||||
|
||||
const VkBufferImageCopy copy{
|
||||
.bufferOffset = image_offset,
|
||||
|
@ -11,6 +11,8 @@ namespace Layout {
|
||||
struct FramebufferLayout;
|
||||
}
|
||||
|
||||
struct PresentFilters;
|
||||
|
||||
namespace Tegra {
|
||||
struct FramebufferConfig;
|
||||
}
|
||||
@ -37,7 +39,8 @@ class Layer final {
|
||||
public:
|
||||
explicit Layer(const Device& device, MemoryAllocator& memory_allocator, Scheduler& scheduler,
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory, size_t image_count,
|
||||
VkExtent2D output_size, VkDescriptorSetLayout layout);
|
||||
VkExtent2D output_size, VkDescriptorSetLayout layout,
|
||||
const PresentFilters& filters);
|
||||
~Layer();
|
||||
|
||||
void ConfigureDraw(PresentPushConstants* out_push_constants,
|
||||
@ -71,6 +74,7 @@ private:
|
||||
MemoryAllocator& memory_allocator;
|
||||
Scheduler& scheduler;
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
const PresentFilters& filters;
|
||||
const size_t image_count{};
|
||||
vk::DescriptorPool descriptor_pool{};
|
||||
vk::DescriptorSets descriptor_sets{};
|
||||
|
@ -362,10 +362,10 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
|
||||
});
|
||||
}
|
||||
|
||||
vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
|
||||
vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
|
||||
bool enable_blending) {
|
||||
static vk::Pipeline CreateWrappedPipelineImpl(
|
||||
const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
|
||||
VkPipelineColorBlendAttachmentState blending) {
|
||||
const std::array<VkPipelineShaderStageCreateInfo, 2> shader_stages{{
|
||||
{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,
|
||||
@ -443,30 +443,6 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
|
||||
.alphaToOneEnable = VK_FALSE,
|
||||
};
|
||||
|
||||
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
|
||||
.blendEnable = VK_FALSE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_enabled{
|
||||
.blendEnable = VK_TRUE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
const VkPipelineColorBlendStateCreateInfo color_blend_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@ -474,8 +450,7 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
|
||||
.logicOpEnable = VK_FALSE,
|
||||
.logicOp = VK_LOGIC_OP_COPY,
|
||||
.attachmentCount = 1,
|
||||
.pAttachments =
|
||||
enable_blending ? &color_blend_attachment_enabled : &color_blend_attachment_disabled,
|
||||
.pAttachments = &blending,
|
||||
.blendConstants = {0.0f, 0.0f, 0.0f, 0.0f},
|
||||
};
|
||||
|
||||
@ -515,6 +490,63 @@ vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderp
|
||||
});
|
||||
}
|
||||
|
||||
vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
|
||||
vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
|
||||
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_disabled{
|
||||
.blendEnable = VK_FALSE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
|
||||
color_blend_attachment_disabled);
|
||||
}
|
||||
|
||||
vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
|
||||
const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
|
||||
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_premultiplied{
|
||||
.blendEnable = VK_TRUE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
|
||||
color_blend_attachment_premultiplied);
|
||||
}
|
||||
|
||||
vk::Pipeline CreateWrappedCoverageBlendingPipeline(
|
||||
const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders) {
|
||||
constexpr VkPipelineColorBlendAttachmentState color_blend_attachment_coverage{
|
||||
.blendEnable = VK_TRUE,
|
||||
.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA,
|
||||
.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = VK_BLEND_OP_ADD,
|
||||
.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE,
|
||||
.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO,
|
||||
.alphaBlendOp = VK_BLEND_OP_ADD,
|
||||
.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT,
|
||||
};
|
||||
|
||||
return CreateWrappedPipelineImpl(device, renderpass, layout, shaders,
|
||||
color_blend_attachment_coverage);
|
||||
}
|
||||
|
||||
VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
|
||||
VkSampler sampler, VkImageView view,
|
||||
VkDescriptorSet set, u32 binding) {
|
||||
|
@ -42,8 +42,13 @@ vk::PipelineLayout CreateWrappedPipelineLayout(const Device& device,
|
||||
vk::DescriptorSetLayout& layout);
|
||||
vk::Pipeline CreateWrappedPipeline(const Device& device, vk::RenderPass& renderpass,
|
||||
vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders,
|
||||
bool enable_blending = false);
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
|
||||
vk::Pipeline CreateWrappedPremultipliedBlendingPipeline(
|
||||
const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
|
||||
vk::Pipeline CreateWrappedCoverageBlendingPipeline(
|
||||
const Device& device, vk::RenderPass& renderpass, vk::PipelineLayout& layout,
|
||||
std::tuple<vk::ShaderModule&, vk::ShaderModule&> shaders);
|
||||
VkWriteDescriptorSet CreateWriteDescriptorSet(std::vector<VkDescriptorImageInfo>& images,
|
||||
VkSampler sampler, VkImageView view,
|
||||
VkDescriptorSet set, u32 binding);
|
||||
|
@ -22,7 +22,7 @@ WindowAdaptPass::WindowAdaptPass(const Device& device_, VkFormat frame_format,
|
||||
CreatePipelineLayout();
|
||||
CreateVertexShader();
|
||||
CreateRenderPass(frame_format);
|
||||
CreatePipeline();
|
||||
CreatePipelines();
|
||||
}
|
||||
|
||||
WindowAdaptPass::~WindowAdaptPass() = default;
|
||||
@ -34,7 +34,6 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
|
||||
|
||||
const VkFramebuffer host_framebuffer{*dst->framebuffer};
|
||||
const VkRenderPass renderpass{*render_pass};
|
||||
const VkPipeline graphics_pipeline{*pipeline};
|
||||
const VkPipelineLayout graphics_pipeline_layout{*pipeline_layout};
|
||||
const VkExtent2D render_area{
|
||||
.width = dst->width,
|
||||
@ -44,9 +43,23 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
|
||||
const size_t layer_count = configs.size();
|
||||
std::vector<PresentPushConstants> push_constants(layer_count);
|
||||
std::vector<VkDescriptorSet> descriptor_sets(layer_count);
|
||||
std::vector<VkPipeline> graphics_pipelines(layer_count);
|
||||
|
||||
auto layer_it = layers.begin();
|
||||
for (size_t i = 0; i < layer_count; i++) {
|
||||
switch (configs[i].blending) {
|
||||
case Tegra::BlendMode::Opaque:
|
||||
default:
|
||||
graphics_pipelines[i] = *opaque_pipeline;
|
||||
break;
|
||||
case Tegra::BlendMode::Premultiplied:
|
||||
graphics_pipelines[i] = *premultiplied_pipeline;
|
||||
break;
|
||||
case Tegra::BlendMode::Coverage:
|
||||
graphics_pipelines[i] = *coverage_pipeline;
|
||||
break;
|
||||
}
|
||||
|
||||
layer_it->ConfigureDraw(&push_constants[i], &descriptor_sets[i], rasterizer, *sampler,
|
||||
image_index, configs[i], layout);
|
||||
layer_it++;
|
||||
@ -77,8 +90,8 @@ void WindowAdaptPass::Draw(RasterizerVulkan& rasterizer, Scheduler& scheduler, s
|
||||
BeginRenderPass(cmdbuf, renderpass, host_framebuffer, render_area);
|
||||
cmdbuf.ClearAttachments({clear_attachment}, {clear_rect});
|
||||
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline);
|
||||
for (size_t i = 0; i < layer_count; i++) {
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipelines[i]);
|
||||
cmdbuf.PushConstants(graphics_pipeline_layout, VK_SHADER_STAGE_VERTEX_BIT,
|
||||
push_constants[i]);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_GRAPHICS, graphics_pipeline_layout, 0,
|
||||
@ -129,9 +142,13 @@ void WindowAdaptPass::CreateRenderPass(VkFormat frame_format) {
|
||||
render_pass = CreateWrappedRenderPass(device, frame_format, VK_IMAGE_LAYOUT_UNDEFINED);
|
||||
}
|
||||
|
||||
void WindowAdaptPass::CreatePipeline() {
|
||||
pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
|
||||
std::tie(vertex_shader, fragment_shader), false);
|
||||
void WindowAdaptPass::CreatePipelines() {
|
||||
opaque_pipeline = CreateWrappedPipeline(device, render_pass, pipeline_layout,
|
||||
std::tie(vertex_shader, fragment_shader));
|
||||
premultiplied_pipeline = CreateWrappedPremultipliedBlendingPipeline(
|
||||
device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
|
||||
coverage_pipeline = CreateWrappedCoverageBlendingPipeline(
|
||||
device, render_pass, pipeline_layout, std::tie(vertex_shader, fragment_shader));
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -42,7 +42,7 @@ private:
|
||||
void CreatePipelineLayout();
|
||||
void CreateVertexShader();
|
||||
void CreateRenderPass(VkFormat frame_format);
|
||||
void CreatePipeline();
|
||||
void CreatePipelines();
|
||||
|
||||
private:
|
||||
const Device& device;
|
||||
@ -52,7 +52,9 @@ private:
|
||||
vk::ShaderModule vertex_shader;
|
||||
vk::ShaderModule fragment_shader;
|
||||
vk::RenderPass render_pass;
|
||||
vk::Pipeline pipeline;
|
||||
vk::Pipeline opaque_pipeline;
|
||||
vk::Pipeline premultiplied_pipeline;
|
||||
vk::Pipeline coverage_pipeline;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -19,7 +19,9 @@
|
||||
#include "core/core_timing.h"
|
||||
#include "core/frontend/graphics_context.h"
|
||||
#include "core/telemetry_session.h"
|
||||
#include "video_core/capture.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_vulkan/present/util.h"
|
||||
#include "video_core/renderer_vulkan/renderer_vulkan.h"
|
||||
#include "video_core/renderer_vulkan/vk_blit_screen.h"
|
||||
@ -38,6 +40,20 @@
|
||||
|
||||
namespace Vulkan {
|
||||
namespace {
|
||||
|
||||
constexpr VkExtent2D CaptureImageSize{
|
||||
.width = VideoCore::Capture::LinearWidth,
|
||||
.height = VideoCore::Capture::LinearHeight,
|
||||
};
|
||||
|
||||
constexpr VkExtent3D CaptureImageExtent{
|
||||
.width = VideoCore::Capture::LinearWidth,
|
||||
.height = VideoCore::Capture::LinearHeight,
|
||||
.depth = VideoCore::Capture::LinearDepth,
|
||||
};
|
||||
|
||||
constexpr VkFormat CaptureFormat = VK_FORMAT_A8B8G8R8_UNORM_PACK32;
|
||||
|
||||
std::string GetReadableVersion(u32 version) {
|
||||
return fmt::format("{}.{}.{}", VK_VERSION_MAJOR(version), VK_VERSION_MINOR(version),
|
||||
VK_VERSION_PATCH(version));
|
||||
@ -99,10 +115,15 @@ RendererVulkan::RendererVulkan(Core::TelemetrySession& telemetry_session_,
|
||||
render_window.GetFramebufferLayout().height),
|
||||
present_manager(instance, render_window, device, memory_allocator, scheduler, swapchain,
|
||||
surface),
|
||||
blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler),
|
||||
blit_screenshot(device_memory, device, memory_allocator, present_manager, scheduler),
|
||||
blit_swapchain(device_memory, device, memory_allocator, present_manager, scheduler,
|
||||
PresentFiltersForDisplay),
|
||||
blit_capture(device_memory, device, memory_allocator, present_manager, scheduler,
|
||||
PresentFiltersForDisplay),
|
||||
blit_applet(device_memory, device, memory_allocator, present_manager, scheduler,
|
||||
PresentFiltersForAppletCapture),
|
||||
rasterizer(render_window, gpu, device_memory, device, memory_allocator, state_tracker,
|
||||
scheduler) {
|
||||
scheduler),
|
||||
applet_frame() {
|
||||
if (Settings::values.renderer_force_max_clock.GetValue() && device.ShouldBoostClocks()) {
|
||||
turbo_mode.emplace(instance, dld);
|
||||
scheduler.RegisterOnSubmit([this] { turbo_mode->QueueSubmitted(); });
|
||||
@ -125,6 +146,8 @@ void RendererVulkan::Composite(std::span<const Tegra::FramebufferConfig> framebu
|
||||
|
||||
SCOPE_EXIT({ render_window.OnFrameDisplayed(); });
|
||||
|
||||
RenderAppletCaptureLayer(framebuffers);
|
||||
|
||||
if (!render_window.IsShown()) {
|
||||
return;
|
||||
}
|
||||
@ -167,30 +190,20 @@ void RendererVulkan::Report() const {
|
||||
telemetry_session.AddField(field, "GPU_Vulkan_Extensions", extensions);
|
||||
}
|
||||
|
||||
void Vulkan::RendererVulkan::RenderScreenshot(
|
||||
std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (!renderer_settings.screenshot_requested) {
|
||||
return;
|
||||
}
|
||||
|
||||
constexpr VkFormat ScreenshotFormat{VK_FORMAT_B8G8R8A8_UNORM};
|
||||
const Layout::FramebufferLayout layout{renderer_settings.screenshot_framebuffer_layout};
|
||||
|
||||
vk::Buffer RendererVulkan::RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout, VkFormat format,
|
||||
VkDeviceSize buffer_size) {
|
||||
auto frame = [&]() {
|
||||
Frame f{};
|
||||
f.image = CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height},
|
||||
ScreenshotFormat);
|
||||
f.image_view = CreateWrappedImageView(device, f.image, ScreenshotFormat);
|
||||
f.framebuffer = blit_screenshot.CreateFramebuffer(layout, *f.image_view, ScreenshotFormat);
|
||||
f.image =
|
||||
CreateWrappedImage(memory_allocator, VkExtent2D{layout.width, layout.height}, format);
|
||||
f.image_view = CreateWrappedImageView(device, f.image, format);
|
||||
f.framebuffer = blit_capture.CreateFramebuffer(layout, *f.image_view, format);
|
||||
return f;
|
||||
}();
|
||||
|
||||
blit_screenshot.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1,
|
||||
VK_FORMAT_B8G8R8A8_UNORM);
|
||||
|
||||
const auto dst_buffer = CreateWrappedBuffer(
|
||||
memory_allocator, static_cast<VkDeviceSize>(layout.width * layout.height * 4),
|
||||
MemoryUsage::Download);
|
||||
auto dst_buffer = CreateWrappedBuffer(memory_allocator, buffer_size, MemoryUsage::Download);
|
||||
blit_capture.DrawToFrame(rasterizer, &frame, framebuffers, layout, 1, format);
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
|
||||
@ -198,15 +211,68 @@ void Vulkan::RendererVulkan::RenderScreenshot(
|
||||
VkExtent3D{layout.width, layout.height, 1});
|
||||
});
|
||||
|
||||
// Ensure the copy is fully completed before saving the screenshot
|
||||
// Ensure the copy is fully completed before saving the capture
|
||||
scheduler.Finish();
|
||||
|
||||
// Copy backing image data to the QImage screenshot buffer
|
||||
// Copy backing image data to the capture buffer
|
||||
dst_buffer.Invalidate();
|
||||
return dst_buffer;
|
||||
}
|
||||
|
||||
void RendererVulkan::RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (!renderer_settings.screenshot_requested) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& layout{renderer_settings.screenshot_framebuffer_layout};
|
||||
const auto dst_buffer = RenderToBuffer(framebuffers, layout, VK_FORMAT_B8G8R8A8_UNORM,
|
||||
layout.width * layout.height * 4);
|
||||
|
||||
std::memcpy(renderer_settings.screenshot_bits, dst_buffer.Mapped().data(),
|
||||
dst_buffer.Mapped().size());
|
||||
renderer_settings.screenshot_complete_callback(false);
|
||||
renderer_settings.screenshot_requested = false;
|
||||
}
|
||||
|
||||
std::vector<u8> RendererVulkan::GetAppletCaptureBuffer() {
|
||||
using namespace VideoCore::Capture;
|
||||
|
||||
std::vector<u8> out(VideoCore::Capture::TiledSize);
|
||||
|
||||
if (!applet_frame.image) {
|
||||
return out;
|
||||
}
|
||||
|
||||
const auto dst_buffer =
|
||||
CreateWrappedBuffer(memory_allocator, VideoCore::Capture::TiledSize, MemoryUsage::Download);
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([&](vk::CommandBuffer cmdbuf) {
|
||||
DownloadColorImage(cmdbuf, *applet_frame.image, *dst_buffer, CaptureImageExtent);
|
||||
});
|
||||
|
||||
// Ensure the copy is fully completed before writing the capture
|
||||
scheduler.Finish();
|
||||
|
||||
// Swizzle image data to the capture buffer
|
||||
dst_buffer.Invalidate();
|
||||
Tegra::Texture::SwizzleTexture(out, dst_buffer.Mapped(), BytesPerPixel, LinearWidth,
|
||||
LinearHeight, LinearDepth, BlockHeight, BlockDepth);
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
void RendererVulkan::RenderAppletCaptureLayer(
|
||||
std::span<const Tegra::FramebufferConfig> framebuffers) {
|
||||
if (!applet_frame.image) {
|
||||
applet_frame.image = CreateWrappedImage(memory_allocator, CaptureImageSize, CaptureFormat);
|
||||
applet_frame.image_view = CreateWrappedImageView(device, applet_frame.image, CaptureFormat);
|
||||
applet_frame.framebuffer = blit_applet.CreateFramebuffer(
|
||||
VideoCore::Capture::Layout, *applet_frame.image_view, CaptureFormat);
|
||||
}
|
||||
|
||||
blit_applet.DrawToFrame(rasterizer, &applet_frame, framebuffers, VideoCore::Capture::Layout, 1,
|
||||
CaptureFormat);
|
||||
}
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -48,6 +48,8 @@ public:
|
||||
|
||||
void Composite(std::span<const Tegra::FramebufferConfig> framebuffers) override;
|
||||
|
||||
std::vector<u8> GetAppletCaptureBuffer() override;
|
||||
|
||||
VideoCore::RasterizerInterface* ReadRasterizer() override {
|
||||
return &rasterizer;
|
||||
}
|
||||
@ -59,7 +61,11 @@ public:
|
||||
private:
|
||||
void Report() const;
|
||||
|
||||
vk::Buffer RenderToBuffer(std::span<const Tegra::FramebufferConfig> framebuffers,
|
||||
const Layout::FramebufferLayout& layout, VkFormat format,
|
||||
VkDeviceSize buffer_size);
|
||||
void RenderScreenshot(std::span<const Tegra::FramebufferConfig> framebuffers);
|
||||
void RenderAppletCaptureLayer(std::span<const Tegra::FramebufferConfig> framebuffers);
|
||||
|
||||
Core::TelemetrySession& telemetry_session;
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
@ -79,9 +85,12 @@ private:
|
||||
Swapchain swapchain;
|
||||
PresentManager present_manager;
|
||||
BlitScreen blit_swapchain;
|
||||
BlitScreen blit_screenshot;
|
||||
BlitScreen blit_capture;
|
||||
BlitScreen blit_applet;
|
||||
RasterizerVulkan rasterizer;
|
||||
std::optional<TurboMode> turbo_mode;
|
||||
|
||||
Frame applet_frame;
|
||||
};
|
||||
|
||||
} // namespace Vulkan
|
||||
|
@ -2,6 +2,7 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "video_core/framebuffer_config.h"
|
||||
#include "video_core/present.h"
|
||||
#include "video_core/renderer_vulkan/present/filters.h"
|
||||
#include "video_core/renderer_vulkan/present/layer.h"
|
||||
#include "video_core/renderer_vulkan/vk_blit_screen.h"
|
||||
@ -12,9 +13,9 @@ namespace Vulkan {
|
||||
|
||||
BlitScreen::BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory_, const Device& device_,
|
||||
MemoryAllocator& memory_allocator_, PresentManager& present_manager_,
|
||||
Scheduler& scheduler_)
|
||||
Scheduler& scheduler_, const PresentFilters& filters_)
|
||||
: device_memory{device_memory_}, device{device_}, memory_allocator{memory_allocator_},
|
||||
present_manager{present_manager_}, scheduler{scheduler_}, image_count{1},
|
||||
present_manager{present_manager_}, scheduler{scheduler_}, filters{filters_}, image_count{1},
|
||||
swapchain_view_format{VK_FORMAT_B8G8R8A8_UNORM} {}
|
||||
|
||||
BlitScreen::~BlitScreen() = default;
|
||||
@ -27,7 +28,7 @@ void BlitScreen::WaitIdle() {
|
||||
|
||||
void BlitScreen::SetWindowAdaptPass() {
|
||||
layers.clear();
|
||||
scaling_filter = Settings::values.scaling_filter.GetValue();
|
||||
scaling_filter = filters.get_scaling_filter();
|
||||
|
||||
switch (scaling_filter) {
|
||||
case Settings::ScalingFilter::NearestNeighbor:
|
||||
@ -59,7 +60,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
|
||||
bool presentation_recreate_required = false;
|
||||
|
||||
// Recreate dynamic resources if the adapting filter changed
|
||||
if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue()) {
|
||||
if (!window_adapt || scaling_filter != filters.get_scaling_filter()) {
|
||||
resource_update_required = true;
|
||||
}
|
||||
|
||||
@ -102,7 +103,7 @@ void BlitScreen::DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
|
||||
|
||||
while (layers.size() < framebuffers.size()) {
|
||||
layers.emplace_back(device, memory_allocator, scheduler, device_memory, image_count,
|
||||
window_size, window_adapt->GetDescriptorSetLayout());
|
||||
window_size, window_adapt->GetDescriptorSetLayout(), filters);
|
||||
}
|
||||
|
||||
// Perform the draw
|
||||
@ -119,8 +120,7 @@ vk::Framebuffer BlitScreen::CreateFramebuffer(const Layout::FramebufferLayout& l
|
||||
VkFormat current_view_format) {
|
||||
const bool format_updated =
|
||||
std::exchange(swapchain_view_format, current_view_format) != current_view_format;
|
||||
if (!window_adapt || scaling_filter != Settings::values.scaling_filter.GetValue() ||
|
||||
format_updated) {
|
||||
if (!window_adapt || scaling_filter != filters.get_scaling_filter() || format_updated) {
|
||||
WaitIdle();
|
||||
SetWindowAdaptPass();
|
||||
}
|
||||
|
@ -16,6 +16,8 @@ namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
struct PresentFilters;
|
||||
|
||||
namespace Tegra {
|
||||
struct FramebufferConfig;
|
||||
}
|
||||
@ -47,7 +49,7 @@ class BlitScreen {
|
||||
public:
|
||||
explicit BlitScreen(Tegra::MaxwellDeviceMemoryManager& device_memory, const Device& device,
|
||||
MemoryAllocator& memory_allocator, PresentManager& present_manager,
|
||||
Scheduler& scheduler);
|
||||
Scheduler& scheduler, const PresentFilters& filters);
|
||||
~BlitScreen();
|
||||
|
||||
void DrawToFrame(RasterizerVulkan& rasterizer, Frame* frame,
|
||||
@ -70,6 +72,7 @@ private:
|
||||
MemoryAllocator& memory_allocator;
|
||||
PresentManager& present_manager;
|
||||
Scheduler& scheduler;
|
||||
const PresentFilters& filters;
|
||||
std::size_t image_count{};
|
||||
std::size_t image_index{};
|
||||
VkFormat swapchain_view_format{};
|
||||
|
@ -746,7 +746,13 @@ std::pair<typename P::ImageView*, bool> TextureCache<P>::TryFindFramebufferImage
|
||||
}();
|
||||
|
||||
const auto GetImageViewForFramebuffer = [&](ImageId image_id) {
|
||||
const ImageViewInfo info{ImageViewType::e2D, view_format};
|
||||
ImageViewInfo info{ImageViewType::e2D, view_format};
|
||||
if (config.blending == Tegra::BlendMode::Opaque) {
|
||||
info.x_source = static_cast<u8>(SwizzleSource::R);
|
||||
info.y_source = static_cast<u8>(SwizzleSource::G);
|
||||
info.z_source = static_cast<u8>(SwizzleSource::B);
|
||||
info.w_source = static_cast<u8>(SwizzleSource::OneFloat);
|
||||
}
|
||||
return std::make_pair(&slot_image_views[FindOrEmplaceImageView(image_id, info)],
|
||||
slot_images[image_id].IsRescaled());
|
||||
};
|
||||
|
Reference in New Issue
Block a user