mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-29 17:19:44 -06:00
Add support for hybrid XFB
This commit is contained in:
@ -520,15 +520,6 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
|
||||
// Scanline buffer, leave room for borders
|
||||
yuv444 scanline[EFB_WIDTH + 2];
|
||||
|
||||
// our internal yuv444 type is not normalized, so black is {0, 0, 0} instead of {16, 128, 128}
|
||||
yuv444 black;
|
||||
black.Y = 0;
|
||||
black.U = 0;
|
||||
black.V = 0;
|
||||
|
||||
scanline[0] = black; // black border at start
|
||||
scanline[right + 1] = black; // black border at end
|
||||
|
||||
for (u16 y = sourceRc.top; y < sourceRc.bottom; y++)
|
||||
{
|
||||
// Get a scanline of YUV pixels in 4:4:4 format
|
||||
@ -538,6 +529,10 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
|
||||
scanline[i] = GetColorYUV(x, y);
|
||||
}
|
||||
|
||||
// Flipper clamps the border colors
|
||||
scanline[0] = scanline[1];
|
||||
scanline[right + 1] = scanline[right];
|
||||
|
||||
// And Downsample them to 4:2:2
|
||||
for (int i = 1, x = left; x < right; i += 2, x += 2)
|
||||
{
|
||||
@ -562,26 +557,7 @@ void CopyToXFB(yuv422_packed* xfb_in_ram, u32 fbWidth, u32 fbHeight, const EFBRe
|
||||
// main memory or doing a yuyv conversion
|
||||
void BypassXFB(u8* texture, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc, float Gamma)
|
||||
{
|
||||
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t textureAddress = 0;
|
||||
const int left = sourceRc.left;
|
||||
const int right = sourceRc.right;
|
||||
|
||||
for (u16 y = sourceRc.top; y < sourceRc.bottom; y++)
|
||||
{
|
||||
for (u16 x = left; x < right; x++)
|
||||
{
|
||||
const u32 color = Common::swap32(GetColor(x, y) | 0xFF);
|
||||
|
||||
std::memcpy(&texture[textureAddress], &color, sizeof(u32));
|
||||
textureAddress += sizeof(u32);
|
||||
}
|
||||
}
|
||||
// TODO: Upload directly to texture cache.
|
||||
}
|
||||
|
||||
bool ZCompare(u16 x, u16 y, u32 z)
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "Common/Logging/Log.h"
|
||||
|
||||
#include "VideoBackends/Software/SWOGLWindow.h"
|
||||
#include "VideoCommon/AbstractTexture.h"
|
||||
|
||||
std::unique_ptr<SWOGLWindow> SWOGLWindow::s_instance;
|
||||
|
||||
@ -53,9 +54,9 @@ void SWOGLWindow::Prepare()
|
||||
|
||||
std::string frag_shader = "in vec2 TexCoord;\n"
|
||||
"out vec4 ColorOut;\n"
|
||||
"uniform sampler2D Texture;\n"
|
||||
"uniform sampler2DArray samp;\n"
|
||||
"void main() {\n"
|
||||
" ColorOut = texture(Texture, TexCoord);\n"
|
||||
" ColorOut = texture(samp, vec3(TexCoord, 0.0));\n"
|
||||
"}\n";
|
||||
|
||||
std::string vertex_shader = "out vec2 TexCoord;\n"
|
||||
@ -74,12 +75,9 @@ void SWOGLWindow::Prepare()
|
||||
|
||||
glUseProgram(m_image_program);
|
||||
|
||||
glUniform1i(glGetUniformLocation(m_image_program, "Texture"), 0);
|
||||
glUniform1i(glGetUniformLocation(m_image_program, "samp"), 0);
|
||||
|
||||
glGenTextures(1, &m_image_texture);
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
|
||||
glGenVertexArrays(1, &m_image_vao);
|
||||
}
|
||||
@ -89,23 +87,19 @@ void SWOGLWindow::PrintText(const std::string& text, int x, int y, u32 color)
|
||||
m_text.push_back({text, x, y, color});
|
||||
}
|
||||
|
||||
void SWOGLWindow::ShowImage(const u8* data, int stride, int width, int height, float aspect)
|
||||
void SWOGLWindow::ShowImage(AbstractTexture* image, float aspect)
|
||||
{
|
||||
GLInterface->MakeCurrent();
|
||||
GLInterface->Update();
|
||||
Prepare();
|
||||
GLInterface->Update(); // just updates the render window position and the backbuffer size
|
||||
|
||||
GLsizei glWidth = (GLsizei)GLInterface->GetBackBufferWidth();
|
||||
GLsizei glHeight = (GLsizei)GLInterface->GetBackBufferHeight();
|
||||
|
||||
glViewport(0, 0, glWidth, glHeight);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, m_image_texture);
|
||||
image->Bind(0);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, stride / 4);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (GLsizei)width, (GLsizei)height, 0, GL_RGBA,
|
||||
GL_UNSIGNED_BYTE, data);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
|
||||
glUseProgram(m_image_program);
|
||||
|
||||
@ -119,7 +113,6 @@ void SWOGLWindow::ShowImage(const u8* data, int stride, int width, int height, f
|
||||
m_text.clear();
|
||||
|
||||
GLInterface->Swap();
|
||||
GLInterface->ClearCurrent();
|
||||
}
|
||||
|
||||
int SWOGLWindow::PeekMessages()
|
||||
|
@ -10,17 +10,20 @@
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
|
||||
class AbstractTexture;
|
||||
|
||||
class SWOGLWindow
|
||||
{
|
||||
public:
|
||||
static void Init(void* window_handle);
|
||||
static void Shutdown();
|
||||
void Prepare();
|
||||
|
||||
// Will be printed on the *next* image
|
||||
void PrintText(const std::string& text, int x, int y, u32 color);
|
||||
|
||||
// Image to show, will be swapped immediately
|
||||
void ShowImage(const u8* data, int stride, int width, int height, float aspect);
|
||||
void ShowImage(AbstractTexture* image, float aspect);
|
||||
|
||||
int PeekMessages();
|
||||
|
||||
@ -28,7 +31,6 @@ public:
|
||||
|
||||
private:
|
||||
SWOGLWindow() {}
|
||||
void Prepare();
|
||||
|
||||
struct TextData
|
||||
{
|
||||
@ -40,5 +42,5 @@ private:
|
||||
|
||||
bool m_init{false};
|
||||
|
||||
u32 m_image_program, m_image_texture, m_image_vao;
|
||||
u32 m_image_program, m_image_vao;
|
||||
};
|
||||
|
@ -23,26 +23,13 @@
|
||||
#include "VideoCommon/VideoBackendBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
static u8* s_xfbColorTexture[2];
|
||||
static int s_currentColorTexture = 0;
|
||||
|
||||
SWRenderer::SWRenderer()
|
||||
: ::Renderer(static_cast<int>(MAX_XFB_WIDTH), static_cast<int>(MAX_XFB_HEIGHT))
|
||||
{
|
||||
}
|
||||
|
||||
SWRenderer::~SWRenderer()
|
||||
{
|
||||
delete[] s_xfbColorTexture[0];
|
||||
delete[] s_xfbColorTexture[1];
|
||||
}
|
||||
|
||||
void SWRenderer::Init()
|
||||
{
|
||||
s_xfbColorTexture[0] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
s_xfbColorTexture[1] = new u8[MAX_XFB_WIDTH * MAX_XFB_HEIGHT * 4];
|
||||
|
||||
s_currentColorTexture = 0;
|
||||
}
|
||||
|
||||
void SWRenderer::Shutdown()
|
||||
@ -55,80 +42,16 @@ void SWRenderer::RenderText(const std::string& pstr, int left, int top, u32 colo
|
||||
SWOGLWindow::s_instance->PrintText(pstr, left, top, color);
|
||||
}
|
||||
|
||||
u8* SWRenderer::GetNextColorTexture()
|
||||
{
|
||||
return s_xfbColorTexture[!s_currentColorTexture];
|
||||
}
|
||||
|
||||
u8* SWRenderer::GetCurrentColorTexture()
|
||||
{
|
||||
return s_xfbColorTexture[s_currentColorTexture];
|
||||
}
|
||||
|
||||
void SWRenderer::SwapColorTexture()
|
||||
{
|
||||
s_currentColorTexture = !s_currentColorTexture;
|
||||
}
|
||||
|
||||
void SWRenderer::UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight)
|
||||
{
|
||||
if (fbWidth * fbHeight > MAX_XFB_WIDTH * MAX_XFB_HEIGHT)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "Framebuffer is too large: %ix%i", fbWidth, fbHeight);
|
||||
return;
|
||||
}
|
||||
|
||||
u32 offset = 0;
|
||||
u8* TexturePointer = GetNextColorTexture();
|
||||
|
||||
for (u16 y = 0; y < fbHeight; y++)
|
||||
{
|
||||
for (u16 x = 0; x < fbWidth; x += 2)
|
||||
{
|
||||
// We do this one color sample (aka 2 RGB pixles) at a time
|
||||
int Y1 = xfb[x].Y - 16;
|
||||
int Y2 = xfb[x + 1].Y - 16;
|
||||
int U = int(xfb[x].UV) - 128;
|
||||
int V = int(xfb[x + 1].UV) - 128;
|
||||
|
||||
// We do the inverse BT.601 conversion for YCbCr to RGB
|
||||
// http://www.equasys.de/colorconversion.html#YCbCr-RGBColorFormatConversion
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] =
|
||||
MathUtil::Clamp(int(1.164f * Y1 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y1 + 2.017f * U), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 1.596f * V), 0, 255);
|
||||
TexturePointer[offset++] =
|
||||
MathUtil::Clamp(int(1.164f * Y2 - 0.392f * U - 0.813f * V), 0, 255);
|
||||
TexturePointer[offset++] = MathUtil::Clamp(int(1.164f * Y2 + 2.017f * U), 0, 255);
|
||||
TexturePointer[offset++] = 255;
|
||||
}
|
||||
xfb += fbWidth;
|
||||
}
|
||||
SwapColorTexture();
|
||||
}
|
||||
|
||||
// Called on the GPU thread
|
||||
void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||
const EFBRectangle& rc, u64 ticks, float Gamma)
|
||||
void SWRenderer::SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma)
|
||||
{
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
EfbInterface::yuv422_packed* xfb = (EfbInterface::yuv422_packed*)Memory::GetPointer(xfbAddr);
|
||||
UpdateColorTexture(xfb, fbWidth, fbHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
EfbInterface::BypassXFB(GetCurrentColorTexture(), fbWidth, fbHeight, rc, Gamma);
|
||||
}
|
||||
SWOGLWindow::s_instance->ShowImage(texture, 1.0);
|
||||
|
||||
// Save screenshot
|
||||
if (IsFrameDumping())
|
||||
{
|
||||
AVIDump::Frame state = AVIDump::FetchState(ticks);
|
||||
DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, state);
|
||||
//DumpFrameData(GetCurrentColorTexture(), fbWidth, fbHeight, fbWidth * 4, state);
|
||||
FinishFrameData();
|
||||
}
|
||||
|
||||
@ -136,15 +59,9 @@ void SWRenderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight,
|
||||
|
||||
DrawDebugText();
|
||||
|
||||
SWOGLWindow::s_instance->ShowImage(GetCurrentColorTexture(), fbWidth * 4, fbWidth, fbHeight, 1.0);
|
||||
SWOGLWindow::s_instance->ShowImage(texture, 1.0);
|
||||
|
||||
UpdateActiveConfig();
|
||||
|
||||
// virtual XFB is not supported
|
||||
if (g_ActiveConfig.bUseXFB)
|
||||
{
|
||||
Config::SetCurrent(Config::GFX_USE_REAL_XFB, true);
|
||||
}
|
||||
}
|
||||
|
||||
u32 SWRenderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 InputData)
|
||||
|
@ -14,16 +14,10 @@ class SWRenderer : public Renderer
|
||||
{
|
||||
public:
|
||||
SWRenderer();
|
||||
~SWRenderer() override;
|
||||
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
static u8* GetNextColorTexture();
|
||||
static u8* GetCurrentColorTexture();
|
||||
void SwapColorTexture();
|
||||
void UpdateColorTexture(EfbInterface::yuv422_packed* xfb, u32 fbWidth, u32 fbHeight);
|
||||
|
||||
void RenderText(const std::string& pstr, int left, int top, u32 color) override;
|
||||
u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override;
|
||||
void PokeEFB(EFBAccessType type, const EfbPokeData* points, size_t num_points) override {}
|
||||
@ -32,8 +26,7 @@ public:
|
||||
|
||||
TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) override;
|
||||
|
||||
void SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, const EFBRectangle& rc,
|
||||
u64 ticks, float Gamma) override;
|
||||
void SwapImpl(AbstractTexture* texture, const EFBRectangle& rc, u64 ticks, float Gamma) override;
|
||||
|
||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable,
|
||||
u32 color, u32 z) override;
|
||||
|
@ -8,16 +8,17 @@
|
||||
#include <utility>
|
||||
|
||||
#include "Common/CommonTypes.h"
|
||||
#include "Common/GL/GLInterfaceBase.h"
|
||||
|
||||
#include "VideoBackends/Software/Clipper.h"
|
||||
#include "VideoBackends/Software/DebugUtil.h"
|
||||
#include "VideoBackends/Software/EfbCopy.h"
|
||||
#include "VideoBackends/Software/EfbInterface.h"
|
||||
#include "VideoBackends/Software/Rasterizer.h"
|
||||
#include "VideoBackends/Software/SWOGLWindow.h"
|
||||
#include "VideoBackends/Software/SWRenderer.h"
|
||||
#include "VideoBackends/Software/SWTexture.h"
|
||||
#include "VideoBackends/Software/SWVertexLoader.h"
|
||||
#include "VideoBackends/Software/TextureCache.h"
|
||||
#include "VideoBackends/Software/VideoBackend.h"
|
||||
|
||||
#include "VideoCommon/FramebufferManagerBase.h"
|
||||
@ -46,58 +47,6 @@ public:
|
||||
bool IsFlushed() const override { return true; }
|
||||
};
|
||||
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette,
|
||||
TLUTFormat format) override
|
||||
{
|
||||
}
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override
|
||||
{
|
||||
return std::make_unique<SWTexture>(config);
|
||||
}
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, unsigned int cbuf_id, const float* colmat) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
};
|
||||
|
||||
class XFBSource : public XFBSourceBase
|
||||
{
|
||||
void DecodeToTexture(u32 xfbAddr, u32 fbWidth, u32 fbHeight) override {}
|
||||
void CopyEFB(float Gamma) override {}
|
||||
};
|
||||
|
||||
class FramebufferManager : public FramebufferManagerBase
|
||||
{
|
||||
std::unique_ptr<XFBSourceBase> CreateXFBSource(unsigned int target_width,
|
||||
unsigned int target_height,
|
||||
unsigned int layers) override
|
||||
{
|
||||
return std::make_unique<XFBSource>();
|
||||
}
|
||||
|
||||
std::pair<u32, u32> GetTargetSize() const override { return std::make_pair(0, 0); }
|
||||
void CopyToRealXFB(u32 xfbAddr, u32 fbStride, u32 fbHeight, const EFBRectangle& sourceRc,
|
||||
float Gamma = 1.0f) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
};
|
||||
|
||||
std::string VideoSoftware::GetName() const
|
||||
{
|
||||
return "Software Renderer";
|
||||
@ -123,6 +72,7 @@ void VideoSoftware::InitBackendInfo()
|
||||
g_Config.backend_info.bSupportsGPUTextureDecoding = false;
|
||||
g_Config.backend_info.bSupportsST3CTextures = false;
|
||||
g_Config.backend_info.bSupportsBPTCTextures = false;
|
||||
g_Config.backend_info.bSupportsCopyToVram = false;
|
||||
|
||||
// aamodes
|
||||
g_Config.backend_info.AAModes = {1};
|
||||
@ -169,12 +119,14 @@ void VideoSoftware::Video_Cleanup()
|
||||
// This is called after Video_Initialize() from the Core
|
||||
void VideoSoftware::Video_Prepare()
|
||||
{
|
||||
GLInterface->MakeCurrent();
|
||||
SWOGLWindow::s_instance->Prepare();
|
||||
|
||||
g_renderer = std::make_unique<SWRenderer>();
|
||||
g_vertex_manager = std::make_unique<SWVertexLoader>();
|
||||
g_perf_query = std::make_unique<PerfQuery>();
|
||||
g_texture_cache = std::make_unique<TextureCache>();
|
||||
SWRenderer::Init();
|
||||
g_framebuffer_manager = std::make_unique<FramebufferManager>();
|
||||
}
|
||||
|
||||
unsigned int VideoSoftware::PeekMessages()
|
||||
|
@ -65,6 +65,7 @@
|
||||
<ClInclude Include="SWTexture.h" />
|
||||
<ClInclude Include="SWVertexLoader.h" />
|
||||
<ClInclude Include="Tev.h" />
|
||||
<ClInclude Include="TextureCache.h" />
|
||||
<ClInclude Include="TextureEncoder.h" />
|
||||
<ClInclude Include="TextureSampler.h" />
|
||||
<ClInclude Include="TransformUnit.h" />
|
||||
|
41
Source/Core/VideoBackends/Software/TextureCache.h
Normal file
41
Source/Core/VideoBackends/Software/TextureCache.h
Normal file
@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "VideoBackends/Software/EfbCopy.h"
|
||||
#include "VideoBackends/Software/SWTexture.h"
|
||||
#include "VideoCommon/TextureCacheBase.h"
|
||||
|
||||
namespace SW
|
||||
{
|
||||
|
||||
class TextureCache : public TextureCacheBase
|
||||
{
|
||||
public:
|
||||
bool CompileShaders() override { return true; }
|
||||
void DeleteShaders() override {}
|
||||
void ConvertTexture(TCacheEntry* entry, TCacheEntry* unconverted, const void* palette,
|
||||
TLUTFormat format) override
|
||||
{
|
||||
}
|
||||
void CopyEFB(u8* dst, const EFBCopyParams& params, u32 native_width, u32 bytes_per_row,
|
||||
u32 num_blocks_y, u32 memory_stride, const EFBRectangle& src_rect,
|
||||
bool scale_by_half) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
|
||||
private:
|
||||
std::unique_ptr<AbstractTexture> CreateTexture(const TextureConfig& config) override
|
||||
{
|
||||
return std::make_unique<SWTexture>(config);
|
||||
}
|
||||
|
||||
void CopyEFBToCacheEntry(TCacheEntry* entry, bool is_depth_copy, const EFBRectangle& src_rect,
|
||||
bool scale_by_half, unsigned int cbuf_id, const float* colmat) override
|
||||
{
|
||||
EfbCopy::CopyEfb();
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace SW
|
Reference in New Issue
Block a user