Split AbstractGfx out of Renderer
Almost all the virtual functions in Renderer are part of dolphin's "graphics api abstraction layer", which has slowly formed over the last decade or two. Most of the work was done previously with the introduction of the various "AbstractX" classes, associated with texture cache cleanups and implementation of newer graphics APIs (Direct3D 12, Vulkan, Metal). We are simply taking the last step and yeeting these functions out of Renderer. This "AbstractGfx" class is now completely agnostic of any details from the flipper/hollywood GPU we are emulating, though somewhat specialized. (Will not build, this commit only contains changes outside VideoBackends)
This commit is contained in:
parent
e57eb04ed3
commit
8a23629345
|
@ -618,6 +618,7 @@
|
|||
<ClInclude Include="VideoBackends\Vulkan\VulkanContext.h" />
|
||||
<ClInclude Include="VideoBackends\Vulkan\VulkanLoader.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractFramebuffer.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractGfx.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractPipeline.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractShader.h" />
|
||||
<ClInclude Include="VideoCommon\AbstractStagingTexture.h" />
|
||||
|
@ -1219,6 +1220,7 @@
|
|||
<ClCompile Include="VideoBackends\Vulkan\VulkanContext.cpp" />
|
||||
<ClCompile Include="VideoBackends\Vulkan\VulkanLoader.cpp" />
|
||||
<ClCompile Include="VideoCommon\AbstractFramebuffer.cpp" />
|
||||
<ClCompile Include="VideoCommon\AbstractGfx.cpp" />
|
||||
<ClCompile Include="VideoCommon\AbstractStagingTexture.cpp" />
|
||||
<ClCompile Include="VideoCommon\AbstractTexture.cpp" />
|
||||
<ClCompile Include="VideoCommon\AsyncRequests.cpp" />
|
||||
|
|
|
@ -36,9 +36,9 @@
|
|||
|
||||
#include "UICommon/DiscordPresence.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/Fifo.cpp"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static thread_local bool tls_is_host_thread = false;
|
||||
|
@ -150,11 +150,11 @@ bool Host::GetRenderFullFocus()
|
|||
void Host::SetRenderFocus(bool focus)
|
||||
{
|
||||
m_render_focus = focus;
|
||||
if (g_renderer && m_render_fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
|
||||
if (g_gfx && m_render_fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
|
||||
{
|
||||
RunWithGPUThreadInactive([focus] {
|
||||
if (!Config::Get(Config::MAIN_RENDER_TO_MAIN))
|
||||
g_renderer->SetFullscreen(focus);
|
||||
g_gfx->SetFullscreen(focus);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -182,10 +182,9 @@ void Host::SetRenderFullscreen(bool fullscreen)
|
|||
{
|
||||
m_render_fullscreen = fullscreen;
|
||||
|
||||
if (g_renderer && g_renderer->IsFullscreen() != fullscreen &&
|
||||
g_ActiveConfig.ExclusiveFullscreenEnabled())
|
||||
if (g_gfx && g_gfx->IsFullscreen() != fullscreen && g_ActiveConfig.ExclusiveFullscreenEnabled())
|
||||
{
|
||||
RunWithGPUThreadInactive([fullscreen] { g_renderer->SetFullscreen(fullscreen); });
|
||||
RunWithGPUThreadInactive([fullscreen] { g_gfx->SetFullscreen(fullscreen); });
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
|
||||
#include "Common/Assert.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/ShaderCache.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
bool AbstractGfx::IsHeadless() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void AbstractGfx::BeginUtilityDrawing()
|
||||
{
|
||||
if (g_renderer)
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
}
|
||||
|
||||
void AbstractGfx::EndUtilityDrawing()
|
||||
{
|
||||
if (g_renderer)
|
||||
g_renderer->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
void AbstractGfx::SetFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void AbstractGfx::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void AbstractGfx::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void AbstractGfx::ClearRegion(const MathUtil::Rectangle<int>& rc,
|
||||
const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
|
||||
bool alphaEnable, bool zEnable, u32 color, u32 z)
|
||||
{
|
||||
g_framebuffer_manager->ClearEFB(rc, colorEnable, alphaEnable, zEnable, color, z);
|
||||
}
|
||||
|
||||
void AbstractGfx::SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth,
|
||||
float max_depth)
|
||||
{
|
||||
SetViewport(static_cast<float>(rect.left), static_cast<float>(rect.top),
|
||||
static_cast<float>(rect.GetWidth()), static_cast<float>(rect.GetHeight()), min_depth,
|
||||
max_depth);
|
||||
SetScissorRect(rect);
|
||||
}
|
||||
|
||||
void AbstractGfx::ScaleTexture(AbstractFramebuffer* dst_framebuffer,
|
||||
const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect)
|
||||
{
|
||||
ASSERT(dst_framebuffer->GetColorFormat() == AbstractTextureFormat::RGBA8);
|
||||
|
||||
BeginUtilityDrawing();
|
||||
|
||||
// The shader needs to know the source rectangle.
|
||||
const auto converted_src_rect =
|
||||
ConvertFramebufferRectangle(src_rect, src_texture->GetWidth(), src_texture->GetHeight());
|
||||
const float rcp_src_width = 1.0f / src_texture->GetWidth();
|
||||
const float rcp_src_height = 1.0f / src_texture->GetHeight();
|
||||
const std::array<float, 4> uniforms = {{converted_src_rect.left * rcp_src_width,
|
||||
converted_src_rect.top * rcp_src_height,
|
||||
converted_src_rect.GetWidth() * rcp_src_width,
|
||||
converted_src_rect.GetHeight() * rcp_src_height}};
|
||||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
|
||||
// Discard if we're overwriting the whole thing.
|
||||
if (static_cast<u32>(dst_rect.GetWidth()) == dst_framebuffer->GetWidth() &&
|
||||
static_cast<u32>(dst_rect.GetHeight()) == dst_framebuffer->GetHeight())
|
||||
{
|
||||
SetAndDiscardFramebuffer(dst_framebuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFramebuffer(dst_framebuffer);
|
||||
}
|
||||
|
||||
SetViewportAndScissor(ConvertFramebufferRectangle(dst_rect, dst_framebuffer));
|
||||
SetPipeline(dst_framebuffer->GetLayers() > 1 ? g_shader_cache->GetRGBA8StereoCopyPipeline() :
|
||||
g_shader_cache->GetRGBA8CopyPipeline());
|
||||
SetTexture(0, src_texture);
|
||||
SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||
Draw(0, 3);
|
||||
EndUtilityDrawing();
|
||||
if (dst_framebuffer->GetColorAttachment())
|
||||
dst_framebuffer->GetColorAttachment()->FinishedRendering();
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int>
|
||||
AbstractGfx::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
const AbstractFramebuffer* framebuffer) const
|
||||
{
|
||||
return ConvertFramebufferRectangle(rect, framebuffer->GetWidth(), framebuffer->GetHeight());
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int>
|
||||
AbstractGfx::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect, u32 fb_width,
|
||||
u32 fb_height) const
|
||||
{
|
||||
MathUtil::Rectangle<int> ret = rect;
|
||||
if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin)
|
||||
{
|
||||
ret.top = fb_height - rect.bottom;
|
||||
ret.bottom = fb_height - rect.top;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> AbstractGfx::CreateAsyncShaderCompiler()
|
||||
{
|
||||
return std::make_unique<VideoCommon::AsyncShaderCompiler>();
|
||||
}
|
||||
|
||||
bool AbstractGfx::UseGeometryShaderForUI() const
|
||||
{
|
||||
// OpenGL doesn't render to a 2-layer backbuffer like D3D/Vulkan for quad-buffered stereo,
|
||||
// instead drawing twice and the eye selected by glDrawBuffer() (see Presenter::RenderXFBToScreen)
|
||||
return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer &&
|
||||
g_ActiveConfig.backend_info.api_type != APIType::OpenGL;
|
||||
}
|
|
@ -0,0 +1,174 @@
|
|||
// Copyright 2023 Dolphin Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "Common/MathUtil.h"
|
||||
|
||||
#include "VideoCommon/RenderState.h"
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
|
||||
class AbstractFramebuffer;
|
||||
class AbstractPipeline;
|
||||
class AbstractShader;
|
||||
class AbstractTexture;
|
||||
class AbstractStagingTexture;
|
||||
class NativeVertexFormat;
|
||||
struct ComputePipelineConfig;
|
||||
struct AbstractPipelineConfig;
|
||||
struct PortableVertexDeclaration;
|
||||
struct TextureConfig;
|
||||
enum class AbstractTextureFormat : u32;
|
||||
enum class ShaderStage;
|
||||
enum class StagingTextureType;
|
||||
|
||||
struct SurfaceInfo
|
||||
{
|
||||
u32 width = 0;
|
||||
u32 height = 0;
|
||||
float scale = 0.0f;
|
||||
AbstractTextureFormat format = {};
|
||||
};
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
class AsyncShaderCompiler;
|
||||
}
|
||||
|
||||
// Bitmask containing information about which configuration has changed for the backend.
|
||||
enum ConfigChangeBits : u32
|
||||
{
|
||||
CONFIG_CHANGE_BIT_HOST_CONFIG = (1 << 0),
|
||||
CONFIG_CHANGE_BIT_MULTISAMPLES = (1 << 1),
|
||||
CONFIG_CHANGE_BIT_STEREO_MODE = (1 << 2),
|
||||
CONFIG_CHANGE_BIT_TARGET_SIZE = (1 << 3),
|
||||
CONFIG_CHANGE_BIT_ANISOTROPY = (1 << 4),
|
||||
CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING = (1 << 5),
|
||||
CONFIG_CHANGE_BIT_VSYNC = (1 << 6),
|
||||
CONFIG_CHANGE_BIT_BBOX = (1 << 7)
|
||||
};
|
||||
|
||||
using ClearColor = std::array<float, 4>;
|
||||
|
||||
class AbstractGfx
|
||||
{
|
||||
public:
|
||||
virtual bool IsHeadless() const = 0;
|
||||
|
||||
virtual void SetPipeline(const AbstractPipeline* pipeline) {}
|
||||
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
|
||||
virtual void SetTexture(u32 index, const AbstractTexture* texture) {}
|
||||
virtual void SetSamplerState(u32 index, const SamplerState& state) {}
|
||||
virtual void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) {}
|
||||
virtual void UnbindTexture(const AbstractTexture* texture) {}
|
||||
virtual void SetViewport(float x, float y, float width, float height, float near_depth,
|
||||
float far_depth)
|
||||
{
|
||||
}
|
||||
virtual void SetFullscreen(bool enable_fullscreen) {}
|
||||
virtual bool IsFullscreen() const { return false; }
|
||||
virtual void BeginUtilityDrawing();
|
||||
virtual void EndUtilityDrawing();
|
||||
virtual std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
|
||||
virtual std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0;
|
||||
|
||||
// Framebuffer operations.
|
||||
virtual void SetFramebuffer(AbstractFramebuffer* framebuffer);
|
||||
virtual void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer);
|
||||
virtual void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {}, float depth_value = 0.0f);
|
||||
|
||||
virtual void ClearRegion(const MathUtil::Rectangle<int>& rc,
|
||||
const MathUtil::Rectangle<int>& target_rc, bool colorEnable,
|
||||
bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||
|
||||
// Drawing with currently-bound pipeline state.
|
||||
virtual void Draw(u32 base_vertex, u32 num_vertices) {}
|
||||
virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {}
|
||||
|
||||
// Dispatching compute shaders with currently-bound state.
|
||||
virtual void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||
{
|
||||
}
|
||||
|
||||
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
|
||||
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
|
||||
// m_backbuffer_height may change after this function returns.
|
||||
virtual void BindBackbuffer(const ClearColor& clear_color = {}) {}
|
||||
|
||||
// Presents the backbuffer to the window system, or "swaps buffers".
|
||||
virtual void PresentBackbuffer() {}
|
||||
|
||||
// Shader modules/objects.
|
||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||
std::string_view source,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage,
|
||||
const void* data, size_t length,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0;
|
||||
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data = nullptr,
|
||||
size_t cache_data_length = 0) = 0;
|
||||
|
||||
AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
|
||||
|
||||
// Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer
|
||||
// coordinates, i.e. lower-left origin in OpenGL.
|
||||
void SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth = 0.0f,
|
||||
float max_depth = 1.0f);
|
||||
|
||||
// Scales a GPU texture using a copy shader.
|
||||
virtual void ScaleTexture(AbstractFramebuffer* dst_framebuffer,
|
||||
const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect);
|
||||
|
||||
// Converts an upper-left to lower-left if required by the backend, optionally
|
||||
// clamping to the framebuffer size.
|
||||
MathUtil::Rectangle<int> ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
u32 fb_width, u32 fb_height) const;
|
||||
MathUtil::Rectangle<int>
|
||||
ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
const AbstractFramebuffer* framebuffer) const;
|
||||
|
||||
virtual void Flush() {}
|
||||
virtual void WaitForGPUIdle() {}
|
||||
|
||||
// For opengl's glDrawBuffer
|
||||
virtual void SelectLeftBuffer() {}
|
||||
virtual void SelectRightBuffer() {}
|
||||
virtual void SelectMainBuffer() {}
|
||||
|
||||
// A simple presentation fallback, only used by video software
|
||||
virtual void ShowImage(const AbstractTexture* source_texture,
|
||||
const MathUtil::Rectangle<int>& source_rc)
|
||||
{
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
|
||||
|
||||
// Called when the configuration changes, and backend structures need to be updated.
|
||||
virtual void OnConfigChanged(u32 bits) {}
|
||||
|
||||
// Returns true if a layer-expanding geometry shader should be used when rendering the user
|
||||
// interface and final XFB.
|
||||
bool UseGeometryShaderForUI() const;
|
||||
|
||||
// Returns info about the main surface (aka backbuffer)
|
||||
virtual SurfaceInfo GetSurfaceInfo() const { return {}; }
|
||||
|
||||
protected:
|
||||
AbstractFramebuffer* m_current_framebuffer = nullptr;
|
||||
const AbstractPipeline* m_current_pipeline = nullptr;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<AbstractGfx> g_gfx;
|
|
@ -8,8 +8,8 @@
|
|||
#include "Common/Assert.h"
|
||||
#include "Common/Image.h"
|
||||
#include "Common/MsgHandler.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
AbstractTexture::AbstractTexture(const TextureConfig& c) : m_config(c)
|
||||
{
|
||||
|
@ -36,7 +36,7 @@ bool AbstractTexture::Save(const std::string& filename, unsigned int level)
|
|||
TextureConfig readback_texture_config(level_width, level_height, 1, 1, 1,
|
||||
AbstractTextureFormat::RGBA8, 0);
|
||||
auto readback_texture =
|
||||
g_renderer->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
||||
g_gfx->CreateStagingTexture(StagingTextureType::Readback, readback_texture_config);
|
||||
if (!readback_texture)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
@ -198,9 +199,8 @@ void SetScissorAndViewport()
|
|||
auto native_rc = ComputeScissorRects().Best();
|
||||
|
||||
auto target_rc = g_renderer->ConvertEFBRectangle(native_rc.rect);
|
||||
auto converted_rc =
|
||||
g_renderer->ConvertFramebufferRectangle(target_rc, g_renderer->GetCurrentFramebuffer());
|
||||
g_renderer->SetScissorRect(converted_rc);
|
||||
auto converted_rc = g_gfx->ConvertFramebufferRectangle(target_rc, g_gfx->GetCurrentFramebuffer());
|
||||
g_gfx->SetScissorRect(converted_rc);
|
||||
|
||||
float raw_x = (xfmem.viewport.xOrig - native_rc.x_off) - xfmem.viewport.wd;
|
||||
float raw_y = (xfmem.viewport.yOrig - native_rc.y_off) + xfmem.viewport.ht;
|
||||
|
@ -280,9 +280,9 @@ void SetScissorAndViewport()
|
|||
|
||||
// Lower-left flip.
|
||||
if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin)
|
||||
y = static_cast<float>(g_renderer->GetCurrentFramebuffer()->GetHeight()) - y - height;
|
||||
y = static_cast<float>(g_gfx->GetCurrentFramebuffer()->GetHeight()) - y - height;
|
||||
|
||||
g_renderer->SetViewport(x, y, width, height, near_depth, far_depth);
|
||||
g_gfx->SetViewport(x, y, width, height, near_depth, far_depth);
|
||||
}
|
||||
|
||||
void SetDepthMode()
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
@ -49,3 +50,5 @@ private:
|
|||
std::array<bool, NUM_BBOX_VALUES> m_dirty = {};
|
||||
bool m_is_valid = true;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<BoundingBox> g_bounding_box;
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
add_library(videocommon
|
||||
AbstractFramebuffer.cpp
|
||||
AbstractFramebuffer.h
|
||||
AbstractGfx.cpp
|
||||
AbstractGfx.h
|
||||
AbstractShader.h
|
||||
AbstractStagingTexture.cpp
|
||||
AbstractStagingTexture.h
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "Core/Config/MainSettings.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
|
@ -51,7 +52,7 @@ void FrameDumper::DumpCurrentFrame(const AbstractTexture* src_texture,
|
|||
if (!CheckFrameDumpRenderTexture(target_width, target_height))
|
||||
return;
|
||||
|
||||
g_renderer->ScaleTexture(m_frame_dump_render_framebuffer.get(),
|
||||
g_gfx->ScaleTexture(m_frame_dump_render_framebuffer.get(),
|
||||
m_frame_dump_render_framebuffer->GetRect(), src_texture, src_rect);
|
||||
src_texture = m_frame_dump_render_texture.get();
|
||||
copy_rect = src_texture->GetRect();
|
||||
|
@ -79,7 +80,7 @@ bool FrameDumper::CheckFrameDumpRenderTexture(u32 target_width, u32 target_heigh
|
|||
// Recreate texture, but release before creating so we don't temporarily use twice the RAM.
|
||||
m_frame_dump_render_framebuffer.reset();
|
||||
m_frame_dump_render_texture.reset();
|
||||
m_frame_dump_render_texture = g_renderer->CreateTexture(
|
||||
m_frame_dump_render_texture = g_gfx->CreateTexture(
|
||||
TextureConfig(target_width, target_height, 1, 1, 1, AbstractTextureFormat::RGBA8,
|
||||
AbstractTextureFlag_RenderTarget),
|
||||
"Frame dump render texture");
|
||||
|
@ -89,7 +90,7 @@ bool FrameDumper::CheckFrameDumpRenderTexture(u32 target_width, u32 target_heigh
|
|||
return false;
|
||||
}
|
||||
m_frame_dump_render_framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_frame_dump_render_texture.get(), nullptr);
|
||||
g_gfx->CreateFramebuffer(m_frame_dump_render_texture.get(), nullptr);
|
||||
ASSERT(m_frame_dump_render_framebuffer);
|
||||
return true;
|
||||
}
|
||||
|
@ -101,7 +102,7 @@ bool FrameDumper::CheckFrameDumpReadbackTexture(u32 target_width, u32 target_hei
|
|||
return true;
|
||||
|
||||
rbtex.reset();
|
||||
rbtex = g_renderer->CreateStagingTexture(
|
||||
rbtex = g_gfx->CreateStagingTexture(
|
||||
StagingTextureType::Readback,
|
||||
TextureConfig(target_width, target_height, 1, 1, 1, AbstractTextureFormat::RGBA8, 0));
|
||||
if (!rbtex)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Core/Config/GraphicsSettings.h"
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
|
@ -171,17 +172,17 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
|||
const TextureConfig efb_depth_texture_config = GetEFBDepthTextureConfig();
|
||||
|
||||
// We need a second texture to swap with for changing pixel formats
|
||||
m_efb_color_texture = g_renderer->CreateTexture(efb_color_texture_config, "EFB color texture");
|
||||
m_efb_depth_texture = g_renderer->CreateTexture(efb_depth_texture_config, "EFB depth texture");
|
||||
m_efb_color_texture = g_gfx->CreateTexture(efb_color_texture_config, "EFB color texture");
|
||||
m_efb_depth_texture = g_gfx->CreateTexture(efb_depth_texture_config, "EFB depth texture");
|
||||
m_efb_convert_color_texture =
|
||||
g_renderer->CreateTexture(efb_color_texture_config, "EFB convert color texture");
|
||||
g_gfx->CreateTexture(efb_color_texture_config, "EFB convert color texture");
|
||||
if (!m_efb_color_texture || !m_efb_depth_texture || !m_efb_convert_color_texture)
|
||||
return false;
|
||||
|
||||
m_efb_framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_color_texture.get(), m_efb_depth_texture.get());
|
||||
g_gfx->CreateFramebuffer(m_efb_color_texture.get(), m_efb_depth_texture.get());
|
||||
m_efb_convert_framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_convert_color_texture.get(), m_efb_depth_texture.get());
|
||||
g_gfx->CreateFramebuffer(m_efb_convert_color_texture.get(), m_efb_depth_texture.get());
|
||||
if (!m_efb_framebuffer || !m_efb_convert_framebuffer)
|
||||
return false;
|
||||
|
||||
|
@ -191,7 +192,7 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
|||
u32 flags = 0;
|
||||
if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve)
|
||||
flags |= AbstractTextureFlag_RenderTarget;
|
||||
m_efb_resolve_color_texture = g_renderer->CreateTexture(
|
||||
m_efb_resolve_color_texture = g_gfx->CreateTexture(
|
||||
TextureConfig(efb_color_texture_config.width, efb_color_texture_config.height, 1,
|
||||
efb_color_texture_config.layers, 1, efb_color_texture_config.format, flags),
|
||||
"EFB color resolve texture");
|
||||
|
@ -201,7 +202,7 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
|||
if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve)
|
||||
{
|
||||
m_efb_color_resolve_framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_resolve_color_texture.get(), nullptr);
|
||||
g_gfx->CreateFramebuffer(m_efb_resolve_color_texture.get(), nullptr);
|
||||
if (!m_efb_color_resolve_framebuffer)
|
||||
return false;
|
||||
}
|
||||
|
@ -210,7 +211,7 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
|||
// We also need one to convert the D24S8 to R32F if that is being used (Adreno).
|
||||
if (g_ActiveConfig.MultisamplingEnabled() || GetEFBDepthFormat() != AbstractTextureFormat::R32F)
|
||||
{
|
||||
m_efb_depth_resolve_texture = g_renderer->CreateTexture(
|
||||
m_efb_depth_resolve_texture = g_gfx->CreateTexture(
|
||||
TextureConfig(efb_depth_texture_config.width, efb_depth_texture_config.height, 1,
|
||||
efb_depth_texture_config.layers, 1, GetEFBDepthCopyFormat(),
|
||||
AbstractTextureFlag_RenderTarget),
|
||||
|
@ -219,15 +220,15 @@ bool FramebufferManager::CreateEFBFramebuffer()
|
|||
return false;
|
||||
|
||||
m_efb_depth_resolve_framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_depth_resolve_texture.get(), nullptr);
|
||||
g_gfx->CreateFramebuffer(m_efb_depth_resolve_texture.get(), nullptr);
|
||||
if (!m_efb_depth_resolve_framebuffer)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clear the renderable textures out.
|
||||
g_renderer->SetAndClearFramebuffer(
|
||||
m_efb_framebuffer.get(), {{0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? 1.0f : 0.0f);
|
||||
g_gfx->SetAndClearFramebuffer(m_efb_framebuffer.get(), {{0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? 1.0f :
|
||||
0.0f);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -245,7 +246,7 @@ void FramebufferManager::DestroyEFBFramebuffer()
|
|||
|
||||
void FramebufferManager::BindEFBFramebuffer()
|
||||
{
|
||||
g_renderer->SetFramebuffer(m_efb_framebuffer.get());
|
||||
g_gfx->SetFramebuffer(m_efb_framebuffer.get());
|
||||
}
|
||||
|
||||
AbstractTexture* FramebufferManager::ResolveEFBColorTexture(const MathUtil::Rectangle<int>& region)
|
||||
|
@ -270,15 +271,15 @@ AbstractTexture* FramebufferManager::ResolveEFBColorTexture(const MathUtil::Rect
|
|||
else
|
||||
{
|
||||
m_efb_color_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->SetAndDiscardFramebuffer(m_efb_color_resolve_framebuffer.get());
|
||||
g_renderer->SetPipeline(m_efb_color_resolve_pipeline.get());
|
||||
g_renderer->SetTexture(0, m_efb_color_texture.get());
|
||||
g_renderer->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_renderer->SetViewportAndScissor(clamped_region);
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->SetAndDiscardFramebuffer(m_efb_color_resolve_framebuffer.get());
|
||||
g_gfx->SetPipeline(m_efb_color_resolve_pipeline.get());
|
||||
g_gfx->SetTexture(0, m_efb_color_texture.get());
|
||||
g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_gfx->SetViewportAndScissor(clamped_region);
|
||||
g_gfx->Draw(0, 3);
|
||||
m_efb_resolve_color_texture->FinishedRendering();
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
m_efb_resolve_color_texture->FinishedRendering();
|
||||
return m_efb_resolve_color_texture.get();
|
||||
|
@ -298,16 +299,16 @@ AbstractTexture* FramebufferManager::ResolveEFBDepthTexture(const MathUtil::Rect
|
|||
clamped_region.ClampUL(0, 0, GetEFBWidth(), GetEFBHeight());
|
||||
|
||||
m_efb_depth_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->SetAndDiscardFramebuffer(m_efb_depth_resolve_framebuffer.get());
|
||||
g_renderer->SetPipeline(IsEFBMultisampled() ? m_efb_depth_resolve_pipeline.get() :
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->SetAndDiscardFramebuffer(m_efb_depth_resolve_framebuffer.get());
|
||||
g_gfx->SetPipeline(IsEFBMultisampled() ? m_efb_depth_resolve_pipeline.get() :
|
||||
m_efb_depth_cache.copy_pipeline.get());
|
||||
g_renderer->SetTexture(0, m_efb_depth_texture.get());
|
||||
g_renderer->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_renderer->SetViewportAndScissor(clamped_region);
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->SetTexture(0, m_efb_depth_texture.get());
|
||||
g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_gfx->SetViewportAndScissor(clamped_region);
|
||||
g_gfx->Draw(0, 3);
|
||||
m_efb_depth_resolve_texture->FinishedRendering();
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
|
||||
return m_efb_depth_resolve_texture.get();
|
||||
}
|
||||
|
@ -322,17 +323,17 @@ bool FramebufferManager::ReinterpretPixelData(EFBReinterpretType convtype)
|
|||
// buffer, which we want to preserve. If we find this to be hindering performance in the
|
||||
// future (e.g. on mobile/tilers), it may be worth discarding only the color buffer.
|
||||
m_efb_color_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->SetFramebuffer(m_efb_convert_framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_renderer->SetPipeline(m_format_conversion_pipelines[static_cast<u32>(convtype)].get());
|
||||
g_renderer->SetTexture(0, m_efb_color_texture.get());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->SetFramebuffer(m_efb_convert_framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_gfx->SetPipeline(m_format_conversion_pipelines[static_cast<u32>(convtype)].get());
|
||||
g_gfx->SetTexture(0, m_efb_color_texture.get());
|
||||
g_gfx->Draw(0, 3);
|
||||
|
||||
// And swap the framebuffers around, so we do new drawing to the converted framebuffer.
|
||||
std::swap(m_efb_color_texture, m_efb_convert_color_texture);
|
||||
std::swap(m_efb_framebuffer, m_efb_convert_framebuffer);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
InvalidatePeekCache(true);
|
||||
return true;
|
||||
}
|
||||
|
@ -342,7 +343,7 @@ bool FramebufferManager::CompileConversionPipelines()
|
|||
for (u32 i = 0; i < NUM_EFB_REINTERPRET_TYPES; i++)
|
||||
{
|
||||
EFBReinterpretType convtype = static_cast<EFBReinterpretType>(i);
|
||||
std::unique_ptr<AbstractShader> pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel,
|
||||
FramebufferShaderGen::GenerateFormatConversionShader(convtype, GetEFBSamples()),
|
||||
fmt::format("Framebuffer conversion pixel shader {}", convtype));
|
||||
|
@ -358,7 +359,7 @@ bool FramebufferManager::CompileConversionPipelines()
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = GetEFBFramebufferState();
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_format_conversion_pipelines[i] = g_renderer->CreatePipeline(config);
|
||||
m_format_conversion_pipelines[i] = g_gfx->CreatePipeline(config);
|
||||
if (!m_format_conversion_pipelines[i])
|
||||
return false;
|
||||
}
|
||||
|
@ -493,7 +494,7 @@ void FramebufferManager::RefreshPeekCache()
|
|||
|
||||
if (flush_command_buffer)
|
||||
{
|
||||
g_renderer->Flush();
|
||||
g_gfx->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -562,33 +563,33 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetColorFramebufferState(GetEFBColorFormat());
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_efb_color_cache.copy_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_efb_color_cache.copy_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_color_cache.copy_pipeline)
|
||||
return false;
|
||||
|
||||
// same for depth, except different format
|
||||
config.framebuffer_state.color_texture_format = GetEFBDepthCopyFormat();
|
||||
m_efb_depth_cache.copy_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_efb_depth_cache.copy_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_depth_cache.copy_pipeline)
|
||||
return false;
|
||||
|
||||
if (IsEFBMultisampled())
|
||||
{
|
||||
auto depth_resolve_shader = g_renderer->CreateShaderFromSource(
|
||||
auto depth_resolve_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateResolveDepthPixelShader(GetEFBSamples()),
|
||||
"Depth resolve pixel shader");
|
||||
if (!depth_resolve_shader)
|
||||
return false;
|
||||
|
||||
config.pixel_shader = depth_resolve_shader.get();
|
||||
m_efb_depth_resolve_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_efb_depth_resolve_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_depth_resolve_pipeline)
|
||||
return false;
|
||||
|
||||
if (!g_ActiveConfig.backend_info.bSupportsPartialMultisampleResolve)
|
||||
{
|
||||
config.framebuffer_state.color_texture_format = GetEFBColorFormat();
|
||||
auto color_resolve_shader = g_renderer->CreateShaderFromSource(
|
||||
auto color_resolve_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel,
|
||||
FramebufferShaderGen::GenerateResolveColorPixelShader(GetEFBSamples()),
|
||||
"Color resolve pixel shader");
|
||||
|
@ -596,14 +597,14 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||
return false;
|
||||
|
||||
config.pixel_shader = color_resolve_shader.get();
|
||||
m_efb_color_resolve_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_efb_color_resolve_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_color_resolve_pipeline)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// EFB restore pipeline
|
||||
auto restore_shader = g_renderer->CreateShaderFromSource(
|
||||
auto restore_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateEFBRestorePixelShader(),
|
||||
"EFB restore pixel shader");
|
||||
if (!restore_shader)
|
||||
|
@ -614,7 +615,7 @@ bool FramebufferManager::CompileReadbackPipelines()
|
|||
config.framebuffer_state.per_sample_shading = false;
|
||||
config.vertex_shader = g_shader_cache->GetScreenQuadVertexShader();
|
||||
config.pixel_shader = restore_shader.get();
|
||||
m_efb_restore_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_efb_restore_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_restore_pipeline)
|
||||
return false;
|
||||
|
||||
|
@ -635,12 +636,12 @@ bool FramebufferManager::CreateReadbackFramebuffer()
|
|||
const TextureConfig color_config(IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_WIDTH,
|
||||
IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1,
|
||||
1, 1, GetEFBColorFormat(), AbstractTextureFlag_RenderTarget);
|
||||
m_efb_color_cache.texture = g_renderer->CreateTexture(color_config, "EFB color cache");
|
||||
m_efb_color_cache.texture = g_gfx->CreateTexture(color_config, "EFB color cache");
|
||||
if (!m_efb_color_cache.texture)
|
||||
return false;
|
||||
|
||||
m_efb_color_cache.framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_color_cache.texture.get(), nullptr);
|
||||
g_gfx->CreateFramebuffer(m_efb_color_cache.texture.get(), nullptr);
|
||||
if (!m_efb_color_cache.framebuffer)
|
||||
return false;
|
||||
}
|
||||
|
@ -657,21 +658,21 @@ bool FramebufferManager::CreateReadbackFramebuffer()
|
|||
IsUsingTiledEFBCache() ? m_efb_cache_tile_size : EFB_HEIGHT, 1,
|
||||
1, 1, GetEFBDepthCopyFormat(),
|
||||
AbstractTextureFlag_RenderTarget);
|
||||
m_efb_depth_cache.texture = g_renderer->CreateTexture(depth_config, "EFB depth cache");
|
||||
m_efb_depth_cache.texture = g_gfx->CreateTexture(depth_config, "EFB depth cache");
|
||||
if (!m_efb_depth_cache.texture)
|
||||
return false;
|
||||
|
||||
m_efb_depth_cache.framebuffer =
|
||||
g_renderer->CreateFramebuffer(m_efb_depth_cache.texture.get(), nullptr);
|
||||
g_gfx->CreateFramebuffer(m_efb_depth_cache.texture.get(), nullptr);
|
||||
if (!m_efb_depth_cache.framebuffer)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Staging texture use the full EFB dimensions, as this is the buffer for the whole cache.
|
||||
m_efb_color_cache.readback_texture = g_renderer->CreateStagingTexture(
|
||||
m_efb_color_cache.readback_texture = g_gfx->CreateStagingTexture(
|
||||
StagingTextureType::Mutable,
|
||||
TextureConfig(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, GetEFBColorFormat(), 0));
|
||||
m_efb_depth_cache.readback_texture = g_renderer->CreateStagingTexture(
|
||||
m_efb_depth_cache.readback_texture = g_gfx->CreateStagingTexture(
|
||||
StagingTextureType::Mutable,
|
||||
TextureConfig(EFB_WIDTH, EFB_HEIGHT, 1, 1, 1, GetEFBDepthCopyFormat(), 0));
|
||||
if (!m_efb_color_cache.readback_texture || !m_efb_depth_cache.readback_texture)
|
||||
|
@ -737,7 +738,7 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index, bool async
|
|||
// TODO: This won't produce correct results at IRs above 2x. More samples are required.
|
||||
// This is the same issue as with EFB copies.
|
||||
src_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
|
||||
const float rcp_src_width = 1.0f / m_efb_framebuffer->GetWidth();
|
||||
const float rcp_src_height = 1.0f / m_efb_framebuffer->GetHeight();
|
||||
|
@ -748,14 +749,13 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index, bool async
|
|||
|
||||
// Viewport will not be TILE_SIZExTILE_SIZE for the last row of tiles, assuming a tile size of
|
||||
// 64, because 528 is not evenly divisible by 64.
|
||||
g_renderer->SetAndDiscardFramebuffer(data.framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(
|
||||
MathUtil::Rectangle<int>(0, 0, rect.GetWidth(), rect.GetHeight()));
|
||||
g_renderer->SetPipeline(data.copy_pipeline.get());
|
||||
g_renderer->SetTexture(0, src_texture);
|
||||
g_renderer->SetSamplerState(0, depth ? RenderState::GetPointSamplerState() :
|
||||
g_gfx->SetAndDiscardFramebuffer(data.framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(MathUtil::Rectangle<int>(0, 0, rect.GetWidth(), rect.GetHeight()));
|
||||
g_gfx->SetPipeline(data.copy_pipeline.get());
|
||||
g_gfx->SetTexture(0, src_texture);
|
||||
g_gfx->SetSamplerState(0, depth ? RenderState::GetPointSamplerState() :
|
||||
RenderState::GetLinearSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->Draw(0, 3);
|
||||
|
||||
// Copy from EFB or copy texture to staging texture.
|
||||
// No need to call FinishedRendering() here because CopyFromTexture() transitions.
|
||||
|
@ -763,7 +763,7 @@ void FramebufferManager::PopulateEFBCache(bool depth, u32 tile_index, bool async
|
|||
data.texture.get(), MathUtil::Rectangle<int>(0, 0, rect.GetWidth(), rect.GetHeight()), 0, 0,
|
||||
rect);
|
||||
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -790,7 +790,7 @@ void FramebufferManager::ClearEFB(const MathUtil::Rectangle<int>& rc, bool clear
|
|||
{
|
||||
FlushEFBPokes();
|
||||
FlagPeekCacheAsOutOfDate();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
|
||||
// Set up uniforms.
|
||||
struct Uniforms
|
||||
|
@ -809,17 +809,17 @@ void FramebufferManager::ClearEFB(const MathUtil::Rectangle<int>& rc, bool clear
|
|||
uniforms.clear_depth = 1.0f - uniforms.clear_depth;
|
||||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
|
||||
const auto target_rc = g_renderer->ConvertFramebufferRectangle(
|
||||
g_renderer->ConvertEFBRectangle(rc), m_efb_framebuffer.get());
|
||||
g_renderer->SetPipeline(m_efb_clear_pipelines[clear_color][clear_alpha][clear_z].get());
|
||||
g_renderer->SetViewportAndScissor(target_rc);
|
||||
g_renderer->Draw(0, 3);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
const auto target_rc = g_gfx->ConvertFramebufferRectangle(g_renderer->ConvertEFBRectangle(rc),
|
||||
m_efb_framebuffer.get());
|
||||
g_gfx->SetPipeline(m_efb_clear_pipelines[clear_color][clear_alpha][clear_z].get());
|
||||
g_gfx->SetViewportAndScissor(target_rc);
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
bool FramebufferManager::CompileClearPipelines()
|
||||
{
|
||||
auto vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
auto vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateClearVertexShader(),
|
||||
"Clear vertex shader");
|
||||
if (!vertex_shader)
|
||||
|
@ -848,7 +848,7 @@ bool FramebufferManager::CompileClearPipelines()
|
|||
config.depth_state.updateenable = depth_enable != 0;
|
||||
|
||||
m_efb_clear_pipelines[color_enable][alpha_enable][depth_enable] =
|
||||
g_renderer->CreatePipeline(config);
|
||||
g_gfx->CreatePipeline(config);
|
||||
if (!m_efb_clear_pipelines[color_enable][alpha_enable][depth_enable])
|
||||
return false;
|
||||
}
|
||||
|
@ -957,17 +957,17 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, u32 ver
|
|||
const AbstractPipeline* pipeline)
|
||||
{
|
||||
// Copy to vertex buffer.
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
u32 base_vertex, base_index;
|
||||
g_vertex_manager->UploadUtilityVertices(vertices, sizeof(EFBPokeVertex),
|
||||
static_cast<u32>(vertex_count), nullptr, 0, &base_vertex,
|
||||
&base_index);
|
||||
|
||||
// Now we can draw.
|
||||
g_renderer->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_renderer->SetPipeline(pipeline);
|
||||
g_renderer->Draw(base_vertex, vertex_count);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_gfx->SetPipeline(pipeline);
|
||||
g_gfx->Draw(base_vertex, vertex_count);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
bool FramebufferManager::CompilePokePipelines()
|
||||
|
@ -985,11 +985,11 @@ bool FramebufferManager::CompilePokePipelines()
|
|||
vtx_decl.colors[0].offset = offsetof(EFBPokeVertex, color);
|
||||
vtx_decl.stride = sizeof(EFBPokeVertex);
|
||||
|
||||
m_poke_vertex_format = g_renderer->CreateNativeVertexFormat(vtx_decl);
|
||||
m_poke_vertex_format = g_gfx->CreateNativeVertexFormat(vtx_decl);
|
||||
if (!m_poke_vertex_format)
|
||||
return false;
|
||||
|
||||
auto poke_vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
auto poke_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateEFBPokeVertexShader(),
|
||||
"EFB poke vertex shader");
|
||||
if (!poke_vertex_shader)
|
||||
|
@ -1007,14 +1007,14 @@ bool FramebufferManager::CompilePokePipelines()
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = GetEFBFramebufferState();
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_color_poke_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_color_poke_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_color_poke_pipeline)
|
||||
return false;
|
||||
|
||||
// Turn off color writes, depth writes on for depth pokes.
|
||||
config.depth_state = RenderState::GetAlwaysWriteDepthState();
|
||||
config.blending_state = RenderState::GetNoColorWriteBlendState();
|
||||
m_depth_poke_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_depth_poke_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_depth_poke_pipeline)
|
||||
return false;
|
||||
|
||||
|
@ -1077,9 +1077,9 @@ void FramebufferManager::DoLoadState(PointerWrap& p)
|
|||
color_tex->texture->GetLayers() != m_efb_color_texture->GetLayers())
|
||||
{
|
||||
WARN_LOG_FMT(VIDEO, "Failed to deserialize EFB contents. Clearing instead.");
|
||||
g_renderer->SetAndClearFramebuffer(
|
||||
m_efb_framebuffer.get(), {{0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? 1.0f : 0.0f);
|
||||
g_gfx->SetAndClearFramebuffer(m_efb_framebuffer.get(), {{0.0f, 0.0f, 0.0f, 0.0f}},
|
||||
g_ActiveConfig.backend_info.bSupportsReversedDepthRange ? 1.0f :
|
||||
0.0f);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1089,15 +1089,15 @@ void FramebufferManager::DoLoadState(PointerWrap& p)
|
|||
color_tex->texture->GetHeight() != m_efb_color_texture->GetHeight();
|
||||
|
||||
// Draw the deserialized textures over the EFB.
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->SetAndDiscardFramebuffer(m_efb_framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_renderer->SetPipeline(m_efb_restore_pipeline.get());
|
||||
g_renderer->SetTexture(0, color_tex->texture.get());
|
||||
g_renderer->SetTexture(1, depth_tex->texture.get());
|
||||
g_renderer->SetSamplerState(0, rescale ? RenderState::GetLinearSamplerState() :
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->SetAndDiscardFramebuffer(m_efb_framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(m_efb_framebuffer->GetRect());
|
||||
g_gfx->SetPipeline(m_efb_restore_pipeline.get());
|
||||
g_gfx->SetTexture(0, color_tex->texture.get());
|
||||
g_gfx->SetTexture(1, depth_tex->texture.get());
|
||||
g_gfx->SetSamplerState(0, rescale ? RenderState::GetLinearSamplerState() :
|
||||
RenderState::GetPointSamplerState());
|
||||
g_renderer->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/Movie.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/FramebufferShaderGen.h"
|
||||
|
@ -18,7 +19,6 @@
|
|||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/PerformanceMetrics.h"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
@ -61,7 +61,7 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale)
|
|||
vdecl.texcoords[0] = {ComponentFormat::Float, 2, offsetof(ImDrawVert, uv), true, false};
|
||||
vdecl.colors[0] = {ComponentFormat::UByte, 4, offsetof(ImDrawVert, col), true, false};
|
||||
vdecl.stride = sizeof(ImDrawVert);
|
||||
m_imgui_vertex_format = g_renderer->CreateNativeVertexFormat(vdecl);
|
||||
m_imgui_vertex_format = g_gfx->CreateNativeVertexFormat(vdecl);
|
||||
if (!m_imgui_vertex_format)
|
||||
{
|
||||
PanicAlertFmt("Failed to create ImGui vertex format");
|
||||
|
@ -78,7 +78,7 @@ bool OnScreenUI::Initialize(u32 width, u32 height, float scale)
|
|||
TextureConfig font_tex_config(font_tex_width, font_tex_height, 1, 1, 1,
|
||||
AbstractTextureFormat::RGBA8, 0);
|
||||
std::unique_ptr<AbstractTexture> font_tex =
|
||||
g_renderer->CreateTexture(font_tex_config, "ImGui font texture");
|
||||
g_gfx->CreateTexture(font_tex_config, "ImGui font texture");
|
||||
if (!font_tex)
|
||||
{
|
||||
PanicAlertFmt("Failed to create ImGui texture");
|
||||
|
@ -120,10 +120,10 @@ bool OnScreenUI::RecompileImGuiPipeline()
|
|||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
std::unique_ptr<AbstractShader> vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateImGuiVertexShader(),
|
||||
"ImGui vertex shader");
|
||||
std::unique_ptr<AbstractShader> pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
std::unique_ptr<AbstractShader> pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateImGuiPixelShader(), "ImGui pixel shader");
|
||||
if (!vertex_shader || !pixel_shader)
|
||||
{
|
||||
|
@ -133,9 +133,9 @@ bool OnScreenUI::RecompileImGuiPipeline()
|
|||
|
||||
// GS is used to render the UI to both eyes in stereo modes.
|
||||
std::unique_ptr<AbstractShader> geometry_shader;
|
||||
if (g_renderer->UseGeometryShaderForUI())
|
||||
if (g_gfx->UseGeometryShaderForUI())
|
||||
{
|
||||
geometry_shader = g_renderer->CreateShaderFromSource(
|
||||
geometry_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 1),
|
||||
"ImGui passthrough geometry shader");
|
||||
if (!geometry_shader)
|
||||
|
@ -163,7 +163,7 @@ bool OnScreenUI::RecompileImGuiPipeline()
|
|||
pconfig.framebuffer_state.samples = 1;
|
||||
pconfig.framebuffer_state.per_sample_shading = false;
|
||||
pconfig.usage = AbstractPipelineUsage::Utility;
|
||||
m_imgui_pipeline = g_renderer->CreatePipeline(pconfig);
|
||||
m_imgui_pipeline = g_gfx->CreatePipeline(pconfig);
|
||||
if (!m_imgui_pipeline)
|
||||
{
|
||||
PanicAlertFmt("Failed to create imgui pipeline");
|
||||
|
@ -204,7 +204,7 @@ void OnScreenUI::DrawImGui()
|
|||
if (!draw_data)
|
||||
return;
|
||||
|
||||
g_renderer->SetViewport(0.0f, 0.0f, static_cast<float>(m_backbuffer_width),
|
||||
g_gfx->SetViewport(0.0f, 0.0f, static_cast<float>(m_backbuffer_width),
|
||||
static_cast<float>(m_backbuffer_height), 0.0f, 1.0f);
|
||||
|
||||
// Uniform buffer for draws.
|
||||
|
@ -216,8 +216,8 @@ void OnScreenUI::DrawImGui()
|
|||
ImGuiUbo ubo = {{1.0f / m_backbuffer_width * 2.0f, 1.0f / m_backbuffer_height * 2.0f}};
|
||||
|
||||
// Set up common state for drawing.
|
||||
g_renderer->SetPipeline(m_imgui_pipeline.get());
|
||||
g_renderer->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_gfx->SetPipeline(m_imgui_pipeline.get());
|
||||
g_gfx->SetSamplerState(0, RenderState::GetPointSamplerState());
|
||||
g_vertex_manager->UploadUtilityUniforms(&ubo, sizeof(ubo));
|
||||
|
||||
for (int i = 0; i < draw_data->CmdListsCount; i++)
|
||||
|
@ -239,13 +239,13 @@ void OnScreenUI::DrawImGui()
|
|||
continue;
|
||||
}
|
||||
|
||||
g_renderer->SetScissorRect(g_renderer->ConvertFramebufferRectangle(
|
||||
g_gfx->SetScissorRect(g_gfx->ConvertFramebufferRectangle(
|
||||
MathUtil::Rectangle<int>(
|
||||
static_cast<int>(cmd.ClipRect.x), static_cast<int>(cmd.ClipRect.y),
|
||||
static_cast<int>(cmd.ClipRect.z), static_cast<int>(cmd.ClipRect.w)),
|
||||
g_renderer->GetCurrentFramebuffer()));
|
||||
g_renderer->SetTexture(0, reinterpret_cast<const AbstractTexture*>(cmd.TextureId));
|
||||
g_renderer->DrawIndexed(base_index, cmd.ElemCount, base_vertex);
|
||||
g_gfx->GetCurrentFramebuffer()));
|
||||
g_gfx->SetTexture(0, reinterpret_cast<const AbstractTexture*>(cmd.TextureId));
|
||||
g_gfx->DrawIndexed(base_index, cmd.ElemCount, base_vertex);
|
||||
base_index += cmd.ElemCount;
|
||||
}
|
||||
}
|
||||
|
@ -255,9 +255,9 @@ void OnScreenUI::DrawImGui()
|
|||
// itself will be clipped to whatever bounds were last set by ImGui, resulting in a rather useless
|
||||
// capture whenever any ImGui windows are open. We'll reset the scissor rectangle to the entire
|
||||
// viewport here to avoid this problem.
|
||||
g_renderer->SetScissorRect(g_renderer->ConvertFramebufferRectangle(
|
||||
g_gfx->SetScissorRect(g_gfx->ConvertFramebufferRectangle(
|
||||
MathUtil::Rectangle<int>(0, 0, m_backbuffer_width, m_backbuffer_height),
|
||||
g_renderer->GetCurrentFramebuffer()));
|
||||
g_gfx->GetCurrentFramebuffer()));
|
||||
}
|
||||
|
||||
// Create On-Screen-Messages
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractPipeline.h"
|
||||
#include "VideoCommon/AbstractShader.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/ShaderCache.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
#include "VideoCommon/VideoCommon.h"
|
||||
|
@ -417,9 +417,9 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
|||
const MathUtil::Rectangle<int>& src,
|
||||
const AbstractTexture* src_tex, int src_layer)
|
||||
{
|
||||
if (g_renderer->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format)
|
||||
if (g_gfx->GetCurrentFramebuffer()->GetColorFormat() != m_framebuffer_format)
|
||||
{
|
||||
m_framebuffer_format = g_renderer->GetCurrentFramebuffer()->GetColorFormat();
|
||||
m_framebuffer_format = g_gfx->GetCurrentFramebuffer()->GetColorFormat();
|
||||
RecompilePipeline();
|
||||
}
|
||||
|
||||
|
@ -430,12 +430,12 @@ void PostProcessing::BlitFromTexture(const MathUtil::Rectangle<int>& dst,
|
|||
g_vertex_manager->UploadUtilityUniforms(m_uniform_staging_buffer.data(),
|
||||
static_cast<u32>(m_uniform_staging_buffer.size()));
|
||||
|
||||
g_renderer->SetViewportAndScissor(
|
||||
g_renderer->ConvertFramebufferRectangle(dst, g_renderer->GetCurrentFramebuffer()));
|
||||
g_renderer->SetPipeline(m_pipeline.get());
|
||||
g_renderer->SetTexture(0, src_tex);
|
||||
g_renderer->SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->SetViewportAndScissor(
|
||||
g_gfx->ConvertFramebufferRectangle(dst, g_gfx->GetCurrentFramebuffer()));
|
||||
g_gfx->SetPipeline(m_pipeline.get());
|
||||
g_gfx->SetTexture(0, src_tex);
|
||||
g_gfx->SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||
g_gfx->Draw(0, 3);
|
||||
}
|
||||
|
||||
std::string PostProcessing::GetUniformBufferHeader() const
|
||||
|
@ -598,8 +598,8 @@ bool PostProcessing::CompileVertexShader()
|
|||
|
||||
ss << "}\n";
|
||||
|
||||
m_vertex_shader = g_renderer->CreateShaderFromSource(ShaderStage::Vertex, ss.str(),
|
||||
"Post-processing vertex shader");
|
||||
m_vertex_shader =
|
||||
g_gfx->CreateShaderFromSource(ShaderStage::Vertex, ss.str(), "Post-processing vertex shader");
|
||||
if (!m_vertex_shader)
|
||||
{
|
||||
PanicAlertFmt("Failed to compile post-processing vertex shader");
|
||||
|
@ -688,7 +688,7 @@ bool PostProcessing::CompilePixelShader()
|
|||
|
||||
// Generate GLSL and compile the new shader.
|
||||
m_config.LoadShader(g_ActiveConfig.sPostProcessingShader);
|
||||
m_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, GetHeader() + m_config.GetShaderCode() + GetFooter(),
|
||||
fmt::format("Post-processing pixel shader: {}", m_config.GetShader()));
|
||||
if (!m_pixel_shader)
|
||||
|
@ -697,7 +697,7 @@ bool PostProcessing::CompilePixelShader()
|
|||
|
||||
// Use default shader.
|
||||
m_config.LoadDefaultShader();
|
||||
m_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
m_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, GetHeader() + m_config.GetShaderCode() + GetFooter(),
|
||||
"Default post-processing pixel shader");
|
||||
if (!m_pixel_shader)
|
||||
|
@ -716,14 +716,14 @@ bool PostProcessing::CompilePipeline()
|
|||
AbstractPipelineConfig config = {};
|
||||
config.vertex_shader = m_vertex_shader.get();
|
||||
config.geometry_shader =
|
||||
g_renderer->UseGeometryShaderForUI() ? g_shader_cache->GetTexcoordGeometryShader() : nullptr;
|
||||
g_gfx->UseGeometryShaderForUI() ? g_shader_cache->GetTexcoordGeometryShader() : nullptr;
|
||||
config.pixel_shader = m_pixel_shader.get();
|
||||
config.rasterization_state = RenderState::GetNoCullRasterizationState(PrimitiveType::Triangles);
|
||||
config.depth_state = RenderState::GetNoDepthTestingDepthState();
|
||||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetColorFramebufferState(m_framebuffer_format);
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_pipeline)
|
||||
return false;
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
|
||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/FrameDumper.h"
|
||||
#include "VideoCommon/OnScreenUI.h"
|
||||
#include "VideoCommon/PostProcessing.h"
|
||||
|
@ -47,6 +48,9 @@ bool Presenter::Initialize()
|
|||
if (!m_onscreen_ui->Initialize(m_backbuffer_width, m_backbuffer_height, m_backbuffer_scale))
|
||||
return false;
|
||||
|
||||
if (!g_gfx->IsHeadless())
|
||||
SetBackbuffer(g_gfx->GetSurfaceInfo());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -57,13 +61,12 @@ void Presenter::SetBackbuffer(int backbuffer_width, int backbuffer_height)
|
|||
UpdateDrawRectangle();
|
||||
}
|
||||
|
||||
void Presenter::SetBackbuffer(int backbuffer_width, int backbuffer_height, float backbuffer_scale,
|
||||
AbstractTextureFormat backbuffer_format)
|
||||
void Presenter::SetBackbuffer(SurfaceInfo info)
|
||||
{
|
||||
m_backbuffer_width = backbuffer_width;
|
||||
m_backbuffer_height = backbuffer_height;
|
||||
m_backbuffer_scale = backbuffer_scale;
|
||||
m_backbuffer_format = backbuffer_format;
|
||||
m_backbuffer_width = info.width;
|
||||
m_backbuffer_height = info.height;
|
||||
m_backbuffer_scale = info.scale;
|
||||
m_backbuffer_format = info.format;
|
||||
UpdateDrawRectangle();
|
||||
}
|
||||
|
||||
|
@ -74,14 +77,14 @@ void Presenter::CheckForConfigChanges(u32 changed_bits)
|
|||
if (m_post_processor->GetConfig()->GetShader() != g_ActiveConfig.sPostProcessingShader)
|
||||
{
|
||||
// The existing shader must not be in use when it's destroyed
|
||||
g_renderer->WaitForGPUIdle();
|
||||
g_gfx->WaitForGPUIdle();
|
||||
|
||||
m_post_processor->RecompileShader();
|
||||
}
|
||||
|
||||
// Stereo mode change requires recompiling our post processing pipeline and imgui pipelines for
|
||||
// rendering the UI.
|
||||
if (changed_bits & Renderer::ConfigChangeBits::CONFIG_CHANGE_BIT_STEREO_MODE)
|
||||
if (changed_bits & ConfigChangeBits::CONFIG_CHANGE_BIT_STEREO_MODE)
|
||||
{
|
||||
m_onscreen_ui->RecompileImGuiPipeline();
|
||||
m_post_processor->RecompilePipeline();
|
||||
|
@ -90,24 +93,24 @@ void Presenter::CheckForConfigChanges(u32 changed_bits)
|
|||
|
||||
void Presenter::BeginUIFrame()
|
||||
{
|
||||
if (g_renderer->IsHeadless())
|
||||
if (g_gfx->IsHeadless())
|
||||
return;
|
||||
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->BindBackbuffer({0.0f, 0.0f, 0.0f, 1.0f});
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->BindBackbuffer({0.0f, 0.0f, 0.0f, 1.0f});
|
||||
}
|
||||
|
||||
void Presenter::EndUIFrame()
|
||||
{
|
||||
m_onscreen_ui->Finalize();
|
||||
|
||||
if (g_renderer->IsHeadless())
|
||||
if (g_gfx->IsHeadless())
|
||||
{
|
||||
m_onscreen_ui->DrawImGui();
|
||||
|
||||
std::lock_guard<std::mutex> guard(m_swap_mutex);
|
||||
g_renderer->PresentBackbuffer();
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->PresentBackbuffer();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
m_onscreen_ui->BeginImGuiFrame(m_backbuffer_width, m_backbuffer_height);
|
||||
|
@ -392,7 +395,7 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
|
|||
{
|
||||
if (!g_ActiveConfig.backend_info.bSupportsPostProcessing)
|
||||
{
|
||||
g_renderer->ShowImage(source_texture, source_rc);
|
||||
g_gfx->ShowImage(source_texture, source_rc);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -400,13 +403,13 @@ void Presenter::RenderXFBToScreen(const MathUtil::Rectangle<int>& target_rc,
|
|||
g_ActiveConfig.backend_info.bUsesExplictQuadBuffering)
|
||||
{
|
||||
// Quad-buffered stereo is annoying on GL.
|
||||
g_renderer->SelectLeftBuffer();
|
||||
g_gfx->SelectLeftBuffer();
|
||||
m_post_processor->BlitFromTexture(target_rc, source_rc, source_texture, 0);
|
||||
|
||||
g_renderer->SelectRightBuffer();
|
||||
g_gfx->SelectRightBuffer();
|
||||
m_post_processor->BlitFromTexture(target_rc, source_rc, source_texture, 1);
|
||||
|
||||
g_renderer->SelectMainBuffer();
|
||||
g_gfx->SelectMainBuffer();
|
||||
}
|
||||
else if (g_ActiveConfig.stereo_mode == StereoMode::SBS ||
|
||||
g_ActiveConfig.stereo_mode == StereoMode::TAB)
|
||||
|
@ -436,7 +439,7 @@ bool Presenter::SubmitXFB(RcTcacheEntry xfb_entry, MathUtil::Rectangle<int>& xfb
|
|||
if (g_frame_dumper->IsFrameDumping())
|
||||
{
|
||||
MathUtil::Rectangle<int> target_rect;
|
||||
if (!g_ActiveConfig.bInternalResolutionFrameDumps && !g_renderer->IsHeadless())
|
||||
if (!g_ActiveConfig.bInternalResolutionFrameDumps && !g_gfx->IsHeadless())
|
||||
{
|
||||
target_rect = GetTargetRectangle();
|
||||
}
|
||||
|
@ -469,10 +472,10 @@ void Presenter::Present()
|
|||
m_onscreen_ui->Finalize();
|
||||
|
||||
// Render the XFB to the screen.
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
if (!g_renderer->IsHeadless())
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
if (!g_gfx->IsHeadless())
|
||||
{
|
||||
g_renderer->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
|
||||
g_gfx->BindBackbuffer({{0.0f, 0.0f, 0.0f, 1.0f}});
|
||||
|
||||
UpdateDrawRectangle();
|
||||
|
||||
|
@ -488,7 +491,7 @@ void Presenter::Present()
|
|||
// Present to the window system.
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(m_swap_mutex);
|
||||
g_renderer->PresentBackbuffer();
|
||||
g_gfx->PresentBackbuffer();
|
||||
}
|
||||
|
||||
// Update the window size based on the frame that was just rendered.
|
||||
|
@ -498,7 +501,7 @@ void Presenter::Present()
|
|||
|
||||
m_onscreen_ui->BeginImGuiFrame(m_backbuffer_width, m_backbuffer_height);
|
||||
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
void Presenter::SetKeyMap(std::span<std::array<int, 2>> key_map)
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include <tuple>
|
||||
|
||||
class AbstractTexture;
|
||||
struct SurfaceInfo;
|
||||
|
||||
namespace VideoCommon
|
||||
{
|
||||
|
@ -51,8 +52,7 @@ public:
|
|||
AbstractTextureFormat GetBackbufferFormat() const { return m_backbuffer_format; }
|
||||
void SetWindowSize(int width, int height);
|
||||
void SetBackbuffer(int backbuffer_width, int backbuffer_height);
|
||||
void SetBackbuffer(int backbuffer_width, int backbuffer_height, float backbuffer_scale,
|
||||
AbstractTextureFormat backbuffer_format);
|
||||
void SetBackbuffer(SurfaceInfo info);
|
||||
|
||||
void UpdateDrawRectangle();
|
||||
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
#include "VideoCommon/CommandProcessor.h"
|
||||
|
@ -59,17 +60,12 @@
|
|||
|
||||
std::unique_ptr<Renderer> g_renderer;
|
||||
|
||||
Renderer::Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale,
|
||||
AbstractTextureFormat backbuffer_format)
|
||||
: m_last_xfb_width{MAX_XFB_WIDTH}, m_last_xfb_height{MAX_XFB_HEIGHT}
|
||||
Renderer::Renderer() : m_last_xfb_width{MAX_XFB_WIDTH}, m_last_xfb_height{MAX_XFB_HEIGHT}
|
||||
{
|
||||
UpdateActiveConfig();
|
||||
FreeLook::UpdateActiveConfig();
|
||||
CalculateTargetSize();
|
||||
|
||||
g_presenter->SetBackbuffer(backbuffer_width, backbuffer_height, backbuffer_scale,
|
||||
backbuffer_format);
|
||||
|
||||
m_is_game_widescreen = SConfig::GetInstance().bWii && Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||
g_freelook_camera.SetControlType(FreeLook::GetActiveConfig().camera_config.control_type);
|
||||
}
|
||||
|
@ -78,13 +74,6 @@ Renderer::~Renderer() = default;
|
|||
|
||||
bool Renderer::Initialize()
|
||||
{
|
||||
m_bounding_box = CreateBoundingBox();
|
||||
if (g_ActiveConfig.backend_info.bSupportsBBox && !m_bounding_box->Initialize())
|
||||
{
|
||||
PanicAlertFmt("Failed to initialize bounding box.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (g_ActiveConfig.bGraphicMods)
|
||||
{
|
||||
// If a config change occurred in a previous session,
|
||||
|
@ -101,12 +90,12 @@ bool Renderer::Initialize()
|
|||
m_graphics_mod_manager.Load(*g_ActiveConfig.graphics_mod_config);
|
||||
}
|
||||
|
||||
return g_presenter->Initialize();
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::Shutdown()
|
||||
{
|
||||
m_bounding_box.reset();
|
||||
g_bounding_box.reset();
|
||||
}
|
||||
|
||||
void Renderer::BeginUtilityDrawing()
|
||||
|
@ -121,31 +110,38 @@ void Renderer::EndUtilityDrawing()
|
|||
BPFunctions::SetScissorAndViewport();
|
||||
}
|
||||
|
||||
void Renderer::SetFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void Renderer::SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void Renderer::SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value, float depth_value)
|
||||
{
|
||||
m_current_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
bool Renderer::EFBHasAlphaChannel() const
|
||||
{
|
||||
return m_prev_efb_format == PixelFormat::RGBA6_Z24;
|
||||
}
|
||||
|
||||
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool colorEnable, bool alphaEnable,
|
||||
bool zEnable, u32 color, u32 z)
|
||||
void Renderer::ClearScreen(const MathUtil::Rectangle<int>& rc, bool color_enable, bool alpha_enable,
|
||||
bool z_enable, u32 color, u32 z)
|
||||
{
|
||||
g_framebuffer_manager->ClearEFB(rc, colorEnable, alphaEnable, zEnable, color, z);
|
||||
g_framebuffer_manager->FlushEFBPokes();
|
||||
g_framebuffer_manager->FlagPeekCacheAsOutOfDate();
|
||||
|
||||
// Native -> EFB coordinates
|
||||
MathUtil::Rectangle<int> target_rc = Renderer::ConvertEFBRectangle(rc);
|
||||
target_rc.ClampUL(0, 0, m_target_width, m_target_height);
|
||||
|
||||
// Determine whether the EFB has an alpha channel. If it doesn't, we can clear the alpha
|
||||
// channel to 0xFF.
|
||||
// On backends that don't allow masking Alpha clears, this allows us to use the fast path
|
||||
// almost all the time
|
||||
if (bpmem.zcontrol.pixel_format == PixelFormat::RGB565_Z16 ||
|
||||
bpmem.zcontrol.pixel_format == PixelFormat::RGB8_Z24 ||
|
||||
bpmem.zcontrol.pixel_format == PixelFormat::Z24)
|
||||
{
|
||||
// Force alpha writes, and clear the alpha channel.
|
||||
alpha_enable = true;
|
||||
color &= 0x00FFFFFF;
|
||||
}
|
||||
|
||||
g_gfx->ClearRegion(rc, target_rc, color_enable, alpha_enable, z_enable, color, z);
|
||||
|
||||
// Scissor rect must be restored.
|
||||
BPFunctions::SetScissorAndViewport();
|
||||
}
|
||||
|
||||
void Renderer::ReinterpretPixelData(EFBReinterpretType convtype)
|
||||
|
@ -155,17 +151,17 @@ void Renderer::ReinterpretPixelData(EFBReinterpretType convtype)
|
|||
|
||||
bool Renderer::IsBBoxEnabled() const
|
||||
{
|
||||
return m_bounding_box->IsEnabled();
|
||||
return g_bounding_box->IsEnabled();
|
||||
}
|
||||
|
||||
void Renderer::BBoxEnable(PixelShaderManager& pixel_shader_manager)
|
||||
{
|
||||
m_bounding_box->Enable(pixel_shader_manager);
|
||||
g_bounding_box->Enable(pixel_shader_manager);
|
||||
}
|
||||
|
||||
void Renderer::BBoxDisable(PixelShaderManager& pixel_shader_manager)
|
||||
{
|
||||
m_bounding_box->Disable(pixel_shader_manager);
|
||||
g_bounding_box->Disable(pixel_shader_manager);
|
||||
}
|
||||
|
||||
u16 Renderer::BBoxRead(u32 index)
|
||||
|
@ -173,7 +169,7 @@ u16 Renderer::BBoxRead(u32 index)
|
|||
if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return m_bounding_box_fallback[index];
|
||||
|
||||
return m_bounding_box->Get(index);
|
||||
return g_bounding_box->Get(index);
|
||||
}
|
||||
|
||||
void Renderer::BBoxWrite(u32 index, u16 value)
|
||||
|
@ -184,7 +180,7 @@ void Renderer::BBoxWrite(u32 index, u16 value)
|
|||
return;
|
||||
}
|
||||
|
||||
m_bounding_box->Set(index, value);
|
||||
g_bounding_box->Set(index, value);
|
||||
}
|
||||
|
||||
void Renderer::BBoxFlush()
|
||||
|
@ -192,7 +188,7 @@ void Renderer::BBoxFlush()
|
|||
if (!g_ActiveConfig.bBBoxEnable || !g_ActiveConfig.backend_info.bSupportsBBox)
|
||||
return;
|
||||
|
||||
m_bounding_box->Flush();
|
||||
g_bounding_box->Flush();
|
||||
}
|
||||
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data)
|
||||
|
@ -436,13 +432,13 @@ void Renderer::CheckForConfigChanges()
|
|||
return;
|
||||
|
||||
// Notify the backend of the changes, if any.
|
||||
OnConfigChanged(changed_bits);
|
||||
g_gfx->OnConfigChanged(changed_bits);
|
||||
|
||||
// If there's any shader changes, wait for the GPU to finish before destroying anything.
|
||||
if (changed_bits & (CONFIG_CHANGE_BIT_HOST_CONFIG | CONFIG_CHANGE_BIT_MULTISAMPLES))
|
||||
{
|
||||
WaitForGPUIdle();
|
||||
SetPipeline(nullptr);
|
||||
g_gfx->WaitForGPUIdle();
|
||||
g_gfx->SetPipeline(nullptr);
|
||||
}
|
||||
|
||||
// Framebuffer changed?
|
||||
|
@ -469,81 +465,6 @@ void Renderer::CheckForConfigChanges()
|
|||
}
|
||||
}
|
||||
|
||||
bool Renderer::IsHeadless() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth,
|
||||
float max_depth)
|
||||
{
|
||||
SetViewport(static_cast<float>(rect.left), static_cast<float>(rect.top),
|
||||
static_cast<float>(rect.GetWidth()), static_cast<float>(rect.GetHeight()), min_depth,
|
||||
max_depth);
|
||||
SetScissorRect(rect);
|
||||
}
|
||||
|
||||
void Renderer::ScaleTexture(AbstractFramebuffer* dst_framebuffer,
|
||||
const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect)
|
||||
{
|
||||
ASSERT(dst_framebuffer->GetColorFormat() == AbstractTextureFormat::RGBA8);
|
||||
|
||||
BeginUtilityDrawing();
|
||||
|
||||
// The shader needs to know the source rectangle.
|
||||
const auto converted_src_rect =
|
||||
ConvertFramebufferRectangle(src_rect, src_texture->GetWidth(), src_texture->GetHeight());
|
||||
const float rcp_src_width = 1.0f / src_texture->GetWidth();
|
||||
const float rcp_src_height = 1.0f / src_texture->GetHeight();
|
||||
const std::array<float, 4> uniforms = {{converted_src_rect.left * rcp_src_width,
|
||||
converted_src_rect.top * rcp_src_height,
|
||||
converted_src_rect.GetWidth() * rcp_src_width,
|
||||
converted_src_rect.GetHeight() * rcp_src_height}};
|
||||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
|
||||
// Discard if we're overwriting the whole thing.
|
||||
if (static_cast<u32>(dst_rect.GetWidth()) == dst_framebuffer->GetWidth() &&
|
||||
static_cast<u32>(dst_rect.GetHeight()) == dst_framebuffer->GetHeight())
|
||||
{
|
||||
SetAndDiscardFramebuffer(dst_framebuffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFramebuffer(dst_framebuffer);
|
||||
}
|
||||
|
||||
SetViewportAndScissor(ConvertFramebufferRectangle(dst_rect, dst_framebuffer));
|
||||
SetPipeline(dst_framebuffer->GetLayers() > 1 ? g_shader_cache->GetRGBA8StereoCopyPipeline() :
|
||||
g_shader_cache->GetRGBA8CopyPipeline());
|
||||
SetTexture(0, src_texture);
|
||||
SetSamplerState(0, RenderState::GetLinearSamplerState());
|
||||
Draw(0, 3);
|
||||
EndUtilityDrawing();
|
||||
if (dst_framebuffer->GetColorAttachment())
|
||||
dst_framebuffer->GetColorAttachment()->FinishedRendering();
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int>
|
||||
Renderer::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
const AbstractFramebuffer* framebuffer) const
|
||||
{
|
||||
return ConvertFramebufferRectangle(rect, framebuffer->GetWidth(), framebuffer->GetHeight());
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int> Renderer::ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
u32 fb_width, u32 fb_height) const
|
||||
{
|
||||
MathUtil::Rectangle<int> ret = rect;
|
||||
if (g_ActiveConfig.backend_info.bUsesLowerLeftOrigin)
|
||||
{
|
||||
ret.top = fb_height - rect.bottom;
|
||||
ret.bottom = fb_height - rect.top;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
MathUtil::Rectangle<int> Renderer::ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const
|
||||
{
|
||||
MathUtil::Rectangle<int> result;
|
||||
|
@ -590,14 +511,6 @@ void Renderer::RecordVideoMemory()
|
|||
texMem);
|
||||
}
|
||||
|
||||
bool Renderer::UseGeometryShaderForUI() const
|
||||
{
|
||||
// OpenGL doesn't render to a 2-layer backbuffer like D3D/Vulkan for quad-buffered stereo,
|
||||
// instead drawing twice and the eye selected by glDrawBuffer() (see Presenter::RenderXFBToScreen)
|
||||
return g_ActiveConfig.stereo_mode == StereoMode::QuadBuffer &&
|
||||
g_ActiveConfig.backend_info.api_type != APIType::OpenGL;
|
||||
}
|
||||
|
||||
void Renderer::ForceReloadTextures()
|
||||
{
|
||||
m_force_reload_textures.Set();
|
||||
|
@ -756,7 +669,7 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
|
|||
}
|
||||
else
|
||||
{
|
||||
Flush();
|
||||
g_gfx->Flush();
|
||||
}
|
||||
|
||||
// Update our last xfb values
|
||||
|
@ -768,7 +681,7 @@ void Renderer::Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u6
|
|||
}
|
||||
else
|
||||
{
|
||||
Flush();
|
||||
g_gfx->Flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -803,7 +716,7 @@ void Renderer::DoState(PointerWrap& p)
|
|||
p.Do(m_last_xfb_height);
|
||||
p.DoArray(m_bounding_box_fallback);
|
||||
|
||||
m_bounding_box->DoState(p);
|
||||
g_bounding_box->DoState(p);
|
||||
|
||||
if (p.IsReadMode())
|
||||
{
|
||||
|
@ -821,11 +734,6 @@ void Renderer::DoState(PointerWrap& p)
|
|||
#endif
|
||||
}
|
||||
|
||||
std::unique_ptr<VideoCommon::AsyncShaderCompiler> Renderer::CreateAsyncShaderCompiler()
|
||||
{
|
||||
return std::make_unique<VideoCommon::AsyncShaderCompiler>();
|
||||
}
|
||||
|
||||
const GraphicsModManager& Renderer::GetGraphicsModManager() const
|
||||
{
|
||||
return m_graphics_mod_manager;
|
||||
|
|
|
@ -64,100 +64,18 @@ struct EfbPokeData
|
|||
class Renderer
|
||||
{
|
||||
public:
|
||||
Renderer(int backbuffer_width, int backbuffer_height, float backbuffer_scale,
|
||||
AbstractTextureFormat backbuffer_format);
|
||||
Renderer();
|
||||
virtual ~Renderer();
|
||||
|
||||
using ClearColor = std::array<float, 4>;
|
||||
|
||||
virtual bool IsHeadless() const = 0;
|
||||
|
||||
virtual bool Initialize();
|
||||
virtual void Shutdown();
|
||||
|
||||
virtual void SetPipeline(const AbstractPipeline* pipeline) {}
|
||||
virtual void SetScissorRect(const MathUtil::Rectangle<int>& rc) {}
|
||||
virtual void SetTexture(u32 index, const AbstractTexture* texture) {}
|
||||
virtual void SetSamplerState(u32 index, const SamplerState& state) {}
|
||||
virtual void SetComputeImageTexture(AbstractTexture* texture, bool read, bool write) {}
|
||||
virtual void UnbindTexture(const AbstractTexture* texture) {}
|
||||
virtual void SetViewport(float x, float y, float width, float height, float near_depth,
|
||||
float far_depth)
|
||||
{
|
||||
}
|
||||
virtual void SetFullscreen(bool enable_fullscreen) {}
|
||||
virtual bool IsFullscreen() const { return false; }
|
||||
virtual void BeginUtilityDrawing();
|
||||
virtual void EndUtilityDrawing();
|
||||
virtual std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<AbstractStagingTexture>
|
||||
CreateStagingTexture(StagingTextureType type, const TextureConfig& config) = 0;
|
||||
virtual std::unique_ptr<AbstractFramebuffer>
|
||||
CreateFramebuffer(AbstractTexture* color_attachment, AbstractTexture* depth_attachment) = 0;
|
||||
|
||||
// Framebuffer operations.
|
||||
virtual void SetFramebuffer(AbstractFramebuffer* framebuffer);
|
||||
virtual void SetAndDiscardFramebuffer(AbstractFramebuffer* framebuffer);
|
||||
virtual void SetAndClearFramebuffer(AbstractFramebuffer* framebuffer,
|
||||
const ClearColor& color_value = {}, float depth_value = 0.0f);
|
||||
|
||||
// Drawing with currently-bound pipeline state.
|
||||
virtual void Draw(u32 base_vertex, u32 num_vertices) {}
|
||||
virtual void DrawIndexed(u32 base_index, u32 num_indices, u32 base_vertex) {}
|
||||
|
||||
// Dispatching compute shaders with currently-bound state.
|
||||
virtual void DispatchComputeShader(const AbstractShader* shader, u32 groupsize_x, u32 groupsize_y,
|
||||
u32 groupsize_z, u32 groups_x, u32 groups_y, u32 groups_z)
|
||||
{
|
||||
}
|
||||
|
||||
// Binds the backbuffer for rendering. The buffer will be cleared immediately after binding.
|
||||
// This is where any window size changes are detected, therefore m_backbuffer_width and/or
|
||||
// m_backbuffer_height may change after this function returns.
|
||||
virtual void BindBackbuffer(const ClearColor& clear_color = {}) {}
|
||||
|
||||
// Presents the backbuffer to the window system, or "swaps buffers".
|
||||
virtual void PresentBackbuffer() {}
|
||||
|
||||
// Shader modules/objects.
|
||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromSource(ShaderStage stage,
|
||||
std::string_view source,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<AbstractShader> CreateShaderFromBinary(ShaderStage stage,
|
||||
const void* data, size_t length,
|
||||
std::string_view name = "") = 0;
|
||||
virtual std::unique_ptr<NativeVertexFormat>
|
||||
CreateNativeVertexFormat(const PortableVertexDeclaration& vtx_decl) = 0;
|
||||
virtual std::unique_ptr<AbstractPipeline> CreatePipeline(const AbstractPipelineConfig& config,
|
||||
const void* cache_data = nullptr,
|
||||
size_t cache_data_length = 0) = 0;
|
||||
|
||||
AbstractFramebuffer* GetCurrentFramebuffer() const { return m_current_framebuffer; }
|
||||
|
||||
void BeginUtilityDrawing();
|
||||
void EndUtilityDrawing();
|
||||
// Ideal internal resolution - multiple of the native EFB resolution
|
||||
int GetTargetWidth() const { return m_target_width; }
|
||||
int GetTargetHeight() const { return m_target_height; }
|
||||
|
||||
// Sets viewport and scissor to the specified rectangle. rect is assumed to be in framebuffer
|
||||
// coordinates, i.e. lower-left origin in OpenGL.
|
||||
void SetViewportAndScissor(const MathUtil::Rectangle<int>& rect, float min_depth = 0.0f,
|
||||
float max_depth = 1.0f);
|
||||
|
||||
// Scales a GPU texture using a copy shader.
|
||||
virtual void ScaleTexture(AbstractFramebuffer* dst_framebuffer,
|
||||
const MathUtil::Rectangle<int>& dst_rect,
|
||||
const AbstractTexture* src_texture,
|
||||
const MathUtil::Rectangle<int>& src_rect);
|
||||
|
||||
// Converts an upper-left to lower-left if required by the backend, optionally
|
||||
// clamping to the framebuffer size.
|
||||
MathUtil::Rectangle<int> ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
u32 fb_width, u32 fb_height) const;
|
||||
MathUtil::Rectangle<int>
|
||||
ConvertFramebufferRectangle(const MathUtil::Rectangle<int>& rect,
|
||||
const AbstractFramebuffer* framebuffer) const;
|
||||
|
||||
// EFB coordinate conversion functions
|
||||
// Use this to convert a whole native EFB rect to backbuffer coordinates
|
||||
MathUtil::Rectangle<int> ConvertEFBRectangle(const MathUtil::Rectangle<int>& rc) const;
|
||||
|
@ -188,29 +106,12 @@ public:
|
|||
void BBoxWrite(u32 index, u16 value);
|
||||
void BBoxFlush();
|
||||
|
||||
virtual void Flush() {}
|
||||
virtual void WaitForGPUIdle() {}
|
||||
|
||||
// Finish up the current frame, print some stats
|
||||
void Swap(u32 xfb_addr, u32 fb_width, u32 fb_stride, u32 fb_height, u64 ticks);
|
||||
|
||||
void UpdateWidescreenHeuristic();
|
||||
bool IsGameWidescreen() const { return m_is_game_widescreen; }
|
||||
|
||||
// A simple presentation fallback, only used by video software
|
||||
virtual void ShowImage(const AbstractTexture* source_texture,
|
||||
const MathUtil::Rectangle<int>& source_rc)
|
||||
{
|
||||
}
|
||||
|
||||
// For opengl's glDrawBuffer
|
||||
virtual void SelectLeftBuffer() {}
|
||||
virtual void SelectRightBuffer() {}
|
||||
virtual void SelectMainBuffer() {}
|
||||
|
||||
// Called when the configuration changes, and backend structures need to be updated.
|
||||
virtual void OnConfigChanged(u32 bits) {}
|
||||
|
||||
PixelFormat GetPrevPixelFormat() const { return m_prev_efb_format; }
|
||||
void StorePixelFormat(PixelFormat new_format) { m_prev_efb_format = new_format; }
|
||||
bool EFBHasAlphaChannel() const;
|
||||
|
@ -218,30 +119,11 @@ public:
|
|||
bool UseVertexDepthRange() const;
|
||||
void DoState(PointerWrap& p);
|
||||
|
||||
virtual std::unique_ptr<VideoCommon::AsyncShaderCompiler> CreateAsyncShaderCompiler();
|
||||
|
||||
// Returns true if a layer-expanding geometry shader should be used when rendering the user
|
||||
// interface and final XFB.
|
||||
bool UseGeometryShaderForUI() const;
|
||||
|
||||
// Will forcibly reload all textures on the next swap
|
||||
void ForceReloadTextures();
|
||||
|
||||
const GraphicsModManager& GetGraphicsModManager() const;
|
||||
|
||||
// Bitmask containing information about which configuration has changed for the backend.
|
||||
enum ConfigChangeBits : u32
|
||||
{
|
||||
CONFIG_CHANGE_BIT_HOST_CONFIG = (1 << 0),
|
||||
CONFIG_CHANGE_BIT_MULTISAMPLES = (1 << 1),
|
||||
CONFIG_CHANGE_BIT_STEREO_MODE = (1 << 2),
|
||||
CONFIG_CHANGE_BIT_TARGET_SIZE = (1 << 3),
|
||||
CONFIG_CHANGE_BIT_ANISOTROPY = (1 << 4),
|
||||
CONFIG_CHANGE_BIT_FORCE_TEXTURE_FILTERING = (1 << 5),
|
||||
CONFIG_CHANGE_BIT_VSYNC = (1 << 6),
|
||||
CONFIG_CHANGE_BIT_BBOX = (1 << 7)
|
||||
};
|
||||
|
||||
protected:
|
||||
std::tuple<int, int> CalculateTargetScale(int x, int y) const;
|
||||
bool CalculateTargetSize();
|
||||
|
@ -251,11 +133,6 @@ protected:
|
|||
void CheckFifoRecording();
|
||||
void RecordVideoMemory();
|
||||
|
||||
virtual std::unique_ptr<BoundingBox> CreateBoundingBox() const = 0;
|
||||
|
||||
AbstractFramebuffer* m_current_framebuffer = nullptr;
|
||||
const AbstractPipeline* m_current_pipeline = nullptr;
|
||||
|
||||
bool m_is_game_widescreen = false;
|
||||
bool m_was_orthographically_anamorphic = false;
|
||||
|
||||
|
|
|
@ -10,12 +10,12 @@
|
|||
#include "Common/MsgHandler.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/ConstantManager.h"
|
||||
#include "VideoCommon/DriverDetails.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/FramebufferShaderGen.h"
|
||||
#include "VideoCommon/Present.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexLoaderManager.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
|
@ -45,7 +45,7 @@ bool ShaderCache::Initialize()
|
|||
if (!CompileSharedPipelines())
|
||||
return false;
|
||||
|
||||
m_async_shader_compiler = g_renderer->CreateAsyncShaderCompiler();
|
||||
m_async_shader_compiler = g_gfx->CreateAsyncShaderCompiler();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -122,7 +122,7 @@ const AbstractPipeline* ShaderCache::GetPipelineForUid(const GXPipelineUid& uid)
|
|||
std::unique_ptr<AbstractPipeline> pipeline;
|
||||
std::optional<AbstractPipelineConfig> pipeline_config = GetGXPipelineConfig(uid);
|
||||
if (pipeline_config)
|
||||
pipeline = g_renderer->CreatePipeline(*pipeline_config);
|
||||
pipeline = g_gfx->CreatePipeline(*pipeline_config);
|
||||
if (g_ActiveConfig.bShaderCache && !exists_in_cache)
|
||||
AppendGXPipelineUID(uid);
|
||||
return InsertGXPipeline(uid, std::move(pipeline));
|
||||
|
@ -154,7 +154,7 @@ const AbstractPipeline* ShaderCache::GetUberPipelineForUid(const GXUberPipelineU
|
|||
std::unique_ptr<AbstractPipeline> pipeline;
|
||||
std::optional<AbstractPipelineConfig> pipeline_config = GetGXPipelineConfig(uid);
|
||||
if (pipeline_config)
|
||||
pipeline = g_renderer->CreatePipeline(*pipeline_config);
|
||||
pipeline = g_gfx->CreatePipeline(*pipeline_config);
|
||||
return InsertGXUberPipeline(uid, std::move(pipeline));
|
||||
}
|
||||
|
||||
|
@ -235,7 +235,7 @@ void ShaderCache::LoadShaderCache(T& cache, APIType api_type, const char* type,
|
|||
CacheReader(T& cache_) : cache(cache_) {}
|
||||
void Read(const K& key, const u8* value, u32 value_size)
|
||||
{
|
||||
auto shader = g_renderer->CreateShaderFromBinary(stage, value, value_size);
|
||||
auto shader = g_gfx->CreateShaderFromBinary(stage, value, value_size);
|
||||
if (shader)
|
||||
{
|
||||
auto& entry = cache.shader_map[key];
|
||||
|
@ -298,7 +298,7 @@ void ShaderCache::LoadPipelineCache(T& cache, LinearDiskCache<DiskKeyType, u8>&
|
|||
if (!config)
|
||||
return;
|
||||
|
||||
auto pipeline = g_renderer->CreatePipeline(*config, value, value_size);
|
||||
auto pipeline = g_gfx->CreatePipeline(*config, value, value_size);
|
||||
if (!pipeline)
|
||||
{
|
||||
// If any of the pipelines fail to create, consider the cache stale.
|
||||
|
@ -435,7 +435,7 @@ std::unique_ptr<AbstractShader> ShaderCache::CompileVertexShader(const VertexSha
|
|||
{
|
||||
const ShaderCode source_code =
|
||||
GenerateVertexShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
|
||||
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer());
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader>
|
||||
|
@ -443,7 +443,7 @@ ShaderCache::CompileVertexUberShader(const UberShader::VertexShaderUid& uid) con
|
|||
{
|
||||
const ShaderCode source_code =
|
||||
UberShader::GenVertexShader(m_api_type, m_host_config, uid.GetUidData());
|
||||
return g_renderer->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(),
|
||||
return g_gfx->CreateShaderFromSource(ShaderStage::Vertex, source_code.GetBuffer(),
|
||||
fmt::to_string(*uid.GetUidData()));
|
||||
}
|
||||
|
||||
|
@ -451,7 +451,7 @@ std::unique_ptr<AbstractShader> ShaderCache::CompilePixelShader(const PixelShade
|
|||
{
|
||||
const ShaderCode source_code =
|
||||
GeneratePixelShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer());
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader>
|
||||
|
@ -459,7 +459,7 @@ ShaderCache::CompilePixelUberShader(const UberShader::PixelShaderUid& uid) const
|
|||
{
|
||||
const ShaderCode source_code =
|
||||
UberShader::GenPixelShader(m_api_type, m_host_config, uid.GetUidData());
|
||||
return g_renderer->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
||||
return g_gfx->CreateShaderFromSource(ShaderStage::Pixel, source_code.GetBuffer(),
|
||||
fmt::to_string(*uid.GetUidData()));
|
||||
}
|
||||
|
||||
|
@ -556,7 +556,7 @@ const AbstractShader* ShaderCache::CreateGeometryShader(const GeometryShaderUid&
|
|||
const ShaderCode source_code =
|
||||
GenerateGeometryShaderCode(m_api_type, m_host_config, uid.GetUidData());
|
||||
std::unique_ptr<AbstractShader> shader =
|
||||
g_renderer->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(),
|
||||
g_gfx->CreateShaderFromSource(ShaderStage::Geometry, source_code.GetBuffer(),
|
||||
fmt::format("Geometry shader: {}", *uid.GetUidData()));
|
||||
|
||||
auto& entry = m_gs_cache.shader_map[uid];
|
||||
|
@ -1159,7 +1159,7 @@ void ShaderCache::QueuePipelineCompile(const GXPipelineUid& uid, u32 priority)
|
|||
bool Compile() override
|
||||
{
|
||||
if (config)
|
||||
pipeline = g_renderer->CreatePipeline(*config);
|
||||
pipeline = g_gfx->CreatePipeline(*config);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1234,7 +1234,7 @@ void ShaderCache::QueueUberPipelineCompile(const GXUberPipelineUid& uid, u32 pri
|
|||
bool Compile() override
|
||||
{
|
||||
if (config)
|
||||
UberPipeline = g_renderer->CreatePipeline(*config);
|
||||
UberPipeline = g_gfx->CreatePipeline(*config);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1372,7 +1372,7 @@ ShaderCache::GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShader
|
|||
return iter->second.get();
|
||||
|
||||
auto shader_code = TextureConversionShaderGen::GeneratePixelShader(m_api_type, uid.GetUidData());
|
||||
auto shader = g_renderer->CreateShaderFromSource(
|
||||
auto shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, shader_code.GetBuffer(),
|
||||
fmt::format("EFB copy to VRAM pixel shader: {}", *uid.GetUidData()));
|
||||
if (!shader)
|
||||
|
@ -1392,7 +1392,7 @@ ShaderCache::GetEFBCopyToVRAMPipeline(const TextureConversionShaderGen::TCShader
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
auto iiter = m_efb_copy_to_vram_pipelines.emplace(uid, g_renderer->CreatePipeline(config));
|
||||
auto iiter = m_efb_copy_to_vram_pipelines.emplace(uid, g_gfx->CreatePipeline(config));
|
||||
return iiter.first->second.get();
|
||||
}
|
||||
|
||||
|
@ -1404,7 +1404,7 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
|
|||
|
||||
const std::string shader_code =
|
||||
TextureConversionShaderTiled::GenerateEncodingShader(uid, m_api_type);
|
||||
const auto shader = g_renderer->CreateShaderFromSource(
|
||||
const auto shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, shader_code, fmt::format("EFB copy to RAM pixel shader: {}", uid));
|
||||
if (!shader)
|
||||
{
|
||||
|
@ -1420,19 +1420,19 @@ const AbstractPipeline* ShaderCache::GetEFBCopyToRAMPipeline(const EFBCopyParams
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetColorFramebufferState(AbstractTextureFormat::BGRA8);
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
auto iiter = m_efb_copy_to_ram_pipelines.emplace(uid, g_renderer->CreatePipeline(config));
|
||||
auto iiter = m_efb_copy_to_ram_pipelines.emplace(uid, g_gfx->CreatePipeline(config));
|
||||
return iiter.first->second.get();
|
||||
}
|
||||
|
||||
bool ShaderCache::CompileSharedPipelines()
|
||||
{
|
||||
m_screen_quad_vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
m_screen_quad_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateScreenQuadVertexShader(),
|
||||
"Screen quad vertex shader");
|
||||
m_texture_copy_vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
m_texture_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, FramebufferShaderGen::GenerateTextureCopyVertexShader(),
|
||||
"Texture copy vertex shader");
|
||||
m_efb_copy_vertex_shader = g_renderer->CreateShaderFromSource(
|
||||
m_efb_copy_vertex_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Vertex, TextureConversionShaderGen::GenerateVertexShader(m_api_type).GetBuffer(),
|
||||
"EFB copy vertex shader");
|
||||
if (!m_screen_quad_vertex_shader || !m_texture_copy_vertex_shader || !m_efb_copy_vertex_shader)
|
||||
|
@ -1440,20 +1440,20 @@ bool ShaderCache::CompileSharedPipelines()
|
|||
|
||||
if (UseGeometryShaderForEFBCopies())
|
||||
{
|
||||
m_texcoord_geometry_shader = g_renderer->CreateShaderFromSource(
|
||||
m_texcoord_geometry_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(1, 0),
|
||||
"Texcoord passthrough geometry shader");
|
||||
m_color_geometry_shader = g_renderer->CreateShaderFromSource(
|
||||
m_color_geometry_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Geometry, FramebufferShaderGen::GeneratePassthroughGeometryShader(0, 1),
|
||||
"Color passthrough geometry shader");
|
||||
if (!m_texcoord_geometry_shader || !m_color_geometry_shader)
|
||||
return false;
|
||||
}
|
||||
|
||||
m_texture_copy_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
m_texture_copy_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateTextureCopyPixelShader(),
|
||||
"Texture copy pixel shader");
|
||||
m_color_pixel_shader = g_renderer->CreateShaderFromSource(
|
||||
m_color_pixel_shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, FramebufferShaderGen::GenerateColorPixelShader(), "Color pixel shader");
|
||||
if (!m_texture_copy_pixel_shader || !m_color_pixel_shader)
|
||||
return false;
|
||||
|
@ -1468,14 +1468,14 @@ bool ShaderCache::CompileSharedPipelines()
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
m_copy_rgba8_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_copy_rgba8_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_copy_rgba8_pipeline)
|
||||
return false;
|
||||
|
||||
if (UseGeometryShaderForEFBCopies())
|
||||
{
|
||||
config.geometry_shader = m_texcoord_geometry_shader.get();
|
||||
m_rgba8_stereo_copy_pipeline = g_renderer->CreatePipeline(config);
|
||||
m_rgba8_stereo_copy_pipeline = g_gfx->CreatePipeline(config);
|
||||
if (!m_rgba8_stereo_copy_pipeline)
|
||||
return false;
|
||||
}
|
||||
|
@ -1488,7 +1488,7 @@ bool ShaderCache::CompileSharedPipelines()
|
|||
for (size_t i = 0; i < NUM_PALETTE_CONVERSION_SHADERS; i++)
|
||||
{
|
||||
TLUTFormat format = static_cast<TLUTFormat>(i);
|
||||
auto shader = g_renderer->CreateShaderFromSource(
|
||||
auto shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel,
|
||||
TextureConversionShaderTiled::GeneratePaletteConversionShader(format, m_api_type),
|
||||
fmt::format("Palette conversion pixel shader: {}", format));
|
||||
|
@ -1496,7 +1496,7 @@ bool ShaderCache::CompileSharedPipelines()
|
|||
return false;
|
||||
|
||||
config.pixel_shader = shader.get();
|
||||
m_palette_conversion_pipelines[i] = g_renderer->CreatePipeline(config);
|
||||
m_palette_conversion_pipelines[i] = g_gfx->CreatePipeline(config);
|
||||
if (!m_palette_conversion_pipelines[i])
|
||||
return false;
|
||||
}
|
||||
|
@ -1527,7 +1527,7 @@ const AbstractPipeline* ShaderCache::GetTextureReinterpretPipeline(TextureFormat
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractShader> shader = g_renderer->CreateShaderFromSource(
|
||||
std::unique_ptr<AbstractShader> shader = g_gfx->CreateShaderFromSource(
|
||||
ShaderStage::Pixel, shader_source,
|
||||
fmt::format("Texture reinterpret pixel shader: {} to {}", from_format, to_format));
|
||||
if (!shader)
|
||||
|
@ -1546,7 +1546,7 @@ const AbstractPipeline* ShaderCache::GetTextureReinterpretPipeline(TextureFormat
|
|||
config.blending_state = RenderState::GetNoBlendingBlendState();
|
||||
config.framebuffer_state = RenderState::GetRGBA8FramebufferState();
|
||||
config.usage = AbstractPipelineUsage::Utility;
|
||||
auto iiter = m_texture_reinterpret_pipelines.emplace(key, g_renderer->CreatePipeline(config));
|
||||
auto iiter = m_texture_reinterpret_pipelines.emplace(key, g_gfx->CreatePipeline(config));
|
||||
return iiter.first->second.get();
|
||||
}
|
||||
|
||||
|
@ -1574,7 +1574,7 @@ ShaderCache::GetTextureDecodingShader(TextureFormat format,
|
|||
fmt::format("Texture decoding compute shader: {}", format);
|
||||
|
||||
std::unique_ptr<AbstractShader> shader =
|
||||
g_renderer->CreateShaderFromSource(ShaderStage::Compute, shader_source, name);
|
||||
g_gfx->CreateShaderFromSource(ShaderStage::Compute, shader_source, name);
|
||||
if (!shader)
|
||||
{
|
||||
m_texture_decoding_shaders.emplace(key, nullptr);
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/AbstractFramebuffer.h"
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/AbstractStagingTexture.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
|
@ -298,7 +299,7 @@ RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const
|
|||
decoded_entry->SetNotCopy();
|
||||
decoded_entry->may_have_overlapping_textures = entry->may_have_overlapping_textures;
|
||||
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
|
||||
const u32 palette_size = entry->format == TextureFormat::I4 ? 32 : 512;
|
||||
u32 texel_buffer_offset;
|
||||
|
@ -318,19 +319,19 @@ RcTcacheEntry TextureCacheBase::ApplyPaletteToEntry(RcTcacheEntry& entry, const
|
|||
uniforms.texel_buffer_offset = texel_buffer_offset;
|
||||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
|
||||
g_renderer->SetAndDiscardFramebuffer(decoded_entry->framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(decoded_entry->texture->GetRect());
|
||||
g_renderer->SetPipeline(pipeline);
|
||||
g_renderer->SetTexture(1, entry->texture.get());
|
||||
g_renderer->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->SetAndDiscardFramebuffer(decoded_entry->framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(decoded_entry->texture->GetRect());
|
||||
g_gfx->SetPipeline(pipeline);
|
||||
g_gfx->SetTexture(1, entry->texture.get());
|
||||
g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
decoded_entry->texture->FinishedRendering();
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG_FMT(VIDEO, "Texel buffer upload of {} bytes failed", palette_size);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
}
|
||||
|
||||
textures_by_address.emplace(decoded_entry->addr, decoded_entry);
|
||||
|
@ -369,14 +370,14 @@ RcTcacheEntry TextureCacheBase::ReinterpretEntry(const RcTcacheEntry& existing_e
|
|||
reinterpreted_entry->may_have_overlapping_textures =
|
||||
existing_entry->may_have_overlapping_textures;
|
||||
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_renderer->SetAndDiscardFramebuffer(reinterpreted_entry->framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(reinterpreted_entry->texture->GetRect());
|
||||
g_renderer->SetPipeline(pipeline);
|
||||
g_renderer->SetTexture(0, existing_entry->texture.get());
|
||||
g_renderer->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
g_gfx->SetAndDiscardFramebuffer(reinterpreted_entry->framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(reinterpreted_entry->texture->GetRect());
|
||||
g_gfx->SetPipeline(pipeline);
|
||||
g_gfx->SetTexture(0, existing_entry->texture.get());
|
||||
g_gfx->SetSamplerState(1, RenderState::GetPointSamplerState());
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
reinterpreted_entry->texture->FinishedRendering();
|
||||
|
||||
textures_by_address.emplace(reinterpreted_entry->addr, reinterpreted_entry);
|
||||
|
@ -408,9 +409,8 @@ void TextureCacheBase::ScaleTextureCacheEntryTo(RcTcacheEntry& entry, u32 new_wi
|
|||
}
|
||||
|
||||
// No need to convert the coordinates here since they'll be the same.
|
||||
g_renderer->ScaleTexture(new_texture->framebuffer.get(),
|
||||
new_texture->texture->GetConfig().GetRect(), entry->texture.get(),
|
||||
entry->texture->GetConfig().GetRect());
|
||||
g_gfx->ScaleTexture(new_texture->framebuffer.get(), new_texture->texture->GetConfig().GetRect(),
|
||||
entry->texture.get(), entry->texture->GetConfig().GetRect());
|
||||
entry->texture.swap(new_texture->texture);
|
||||
entry->framebuffer.swap(new_texture->framebuffer);
|
||||
|
||||
|
@ -432,8 +432,7 @@ bool TextureCacheBase::CheckReadbackTexture(u32 width, u32 height, AbstractTextu
|
|||
|
||||
TextureConfig staging_config(std::max(width, 128u), std::max(height, 128u), 1, 1, 1, format, 0);
|
||||
m_readback_texture.reset();
|
||||
m_readback_texture =
|
||||
g_renderer->CreateStagingTexture(StagingTextureType::Readback, staging_config);
|
||||
m_readback_texture = g_gfx->CreateStagingTexture(StagingTextureType::Readback, staging_config);
|
||||
return m_readback_texture != nullptr;
|
||||
}
|
||||
|
||||
|
@ -1081,7 +1080,7 @@ static void SetSamplerState(u32 index, float custom_tex_scale, bool custom_tex,
|
|||
state.tm0.anisotropic_filtering = false;
|
||||
}
|
||||
|
||||
g_renderer->SetSamplerState(index, state);
|
||||
g_gfx->SetSamplerState(index, state);
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& pixel_shader_manager = system.GetPixelShaderManager();
|
||||
pixel_shader_manager.SetSamplerState(index, state.tm0.hex, state.tm1.hex);
|
||||
|
@ -1096,7 +1095,7 @@ void TextureCacheBase::BindTextures(BitSet32 used_textures)
|
|||
const RcTcacheEntry& tentry = bound_textures[i];
|
||||
if (used_textures[i] && tentry)
|
||||
{
|
||||
g_renderer->SetTexture(i, tentry->texture.get());
|
||||
g_gfx->SetTexture(i, tentry->texture.get());
|
||||
pixel_shader_manager.SetTexDims(i, tentry->native_width, tentry->native_height);
|
||||
|
||||
const float custom_tex_scale = tentry->GetWidth() / float(tentry->native_width);
|
||||
|
@ -2013,7 +2012,7 @@ void TextureCacheBase::StitchXFBCopy(RcTcacheEntry& stitched_entry)
|
|||
// We may have to scale if one of the copies is not internal resolution.
|
||||
if (srcrect.GetWidth() != dstrect.GetWidth() || srcrect.GetHeight() != dstrect.GetHeight())
|
||||
{
|
||||
g_renderer->ScaleTexture(stitched_entry->framebuffer.get(), dstrect, entry->texture.get(),
|
||||
g_gfx->ScaleTexture(stitched_entry->framebuffer.get(), dstrect, entry->texture.get(),
|
||||
srcrect);
|
||||
}
|
||||
else
|
||||
|
@ -2521,7 +2520,7 @@ std::unique_ptr<AbstractStagingTexture> TextureCacheBase::GetEFBCopyStagingTextu
|
|||
return ptr;
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractStagingTexture> tex = g_renderer->CreateStagingTexture(
|
||||
std::unique_ptr<AbstractStagingTexture> tex = g_gfx->CreateStagingTexture(
|
||||
StagingTextureType::Readback, m_efb_encoding_texture->GetConfig());
|
||||
if (!tex)
|
||||
WARN_LOG_FMT(VIDEO, "Failed to create EFB copy staging texture");
|
||||
|
@ -2614,7 +2613,7 @@ TextureCacheBase::AllocateTexture(const TextureConfig& config)
|
|||
return std::move(entry);
|
||||
}
|
||||
|
||||
std::unique_ptr<AbstractTexture> texture = g_renderer->CreateTexture(config);
|
||||
std::unique_ptr<AbstractTexture> texture = g_gfx->CreateTexture(config);
|
||||
if (!texture)
|
||||
{
|
||||
WARN_LOG_FMT(VIDEO, "Failed to allocate a {}x{}x{} texture", config.width, config.height,
|
||||
|
@ -2625,7 +2624,7 @@ TextureCacheBase::AllocateTexture(const TextureConfig& config)
|
|||
std::unique_ptr<AbstractFramebuffer> framebuffer;
|
||||
if (config.IsRenderTarget())
|
||||
{
|
||||
framebuffer = g_renderer->CreateFramebuffer(texture.get(), nullptr);
|
||||
framebuffer = g_gfx->CreateFramebuffer(texture.get(), nullptr);
|
||||
if (!framebuffer)
|
||||
{
|
||||
WARN_LOG_FMT(VIDEO, "Failed to allocate a {}x{}x{} framebuffer", config.width, config.height,
|
||||
|
@ -2745,12 +2744,11 @@ bool TextureCacheBase::CreateUtilityTextures()
|
|||
{
|
||||
constexpr TextureConfig encoding_texture_config(
|
||||
EFB_WIDTH * 4, 1024, 1, 1, 1, AbstractTextureFormat::BGRA8, AbstractTextureFlag_RenderTarget);
|
||||
m_efb_encoding_texture =
|
||||
g_renderer->CreateTexture(encoding_texture_config, "EFB encoding texture");
|
||||
m_efb_encoding_texture = g_gfx->CreateTexture(encoding_texture_config, "EFB encoding texture");
|
||||
if (!m_efb_encoding_texture)
|
||||
return false;
|
||||
|
||||
m_efb_encoding_framebuffer = g_renderer->CreateFramebuffer(m_efb_encoding_texture.get(), nullptr);
|
||||
m_efb_encoding_framebuffer = g_gfx->CreateFramebuffer(m_efb_encoding_texture.get(), nullptr);
|
||||
if (!m_efb_encoding_framebuffer)
|
||||
return false;
|
||||
|
||||
|
@ -2759,7 +2757,7 @@ bool TextureCacheBase::CreateUtilityTextures()
|
|||
constexpr TextureConfig decoding_texture_config(
|
||||
1024, 1024, 1, 1, 1, AbstractTextureFormat::RGBA8, AbstractTextureFlag_ComputeImage);
|
||||
m_decoding_texture =
|
||||
g_renderer->CreateTexture(decoding_texture_config, "GPU texture decoding texture");
|
||||
g_gfx->CreateTexture(decoding_texture_config, "GPU texture decoding texture");
|
||||
if (!m_decoding_texture)
|
||||
return false;
|
||||
}
|
||||
|
@ -2788,14 +2786,14 @@ void TextureCacheBase::CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_c
|
|||
}
|
||||
|
||||
const auto scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
const auto framebuffer_rect = g_renderer->ConvertFramebufferRectangle(
|
||||
const auto framebuffer_rect = g_gfx->ConvertFramebufferRectangle(
|
||||
scaled_src_rect, g_framebuffer_manager->GetEFBFramebuffer());
|
||||
AbstractTexture* src_texture =
|
||||
is_depth_copy ? g_framebuffer_manager->ResolveEFBDepthTexture(framebuffer_rect) :
|
||||
g_framebuffer_manager->ResolveEFBColorTexture(framebuffer_rect);
|
||||
|
||||
src_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
|
||||
// Fill uniform buffer.
|
||||
struct Uniforms
|
||||
|
@ -2832,14 +2830,14 @@ void TextureCacheBase::CopyEFBToCacheEntry(RcTcacheEntry& entry, bool is_depth_c
|
|||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
|
||||
// Use the copy pipeline to render the VRAM copy.
|
||||
g_renderer->SetAndDiscardFramebuffer(entry->framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(entry->framebuffer->GetRect());
|
||||
g_renderer->SetPipeline(copy_pipeline);
|
||||
g_renderer->SetTexture(0, src_texture);
|
||||
g_renderer->SetSamplerState(0, linear_filter ? RenderState::GetLinearSamplerState() :
|
||||
g_gfx->SetAndDiscardFramebuffer(entry->framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(entry->framebuffer->GetRect());
|
||||
g_gfx->SetPipeline(copy_pipeline);
|
||||
g_gfx->SetTexture(0, src_texture);
|
||||
g_gfx->SetSamplerState(0, linear_filter ? RenderState::GetLinearSamplerState() :
|
||||
RenderState::GetPointSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->Draw(0, 3);
|
||||
g_gfx->EndUtilityDrawing();
|
||||
entry->texture->FinishedRendering();
|
||||
}
|
||||
|
||||
|
@ -2862,14 +2860,14 @@ void TextureCacheBase::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams&
|
|||
}
|
||||
|
||||
const auto scaled_src_rect = g_renderer->ConvertEFBRectangle(src_rect);
|
||||
const auto framebuffer_rect = g_renderer->ConvertFramebufferRectangle(
|
||||
const auto framebuffer_rect = g_gfx->ConvertFramebufferRectangle(
|
||||
scaled_src_rect, g_framebuffer_manager->GetEFBFramebuffer());
|
||||
AbstractTexture* src_texture =
|
||||
params.depth ? g_framebuffer_manager->ResolveEFBDepthTexture(framebuffer_rect) :
|
||||
g_framebuffer_manager->ResolveEFBColorTexture(framebuffer_rect);
|
||||
|
||||
src_texture->FinishedRendering();
|
||||
g_renderer->BeginUtilityDrawing();
|
||||
g_gfx->BeginUtilityDrawing();
|
||||
|
||||
// Fill uniform buffer.
|
||||
struct Uniforms
|
||||
|
@ -2909,15 +2907,15 @@ void TextureCacheBase::CopyEFB(AbstractStagingTexture* dst, const EFBCopyParams&
|
|||
const auto encode_rect = MathUtil::Rectangle<int>(0, 0, render_width, render_height);
|
||||
|
||||
// Render to GPU texture, and then copy to CPU-accessible texture.
|
||||
g_renderer->SetAndDiscardFramebuffer(m_efb_encoding_framebuffer.get());
|
||||
g_renderer->SetViewportAndScissor(encode_rect);
|
||||
g_renderer->SetPipeline(copy_pipeline);
|
||||
g_renderer->SetTexture(0, src_texture);
|
||||
g_renderer->SetSamplerState(0, linear_filter ? RenderState::GetLinearSamplerState() :
|
||||
g_gfx->SetAndDiscardFramebuffer(m_efb_encoding_framebuffer.get());
|
||||
g_gfx->SetViewportAndScissor(encode_rect);
|
||||
g_gfx->SetPipeline(copy_pipeline);
|
||||
g_gfx->SetTexture(0, src_texture);
|
||||
g_gfx->SetSamplerState(0, linear_filter ? RenderState::GetLinearSamplerState() :
|
||||
RenderState::GetPointSamplerState());
|
||||
g_renderer->Draw(0, 3);
|
||||
g_gfx->Draw(0, 3);
|
||||
dst->CopyFromTexture(m_efb_encoding_texture.get(), encode_rect, 0, 0, encode_rect);
|
||||
g_renderer->EndUtilityDrawing();
|
||||
g_gfx->EndUtilityDrawing();
|
||||
|
||||
// Flush if there's sufficient draws between this copy and the last.
|
||||
g_vertex_manager->OnEFBCopyToRAM();
|
||||
|
@ -2970,11 +2968,11 @@ bool TextureCacheBase::DecodeTextureOnGPU(RcTcacheEntry& entry, u32 dst_level, c
|
|||
aligned_height, src_offset, row_stride / bytes_per_buffer_elem,
|
||||
palette_offset};
|
||||
g_vertex_manager->UploadUtilityUniforms(&uniforms, sizeof(uniforms));
|
||||
g_renderer->SetComputeImageTexture(m_decoding_texture.get(), false, true);
|
||||
g_gfx->SetComputeImageTexture(m_decoding_texture.get(), false, true);
|
||||
|
||||
auto dispatch_groups =
|
||||
TextureConversionShaderTiled::GetDispatchCount(info, aligned_width, aligned_height);
|
||||
g_renderer->DispatchComputeShader(shader, info->group_size_x, info->group_size_y, 1,
|
||||
g_gfx->DispatchComputeShader(shader, info->group_size_x, info->group_size_y, 1,
|
||||
dispatch_groups.first, dispatch_groups.second, 1);
|
||||
|
||||
// Copy from decoding texture -> final texture
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
#include "Core/HW/Memmap.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/CPMemory.h"
|
||||
#include "VideoCommon/DataReader.h"
|
||||
#include "VideoCommon/IndexGenerator.h"
|
||||
#include "VideoCommon/NativeVertexFormat.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/Statistics.h"
|
||||
#include "VideoCommon/VertexLoaderBase.h"
|
||||
#include "VideoCommon/VertexManagerBase.h"
|
||||
|
@ -140,7 +140,7 @@ NativeVertexFormat* GetOrCreateMatchingFormat(const PortableVertexDeclaration& d
|
|||
auto iter = s_native_vertex_map.find(decl);
|
||||
if (iter == s_native_vertex_map.end())
|
||||
{
|
||||
std::unique_ptr<NativeVertexFormat> fmt = g_renderer->CreateNativeVertexFormat(decl);
|
||||
std::unique_ptr<NativeVertexFormat> fmt = g_gfx->CreateNativeVertexFormat(decl);
|
||||
auto ipair = s_native_vertex_map.emplace(decl, std::move(fmt));
|
||||
iter = ipair.first;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "Core/DolphinAnalytics.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "VideoCommon/AbstractGfx.h"
|
||||
#include "VideoCommon/BPMemory.h"
|
||||
#include "VideoCommon/BoundingBox.h"
|
||||
#include "VideoCommon/DataReader.h"
|
||||
|
@ -329,7 +330,7 @@ void VertexManagerBase::DrawCurrentBatch(u32 base_index, u32 num_indices, u32 ba
|
|||
g_renderer->BBoxFlush();
|
||||
}
|
||||
|
||||
g_renderer->DrawIndexed(base_index, num_indices, base_vertex);
|
||||
g_gfx->DrawIndexed(base_index, num_indices, base_vertex);
|
||||
}
|
||||
|
||||
void VertexManagerBase::UploadUniforms()
|
||||
|
@ -599,7 +600,7 @@ void VertexManagerBase::Flush()
|
|||
UpdatePipelineObject();
|
||||
if (m_current_pipeline_object)
|
||||
{
|
||||
g_renderer->SetPipeline(m_current_pipeline_object);
|
||||
g_gfx->SetPipeline(m_current_pipeline_object);
|
||||
if (PerfQueryBase::ShouldEmulate())
|
||||
g_perf_query->EnableQuery(bpmem.zcontrol.early_ztest ? PQG_ZCOMP_ZCOMPLOC : PQG_ZCOMP);
|
||||
|
||||
|
@ -877,7 +878,7 @@ void VertexManagerBase::OnDraw()
|
|||
u32 diff = m_draw_counter - m_last_efb_copy_draw_counter;
|
||||
if (m_unflushed_efb_copy && diff > MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK)
|
||||
{
|
||||
g_renderer->Flush();
|
||||
g_gfx->Flush();
|
||||
m_unflushed_efb_copy = false;
|
||||
m_last_efb_copy_draw_counter = m_draw_counter;
|
||||
}
|
||||
|
@ -892,7 +893,7 @@ void VertexManagerBase::OnDraw()
|
|||
m_scheduled_command_buffer_kicks.end(), m_draw_counter))
|
||||
{
|
||||
// Kick a command buffer on the background thread.
|
||||
g_renderer->Flush();
|
||||
g_gfx->Flush();
|
||||
m_unflushed_efb_copy = false;
|
||||
m_last_efb_copy_draw_counter = m_draw_counter;
|
||||
}
|
||||
|
@ -927,7 +928,7 @@ void VertexManagerBase::OnEFBCopyToRAM()
|
|||
}
|
||||
|
||||
m_unflushed_efb_copy = false;
|
||||
g_renderer->Flush();
|
||||
g_gfx->Flush();
|
||||
}
|
||||
|
||||
void VertexManagerBase::OnEndFrame()
|
||||
|
|
|
@ -324,7 +324,9 @@ void VideoBackendBase::InitializeShared()
|
|||
// do not initialize again for the config window
|
||||
m_initialized = true;
|
||||
|
||||
g_renderer = std::make_unique<Renderer>();
|
||||
g_presenter = std::make_unique<VideoCommon::Presenter>();
|
||||
g_frame_dumper = std::make_unique<FrameDumper>();
|
||||
|
||||
auto& system = Core::System::GetInstance();
|
||||
auto& command_processor = system.GetCommandProcessor();
|
||||
|
@ -337,7 +339,13 @@ void VideoBackendBase::InitializeShared()
|
|||
system.GetGeometryShaderManager().Init();
|
||||
system.GetPixelShaderManager().Init();
|
||||
TMEM::Init();
|
||||
g_frame_dumper = std::make_unique<FrameDumper>();
|
||||
|
||||
if (!g_renderer->Initialize() || !g_presenter->Initialize())
|
||||
{
|
||||
PanicAlertFmtT("Failed to initialize renderer classes");
|
||||
Shutdown();
|
||||
return;
|
||||
}
|
||||
|
||||
g_Config.VerifyValidity();
|
||||
UpdateActiveConfig();
|
||||
|
|
Loading…
Reference in New Issue