video_core: Refactor GPU interface (#7272)

* video_core: Refactor GPU interface

* citra_qt: Better debug widget lifetime
This commit is contained in:
GPUCode
2023-12-28 12:46:57 +02:00
committed by GitHub
parent 602f4f60d8
commit 2bb7f89c30
167 changed files with 4172 additions and 4866 deletions

View File

@@ -4,10 +4,8 @@
#pragma once
#include "common/logging/log.h"
#include "core/core.h"
#include "core/telemetry_session.h"
#include "video_core/regs.h"
#include "common/assert.h"
#include "video_core/pica/regs_internal.h"
#include "video_core/renderer_vulkan/vk_common.h"
namespace PicaToVK {
@@ -56,14 +54,6 @@ inline vk::SamplerAddressMode WrapMode(Pica::TexturingRegs::TextureConfig::WrapM
const auto index = static_cast<std::size_t>(mode);
ASSERT_MSG(index < wrap_mode_table.size(), "Unknown texture wrap mode {}", index);
if (index > 3) {
Core::System::GetInstance().TelemetrySession().AddField(
Common::Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode",
static_cast<u32>(index));
LOG_WARNING(Render_Vulkan, "Using texture wrap mode {}", index);
}
return wrap_mode_table[index];
}

View File

@@ -9,9 +9,8 @@
#include "common/settings.h"
#include "core/core.h"
#include "core/frontend/emu_window.h"
#include "core/hw/gpu.h"
#include "core/hw/hw.h"
#include "core/hw/lcd.h"
#include "video_core/gpu.h"
#include "video_core/pica/pica_core.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_memory_util.h"
#include "video_core/renderer_vulkan/vk_shader_util.h"
@@ -51,15 +50,16 @@ constexpr static std::array<vk::DescriptorSetLayoutBinding, 1> PRESENT_BINDINGS
{0, vk::DescriptorType::eCombinedImageSampler, 3, vk::ShaderStageFlagBits::eFragment},
}};
RendererVulkan::RendererVulkan(Core::System& system, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window)
: RendererBase{system, window, secondary_window}, memory{system.Memory()},
RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
: RendererBase{system, window, secondary_window}, memory{system.Memory()}, pica{pica_},
instance{system.TelemetrySession(), window, Settings::values.physical_device.GetValue()},
scheduler{instance}, renderpass_cache{instance, scheduler}, pool{instance},
main_window{window, instance, scheduler},
vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer,
VERTEX_BUFFER_SIZE},
rasterizer{memory,
pica,
system.CustomTexManager(),
*this,
render_window,
@@ -103,37 +103,25 @@ void RendererVulkan::Sync() {
}
void RendererVulkan::PrepareRendertarget() {
const auto& framebuffer_config = pica.regs.framebuffer_config;
const auto& regs_lcd = pica.regs_lcd;
for (u32 i = 0; i < 3; i++) {
const u32 fb_id = i == 2 ? 1 : 0;
const auto& framebuffer = GPU::g_regs.framebuffer_config[fb_id];
// Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04
u32 lcd_color_addr =
(fb_id == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr;
LCD::Regs::ColorFill color_fill{0};
LCD::Read(color_fill.raw, lcd_color_addr);
const auto& framebuffer = framebuffer_config[fb_id];
auto& texture = screen_infos[i].texture;
const auto color_fill = fb_id == 0 ? regs_lcd.color_fill_top : regs_lcd.color_fill_bottom;
if (color_fill.is_enabled) {
LoadColorToActiveVkTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b,
screen_infos[i].texture);
} else {
TextureInfo& texture = screen_infos[i].texture;
if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
texture.format != framebuffer.color_format) {
// Reallocate texture if the framebuffer size has changed.
// This is expected to not happen very often and hence should not be a
// performance problem.
ConfigureFramebufferTexture(texture, framebuffer);
}
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1);
// Resize the texture in case the framebuffer size has changed
texture.width = framebuffer.width;
texture.height = framebuffer.height;
FillScreen(color_fill.AsVector(), texture);
continue;
}
if (texture.width != framebuffer.width || texture.height != framebuffer.height ||
texture.format != framebuffer.color_format) {
ConfigureFramebufferTexture(texture, framebuffer);
}
LoadFBToScreenInfo(framebuffer, screen_infos[i], i == 1);
}
}
@@ -203,7 +191,7 @@ void RendererVulkan::RenderToWindow(PresentWindow& window, const Layout::Framebu
window.Present(frame);
}
void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
void RendererVulkan::LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer,
ScreenInfo& screen_info, bool right_eye) {
if (framebuffer.address_right1 == 0 || framebuffer.address_right2 == 0) {
@@ -219,7 +207,7 @@ void RendererVulkan::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
framebuffer.stride * framebuffer.height, framebuffer_addr, framebuffer.width.Value(),
framebuffer.height.Value(), framebuffer.format);
const int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
const u32 bpp = Pica::BytesPerPixel(framebuffer.color_format);
const std::size_t pixel_stride = framebuffer.stride / bpp;
ASSERT(pixel_stride * bpp == framebuffer.stride);
@@ -405,7 +393,7 @@ void RendererVulkan::BuildPipelines() {
}
void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer) {
const Pica::FramebufferConfig& framebuffer) {
vk::Device device = instance.GetDevice();
if (texture.image_view) {
device.destroyImageView(texture.image_view);
@@ -466,14 +454,14 @@ void RendererVulkan::ConfigureFramebufferTexture(TextureInfo& texture,
texture.format = framebuffer.color_format;
}
void RendererVulkan::LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b,
const TextureInfo& texture) {
void RendererVulkan::FillScreen(Common::Vec3<u8> color, const TextureInfo& texture) {
return;
const vk::ClearColorValue clear_color = {
.float32 =
std::array{
color_r / 255.0f,
color_g / 255.0f,
color_b / 255.0f,
color.r() / 255.0f,
color.g() / 255.0f,
color.b() / 255.0f,
1.0f,
},
};

View File

@@ -4,12 +4,8 @@
#pragma once
#include <array>
#include <condition_variable>
#include <mutex>
#include "common/common_types.h"
#include "common/math_util.h"
#include "core/hw/gpu.h"
#include "video_core/renderer_base.h"
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_instance.h"
@@ -17,7 +13,6 @@
#include "video_core/renderer_vulkan/vk_rasterizer.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_swapchain.h"
namespace Core {
class System;
@@ -27,16 +22,24 @@ namespace Memory {
class MemorySystem;
}
namespace Pica {
class PicaCore;
}
namespace Layout {
struct FramebufferLayout;
}
namespace VideoCore {
class GPU;
}
namespace Vulkan {
struct TextureInfo {
u32 width;
u32 height;
GPU::Regs::PixelFormat format;
Pica::PixelFormat format;
vk::Image image;
vk::ImageView image_view;
VmaAllocation allocation;
@@ -64,7 +67,7 @@ class RendererVulkan : public VideoCore::RendererBase {
static constexpr std::size_t PRESENT_PIPELINES = 3;
public:
explicit RendererVulkan(Core::System& system, Frontend::EmuWindow& window,
explicit RendererVulkan(Core::System& system, Pica::PicaCore& pica, Frontend::EmuWindow& window,
Frontend::EmuWindow* secondary_window);
~RendererVulkan() override;
@@ -86,7 +89,7 @@ private:
void BuildLayouts();
void BuildPipelines();
void ConfigureFramebufferTexture(TextureInfo& texture,
const GPU::Regs::FramebufferConfig& framebuffer);
const Pica::FramebufferConfig& framebuffer);
void ConfigureRenderPipeline();
void PrepareRendertarget();
void RenderScreenshot();
@@ -105,12 +108,13 @@ private:
Layout::DisplayOrientation orientation);
void DrawSingleScreenStereo(u32 screen_id_l, u32 screen_id_r, float x, float y, float w,
float h, Layout::DisplayOrientation orientation);
void LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
ScreenInfo& screen_info, bool right_eye);
void LoadColorToActiveVkTexture(u8 color_r, u8 color_g, u8 color_b, const TextureInfo& texture);
void LoadFBToScreenInfo(const Pica::FramebufferConfig& framebuffer, ScreenInfo& screen_info,
bool right_eye);
void FillScreen(Common::Vec3<u8> color, const TextureInfo& texture);
private:
Memory::MemorySystem& memory;
Pica::PicaCore& pica;
Instance instance;
Scheduler scheduler;

View File

@@ -3,9 +3,9 @@
// Refer to the license.txt file included.
#include "common/thread_worker.h"
#include "video_core/pica/regs_pipeline.h"
#include "video_core/pica/regs_rasterizer.h"
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/regs_pipeline.h"
#include "video_core/regs_rasterizer.h"
#include "video_core/renderer_vulkan/vk_common.h"
namespace Common {

View File

@@ -6,8 +6,8 @@
#include <span>
#include "video_core/pica/regs_pipeline.h"
#include "video_core/rasterizer_cache/pixel_format.h"
#include "video_core/regs_pipeline.h"
#include "video_core/renderer_vulkan/vk_platform.h"
namespace Core {

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <limits>
#include <mutex>
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"

View File

@@ -377,8 +377,8 @@ bool PipelineCache::BindPipeline(const PipelineInfo& info, bool wait_built) {
return true;
}
bool PipelineCache::UseProgrammableVertexShader(const Pica::Regs& regs,
Pica::Shader::ShaderSetup& setup,
bool PipelineCache::UseProgrammableVertexShader(const Pica::RegsInternal& regs,
Pica::ShaderSetup& setup,
const VertexLayout& layout) {
// Enable the geometry-shader only if we are actually doing per-fragment lighting
// and care about proper quaternions. Otherwise just use standard vertex+fragment shaders.
@@ -443,7 +443,7 @@ void PipelineCache::UseTrivialVertexShader() {
shader_hashes[ProgramType::VS] = 0;
}
bool PipelineCache::UseFixedGeometryShader(const Pica::Regs& regs) {
bool PipelineCache::UseFixedGeometryShader(const Pica::RegsInternal& regs) {
if (!instance.UseGeometryShaders()) {
UseTrivialGeometryShader();
return true;
@@ -472,7 +472,7 @@ void PipelineCache::UseTrivialGeometryShader() {
shader_hashes[ProgramType::GS] = 0;
}
void PipelineCache::UseFragmentShader(const Pica::Regs& regs,
void PipelineCache::UseFragmentShader(const Pica::RegsInternal& regs,
const Pica::Shader::UserConfig& user) {
const FSConfig fs_config{regs, user, profile};
const auto [it, new_shader] = fragment_shaders.try_emplace(fs_config, instance);

View File

@@ -14,12 +14,9 @@
#include "video_core/shader/generator/shader_gen.h"
namespace Pica {
struct Regs;
}
namespace Pica::Shader {
struct RegsInternal;
struct ShaderSetup;
}
} // namespace Pica
namespace Vulkan {
@@ -54,20 +51,20 @@ public:
bool BindPipeline(const PipelineInfo& info, bool wait_built = false);
/// Binds a PICA decompiled vertex shader
bool UseProgrammableVertexShader(const Pica::Regs& regs, Pica::Shader::ShaderSetup& setup,
bool UseProgrammableVertexShader(const Pica::RegsInternal& regs, Pica::ShaderSetup& setup,
const VertexLayout& layout);
/// Binds a passthrough vertex shader
void UseTrivialVertexShader();
/// Binds a PICA decompiled geometry shader
bool UseFixedGeometryShader(const Pica::Regs& regs);
bool UseFixedGeometryShader(const Pica::RegsInternal& regs);
/// Binds a passthrough geometry shader
void UseTrivialGeometryShader();
/// Binds a fragment shader generated from PICA state
void UseFragmentShader(const Pica::Regs& regs, const Pica::Shader::UserConfig& user);
void UseFragmentShader(const Pica::RegsInternal& regs, const Pica::Shader::UserConfig& user);
/// Binds a texture to the specified binding
void BindTexture(u32 binding, vk::ImageView image_view, vk::Sampler sampler);

View File

@@ -8,10 +8,8 @@
#include "common/math_util.h"
#include "common/microprofile.h"
#include "common/settings.h"
#include "video_core/pica_state.h"
#include "video_core/regs_framebuffer.h"
#include "video_core/regs_pipeline.h"
#include "video_core/regs_rasterizer.h"
#include "core/memory.h"
#include "video_core/pica/pica_core.h"
#include "video_core/renderer_vulkan/renderer_vulkan.h"
#include "video_core/renderer_vulkan/vk_instance.h"
#include "video_core/renderer_vulkan/vk_rasterizer.h"
@@ -56,13 +54,13 @@ struct DrawParams {
} // Anonymous namespace
RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory,
RasterizerVulkan::RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& pica,
VideoCore::CustomTexManager& custom_tex_manager,
VideoCore::RendererBase& renderer,
Frontend::EmuWindow& emu_window, const Instance& instance,
Scheduler& scheduler, DescriptorPool& pool,
RenderpassCache& renderpass_cache, u32 image_count)
: RasterizerAccelerated{memory}, instance{instance}, scheduler{scheduler},
: RasterizerAccelerated{memory, pica}, instance{instance}, scheduler{scheduler},
renderpass_cache{renderpass_cache}, pipeline_cache{instance, scheduler, renderpass_cache,
pool},
runtime{instance, scheduler, renderpass_cache, pool, pipeline_cache.TextureProvider(),
@@ -278,7 +276,7 @@ void RasterizerVulkan::SetupFixedAttribs() {
if (vertex_attributes.IsDefaultAttribute(i)) {
const u32 reg = regs.vs.GetRegisterForAttribute(i);
if (!enable_attributes[reg]) {
const auto& attr = Pica::g_state.input_default_attributes.attr[i];
const auto& attr = pica.input_default_attributes[i];
const std::array data = {attr.x.ToFloat32(), attr.y.ToFloat32(), attr.z.ToFloat32(),
attr.w.ToFloat32()};
@@ -323,7 +321,7 @@ void RasterizerVulkan::SetupFixedAttribs() {
bool RasterizerVulkan::SetupVertexShader() {
MICROPROFILE_SCOPE(Vulkan_VS);
return pipeline_cache.UseProgrammableVertexShader(regs, Pica::g_state.vs,
return pipeline_cache.UseProgrammableVertexShader(regs, pica.vs_setup,
pipeline_info.vertex_layout);
}
@@ -741,19 +739,19 @@ void RasterizerVulkan::ClearAll(bool flush) {
res_cache.ClearAll(flush);
}
bool RasterizerVulkan::AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) {
bool RasterizerVulkan::AccelerateDisplayTransfer(const Pica::DisplayTransferConfig& config) {
return res_cache.AccelerateDisplayTransfer(config);
}
bool RasterizerVulkan::AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) {
bool RasterizerVulkan::AccelerateTextureCopy(const Pica::DisplayTransferConfig& config) {
return res_cache.AccelerateTextureCopy(config);
}
bool RasterizerVulkan::AccelerateFill(const GPU::Regs::MemoryFillConfig& config) {
bool RasterizerVulkan::AccelerateFill(const Pica::MemoryFillConfig& config) {
return res_cache.AccelerateFill(config);
}
bool RasterizerVulkan::AccelerateDisplay(const GPU::Regs::FramebufferConfig& config,
bool RasterizerVulkan::AccelerateDisplay(const Pica::FramebufferConfig& config,
PAddr framebuffer_addr, u32 pixel_stride,
ScreenInfo& screen_info) {
if (framebuffer_addr == 0) [[unlikely]] {
@@ -935,7 +933,7 @@ void RasterizerVulkan::SyncAndUploadLUTsLF() {
for (unsigned index = 0; index < fs_uniform_block_data.lighting_lut_dirty.size(); index++) {
if (fs_uniform_block_data.lighting_lut_dirty[index] || invalidate) {
std::array<Common::Vec2f, 256> new_data;
const auto& source_lut = Pica::g_state.lighting.luts[index];
const auto& source_lut = pica.lighting.luts[index];
std::transform(source_lut.begin(), source_lut.end(), new_data.begin(),
[](const auto& entry) {
return Common::Vec2f{entry.ToFloat(), entry.DiffToFloat()};
@@ -960,7 +958,7 @@ void RasterizerVulkan::SyncAndUploadLUTsLF() {
if (fs_uniform_block_data.fog_lut_dirty || invalidate) {
std::array<Common::Vec2f, 128> new_data;
std::transform(Pica::g_state.fog.lut.begin(), Pica::g_state.fog.lut.end(), new_data.begin(),
std::transform(pica.fog.lut.begin(), pica.fog.lut.end(), new_data.begin(),
[](const auto& entry) {
return Common::Vec2f{entry.ToFloat(), entry.DiffToFloat()};
});
@@ -981,7 +979,7 @@ void RasterizerVulkan::SyncAndUploadLUTsLF() {
}
void RasterizerVulkan::SyncAndUploadLUTs() {
const auto& proctex = Pica::g_state.proctex;
const auto& proctex = pica.proctex;
constexpr std::size_t max_size =
sizeof(Common::Vec2f) * 128 * 3 + // proctex: noise + color + alpha
sizeof(Common::Vec4f) * 256 + // proctex
@@ -1000,7 +998,7 @@ void RasterizerVulkan::SyncAndUploadLUTs() {
// helper function for SyncProcTexNoiseLUT/ColorMap/AlphaMap
auto sync_proctex_value_lut =
[this, buffer = buffer, offset = offset, invalidate = invalidate,
&bytes_used](const std::array<Pica::State::ProcTex::ValueEntry, 128>& lut,
&bytes_used](const std::array<Pica::PicaCore::ProcTex::ValueEntry, 128>& lut,
std::array<Common::Vec2f, 128>& lut_data, int& lut_offset) {
std::array<Common::Vec2f, 128> new_data;
std::transform(lut.begin(), lut.end(), new_data.begin(), [](const auto& entry) {
@@ -1120,7 +1118,7 @@ void RasterizerVulkan::UploadUniforms(bool accelerate_draw) {
if (sync_vs_pica) {
VSPicaUniformData vs_uniforms;
vs_uniforms.uniforms.SetFromRegs(regs.vs, Pica::g_state.vs);
vs_uniforms.uniforms.SetFromRegs(regs.vs, pica.vs_setup);
std::memcpy(uniforms + used_bytes, &vs_uniforms, sizeof(vs_uniforms));
pipeline_cache.SetBufferOffset(0, offset + used_bytes);

View File

@@ -4,7 +4,6 @@
#pragma once
#include "core/hw/gpu.h"
#include "video_core/rasterizer_accelerated.h"
#include "video_core/renderer_vulkan/vk_pipeline_cache.h"
#include "video_core/renderer_vulkan/vk_renderpass_cache.h"
@@ -20,6 +19,12 @@ class CustomTexManager;
class RendererBase;
} // namespace VideoCore
namespace Pica {
struct DisplayTransferConfig;
struct MemoryFillConfig;
struct FramebufferConfig;
} // namespace Pica
namespace Vulkan {
struct ScreenInfo;
@@ -31,7 +36,7 @@ class DescriptorPool;
class RasterizerVulkan : public VideoCore::RasterizerAccelerated {
public:
explicit RasterizerVulkan(Memory::MemorySystem& memory,
explicit RasterizerVulkan(Memory::MemorySystem& memory, Pica::PicaCore& pica,
VideoCore::CustomTexManager& custom_tex_manager,
VideoCore::RendererBase& renderer, Frontend::EmuWindow& emu_window,
const Instance& instance, Scheduler& scheduler, DescriptorPool& pool,
@@ -48,10 +53,10 @@ public:
void InvalidateRegion(PAddr addr, u32 size) override;
void FlushAndInvalidateRegion(PAddr addr, u32 size) override;
void ClearAll(bool flush) override;
bool AccelerateDisplayTransfer(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateTextureCopy(const GPU::Regs::DisplayTransferConfig& config) override;
bool AccelerateFill(const GPU::Regs::MemoryFillConfig& config) override;
bool AccelerateDisplay(const GPU::Regs::FramebufferConfig& config, PAddr framebuffer_addr,
bool AccelerateDisplayTransfer(const Pica::DisplayTransferConfig& config) override;
bool AccelerateTextureCopy(const Pica::DisplayTransferConfig& config) override;
bool AccelerateFill(const Pica::MemoryFillConfig& config) override;
bool AccelerateDisplay(const Pica::FramebufferConfig& config, PAddr framebuffer_addr,
u32 pixel_stride, ScreenInfo& screen_info);
bool AccelerateDrawBatch(bool is_indexed) override;