Merge pull request #12756 from liamwhite/applet-multiprocess-hwc

general: applet multiprocess
This commit is contained in:
Narr the Reg
2024-02-11 20:58:28 -06:00
committed by GitHub
79 changed files with 1173 additions and 255 deletions

View File

@ -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
View 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

View File

@ -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,

View File

@ -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();
}

View File

@ -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.

View File

@ -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
}

View File

@ -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);
}

View File

@ -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
}

View File

@ -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));
}

View File

@ -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);
}

View File

@ -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;
}

View File

@ -6,5 +6,6 @@
#define YUZU_USE_FP16
#define USE_EASU 1
#define VERSION 1
#include "fidelityfx_fsr.frag"

View File

@ -5,5 +5,6 @@
#extension GL_GOOGLE_include_directive : enable
#define USE_EASU 1
#define VERSION 1
#include "fidelityfx_fsr.frag"

View File

@ -6,5 +6,6 @@
#define YUZU_USE_FP16
#define USE_RCAS 1
#define VERSION 1
#include "fidelityfx_fsr.frag"

View File

@ -5,5 +5,6 @@
#extension GL_GOOGLE_include_directive : enable
#define USE_RCAS 1
#define VERSION 1
#include "fidelityfx_fsr.frag"

View File

@ -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"

View File

@ -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
View 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,
};

View File

@ -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;

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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;

View File

@ -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));

View File

@ -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;

View File

@ -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());

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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{};

View File

@ -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) {

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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{};

View File

@ -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());
};