Display buffer flips are now triggered by the CPU thread through the Video_UpdateXFB function. This is a fairly significant change of behavior, but it improves performance.
Also, render target code is cleaned up. Post-processing shaders now work with multisampling and Real-XFB mode. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@3545 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
a7eb7bbf00
commit
ade9479005
|
@ -1079,9 +1079,6 @@ void Update()
|
||||||
u8* xfbPtr = 0;
|
u8* xfbPtr = 0;
|
||||||
int yOffset = 0;
|
int yOffset = 0;
|
||||||
|
|
||||||
// (mb2) hack: We request XFB updates from CPUthread (here) only when homebrews use directly XFB without FIFO and CP
|
|
||||||
if (!Core::GetStartupParameter().bUseDualCore || CommandProcessor::IsCommandProcessorNotUsed())
|
|
||||||
{
|
|
||||||
if (NextXFBRender == 1)
|
if (NextXFBRender == 1)
|
||||||
{
|
{
|
||||||
NextXFBRender = LinesPerField;
|
NextXFBRender = LinesPerField;
|
||||||
|
@ -1118,7 +1115,6 @@ void Update()
|
||||||
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE);
|
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// check INT_PRERETRACE
|
// check INT_PRERETRACE
|
||||||
if (m_InterruptRegister[0].VCT == m_VBeamPos)
|
if (m_InterruptRegister[0].VCT == m_VBeamPos)
|
||||||
|
|
|
@ -143,7 +143,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
||||||
if (g_XFBUpdateRequested)
|
if (g_XFBUpdateRequested)
|
||||||
{
|
{
|
||||||
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||||
video_initialize.pCopiedToXFB();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if we are able to run this buffer
|
// check if we are able to run this buffer
|
||||||
|
|
|
@ -134,26 +134,7 @@ void CopyEFB(const Bypass &bp, const TRectangle &rc, const u32 &address, const b
|
||||||
|
|
||||||
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u8* pXFB, const u32 &dstWidth, const u32 &dstHeight)
|
void RenderToXFB(const Bypass &bp, const TRectangle &multirc, const float &yScale, const float &xfbLines, u8* pXFB, const u32 &dstWidth, const u32 &dstHeight)
|
||||||
{
|
{
|
||||||
// EFB to XFB
|
Renderer::RenderToXFB(pXFB, multirc, dstWidth, dstHeight);
|
||||||
if (g_Config.bUseXFB)
|
|
||||||
{
|
|
||||||
|
|
||||||
XFB_Write(pXFB, multirc, dstWidth, dstHeight);
|
|
||||||
// FIXME: we draw XFB from here in DC mode.
|
|
||||||
// Bad hack since we can have multiple EFB to XFB copy before a draw.
|
|
||||||
// Plus we should use width and height from VI regs (see VI->Update()).
|
|
||||||
// Dixit donkopunchstania for the info.
|
|
||||||
//DebugLog("(EFB to XFB->XFB_Draw): ptr: %08x | %ix%i", (u32)pXFB, dstWidth, dstHeight);
|
|
||||||
if (g_VideoInitialize.bUseDualCore)
|
|
||||||
XFB_Draw(pXFB, dstWidth, dstHeight, 0);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Hm, we need to compensate for the fact that the copy may be bigger than what is displayed.
|
|
||||||
// Seen in Spartan Warrior. Not sure how to deal with it yet.
|
|
||||||
Renderer::Swap(multirc);
|
|
||||||
}
|
|
||||||
g_VideoInitialize.pCopiedToXFB();
|
|
||||||
}
|
}
|
||||||
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
|
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
|
||||||
{
|
{
|
||||||
|
|
|
@ -49,6 +49,7 @@
|
||||||
#include "VertexLoaderManager.h"
|
#include "VertexLoaderManager.h"
|
||||||
#include "VertexLoader.h"
|
#include "VertexLoader.h"
|
||||||
#include "PostProcessing.h"
|
#include "PostProcessing.h"
|
||||||
|
#include "TextureConverter.h"
|
||||||
#include "XFB.h"
|
#include "XFB.h"
|
||||||
#include "OnScreenDisplay.h"
|
#include "OnScreenDisplay.h"
|
||||||
#include "Timer.h"
|
#include "Timer.h"
|
||||||
|
@ -122,6 +123,10 @@ static GLuint s_DepthBuffer = 0;
|
||||||
static GLuint s_ResolvedRenderTarget = 0;
|
static GLuint s_ResolvedRenderTarget = 0;
|
||||||
static GLuint s_ResolvedDepthTarget = 0;
|
static GLuint s_ResolvedDepthTarget = 0;
|
||||||
|
|
||||||
|
static TRectangle s_efbSourceRc;
|
||||||
|
static GLuint s_xfbFramebuffer = 0; // Only used when multisampling is on
|
||||||
|
static GLuint s_xfbTexture = 0;
|
||||||
|
|
||||||
static bool s_bHaveStencilBuffer = false;
|
static bool s_bHaveStencilBuffer = false;
|
||||||
static bool s_bHaveFramebufferBlit = false;
|
static bool s_bHaveFramebufferBlit = false;
|
||||||
static bool s_bHaveCoverageMSAA = false;
|
static bool s_bHaveCoverageMSAA = false;
|
||||||
|
@ -319,6 +324,12 @@ bool Renderer::Init()
|
||||||
if (s_targetheight < EFB_HEIGHT)
|
if (s_targetheight < EFB_HEIGHT)
|
||||||
s_targetheight = EFB_HEIGHT;
|
s_targetheight = EFB_HEIGHT;
|
||||||
|
|
||||||
|
// Create the XFB texture
|
||||||
|
glGenTextures(1, &s_xfbTexture);
|
||||||
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture);
|
||||||
|
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
SetDefaultRectTexParams();
|
||||||
|
|
||||||
glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer);
|
glGenFramebuffersEXT(1, (GLuint *)&s_uFramebuffer);
|
||||||
if (s_uFramebuffer == 0) {
|
if (s_uFramebuffer == 0) {
|
||||||
ERROR_LOG(VIDEO, "failed to create the renderbufferDoes your video card support OpenGL 2.x?");
|
ERROR_LOG(VIDEO, "failed to create the renderbufferDoes your video card support OpenGL 2.x?");
|
||||||
|
@ -365,6 +376,17 @@ bool Renderer::Init()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Create XFB framebuffer for transferring the multisampled EFB to the
|
||||||
|
// XFB texture
|
||||||
|
glGenFramebuffersEXT(1, &s_xfbFramebuffer);
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_xfbFramebuffer);
|
||||||
|
|
||||||
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture, 0);
|
||||||
|
|
||||||
|
GL_REPORT_FBO_ERROR();
|
||||||
|
|
||||||
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||||
|
|
||||||
// MSAA rendertarget init.
|
// MSAA rendertarget init.
|
||||||
// First set up the boring multisampled rendertarget.
|
// First set up the boring multisampled rendertarget.
|
||||||
glGenRenderbuffersEXT(1, &s_RenderTarget);
|
glGenRenderbuffersEXT(1, &s_RenderTarget);
|
||||||
|
@ -466,12 +488,7 @@ bool Renderer::Init()
|
||||||
if (!InitializeGL())
|
if (!InitializeGL())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
XFB_Init();
|
|
||||||
return glGetError() == GL_NO_ERROR && bSuccess;
|
return glGetError() == GL_NO_ERROR && bSuccess;
|
||||||
|
|
||||||
// Now save the actual settings
|
|
||||||
s_targetwidth = (int)OpenGL_GetBackbufferWidth();
|
|
||||||
s_targetheight = (int)OpenGL_GetBackbufferHeight();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::Shutdown(void)
|
void Renderer::Shutdown(void)
|
||||||
|
@ -479,24 +496,28 @@ void Renderer::Shutdown(void)
|
||||||
delete s_pfont;
|
delete s_pfont;
|
||||||
s_pfont = 0;
|
s_pfont = 0;
|
||||||
|
|
||||||
XFB_Shutdown();
|
|
||||||
|
|
||||||
if (g_cgcontext) {
|
if (g_cgcontext) {
|
||||||
cgDestroyContext(g_cgcontext);
|
cgDestroyContext(g_cgcontext);
|
||||||
g_cgcontext = 0;
|
g_cgcontext = 0;
|
||||||
}
|
}
|
||||||
if (s_RenderTarget) {
|
|
||||||
glDeleteTextures(1, &s_RenderTarget);
|
// Note: OpenGL delete functions automatically ignore if parameter is 0
|
||||||
s_RenderTarget = 0;
|
|
||||||
}
|
|
||||||
if (s_DepthTarget) {
|
|
||||||
glDeleteRenderbuffersEXT(1, &s_DepthTarget);
|
|
||||||
s_DepthTarget = 0;
|
|
||||||
}
|
|
||||||
if (s_uFramebuffer) {
|
|
||||||
glDeleteFramebuffersEXT(1, &s_uFramebuffer);
|
glDeleteFramebuffersEXT(1, &s_uFramebuffer);
|
||||||
s_uFramebuffer = 0;
|
s_uFramebuffer = 0;
|
||||||
}
|
|
||||||
|
glDeleteTextures(1, &s_RenderTarget);
|
||||||
|
s_RenderTarget = 0;
|
||||||
|
|
||||||
|
glDeleteRenderbuffersEXT(1, &s_DepthTarget);
|
||||||
|
s_DepthTarget = 0;
|
||||||
|
|
||||||
|
glDeleteFramebuffersEXT(1, &s_xfbFramebuffer);
|
||||||
|
s_xfbFramebuffer = 0;
|
||||||
|
|
||||||
|
glDeleteTextures(1, &s_xfbTexture);
|
||||||
|
s_xfbTexture = 0;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if(s_bAVIDumping) {
|
if(s_bAVIDumping) {
|
||||||
AVIDump::Stop();
|
AVIDump::Stop();
|
||||||
|
@ -579,6 +600,9 @@ float Renderer::GetTargetScaleY()
|
||||||
// Various supporting functions
|
// Various supporting functions
|
||||||
void Renderer::SetRenderTarget(GLuint targ)
|
void Renderer::SetRenderTarget(GLuint targ)
|
||||||
{
|
{
|
||||||
|
if (!targ && s_MSAASamples > 1)
|
||||||
|
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_RenderTarget);
|
||||||
|
else
|
||||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB,
|
||||||
targ != 0 ? targ : s_RenderTarget, 0);
|
targ != 0 ? targ : s_RenderTarget, 0);
|
||||||
}
|
}
|
||||||
|
@ -603,9 +627,14 @@ void Renderer::ResetGLState()
|
||||||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UpdateViewport();
|
||||||
|
|
||||||
void Renderer::RestoreGLState()
|
void Renderer::RestoreGLState()
|
||||||
{
|
{
|
||||||
// Gets us back into a more game-like state.
|
// Gets us back into a more game-like state.
|
||||||
|
|
||||||
|
UpdateViewport();
|
||||||
|
|
||||||
if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
|
if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
|
||||||
if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
|
if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
|
||||||
if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
|
if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
|
||||||
|
@ -849,11 +878,66 @@ void ComputeBackbufferRectangle(TRectangle *rc)
|
||||||
rc->bottom = YOffset + ceil(FloatGLHeight);
|
rc->bottom = YOffset + ceil(FloatGLHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::DecodeFromXFB(u8* xfbInRam, u32 dstWidth, u32 dstHeight, s32 yOffset)
|
||||||
|
{
|
||||||
|
TextureConverter::DecodeToTexture(xfbInRam + yOffset*(XFB_WIDTH*2), dstWidth, dstHeight, s_xfbTexture);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidth, u32 dstHeight)
|
||||||
|
{
|
||||||
|
// Make sure the previous contents made it to the screen if requested
|
||||||
|
if (g_XFBUpdateRequested)
|
||||||
|
{
|
||||||
|
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (g_Config.bUseXFB)
|
||||||
|
{
|
||||||
|
s_efbSourceRc.left = 0;
|
||||||
|
s_efbSourceRc.top = 0;
|
||||||
|
s_efbSourceRc.right = GetTargetWidth();
|
||||||
|
s_efbSourceRc.bottom = GetTargetHeight();
|
||||||
|
XFB_Write(xfbInRam, sourceRc, dstWidth, dstHeight);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Renderer::Swap will use the source rectangle saved here
|
||||||
|
s_efbSourceRc = sourceRc;
|
||||||
|
|
||||||
|
if (s_MSAASamples > 1)
|
||||||
|
{
|
||||||
|
// Cannot use glCopyTexImage2D on multisampled framebuffers, so
|
||||||
|
// EXT_framebuffer_blit must be used
|
||||||
|
|
||||||
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||||
|
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, s_xfbFramebuffer);
|
||||||
|
|
||||||
|
glBlitFramebufferEXT(
|
||||||
|
0, 0, s_targetwidth, s_targetheight,
|
||||||
|
0, 0, s_targetwidth, s_targetheight,
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||||
|
);
|
||||||
|
|
||||||
|
// Return to the EFB
|
||||||
|
SetFramebuffer(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Just copy the EFB directly
|
||||||
|
SetFramebuffer(0);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture);
|
||||||
|
glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGB, 0, 0, s_targetwidth, s_targetheight, 0);
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// This function has the final picture if the XFB functions are not used. We
|
// This function has the final picture. We
|
||||||
// adjust the aspect ratio here.
|
// adjust the aspect ratio here.
|
||||||
void Renderer::Swap(const TRectangle& rc)
|
void Renderer::Swap()
|
||||||
{
|
{
|
||||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
||||||
DVSTARTPROFILE();
|
DVSTARTPROFILE();
|
||||||
|
@ -868,8 +952,8 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
float v_max;
|
float v_max;
|
||||||
if (g_Config.bAutoScale)
|
if (g_Config.bAutoScale)
|
||||||
{
|
{
|
||||||
u_max = (rc.right - rc.left);
|
u_max = (s_efbSourceRc.right - s_efbSourceRc.left);
|
||||||
v_min = (float)GetTargetHeight() - (rc.bottom - rc.top);
|
v_min = (float)GetTargetHeight() - (s_efbSourceRc.bottom - s_efbSourceRc.top);
|
||||||
v_max = (float)GetTargetHeight();
|
v_max = (float)GetTargetHeight();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -879,37 +963,14 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tell the OSD Menu about the current internal resolution
|
// Tell the OSD Menu about the current internal resolution
|
||||||
OSDInternalW = rc.right; OSDInternalH = rc.bottom;
|
OSDInternalW = s_efbSourceRc.GetWidth(); OSDInternalH = s_efbSourceRc.bottom;
|
||||||
|
|
||||||
// Make sure that the wireframe setting doesn't screw up the screen copy.
|
// Make sure that the wireframe setting doesn't screw up the screen copy.
|
||||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// Textured triangles are necessary because of post-processing shaders
|
||||||
// Resolve the multisampled rendertarget into the normal one.
|
|
||||||
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
|
// Disable all other stages
|
||||||
if (/*s_bHaveFramebufferBlit*/ s_MSAASamples > 1)
|
|
||||||
{
|
|
||||||
// Use framebuffer blit to stretch screen.
|
|
||||||
// No messing around with annoying glBegin and viewports, plus can support multisampling.
|
|
||||||
if (s_MSAASamples > 1)
|
|
||||||
{
|
|
||||||
ResolveAndGetRenderTarget(rc);
|
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uResolvedFramebuffer);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
|
||||||
}
|
|
||||||
// Draw to the window buffer with bilinear filtering
|
|
||||||
glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, 0);
|
|
||||||
glBlitFramebufferEXT(0, v_min, u_max, v_max,
|
|
||||||
back_rc.left, back_rc.top, back_rc.right, back_rc.bottom,
|
|
||||||
GL_COLOR_BUFFER_BIT, GL_LINEAR);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// No framebuffer_blit extension - crappy gfx card! Fall back to plain texturing solution.
|
|
||||||
// Disable all other stages.
|
|
||||||
for (int i = 1; i < 8; ++i)
|
for (int i = 1; i < 8; ++i)
|
||||||
TextureMngr::DisableStage(i);
|
TextureMngr::DisableStage(i);
|
||||||
|
|
||||||
|
@ -920,28 +981,18 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
|
|
||||||
// Copy the framebuffer to screen.
|
// Copy the framebuffer to screen.
|
||||||
// TODO: Use glBlitFramebufferEXT.
|
|
||||||
// Render to the real buffer now.
|
// Render to the real buffer now.
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
|
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
|
||||||
|
|
||||||
// Texture map s_RenderTargets[s_curtarget] onto the main buffer
|
// Texture map s_xfbTexture onto the main buffer
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture);
|
||||||
// Use linear filtering.
|
// Use linear filtering.
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
/*
|
|
||||||
static const float vtx_data[8] = {-1, -1, -1, 1, 1, 1, 1, -1};
|
|
||||||
const float uv_data[8] = {0, v_min, 0, v_max, u_max, v_max, u_max, v_min};
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
|
||||||
glVertexPointer(2, GL_FLOAT, 0, (void *)vtx_data);
|
|
||||||
glTexCoordPointer(2, GL_FLOAT, 0, (void *)uv_data);
|
|
||||||
glDrawArrays(GL_QUADS, 0, 4);
|
|
||||||
*/
|
|
||||||
|
|
||||||
// We must call ApplyShader here even if no post proc is selected - it takes
|
// We must call ApplyShader here even if no post proc is selected - it takes
|
||||||
// care of disabling it in that case. It returns false in case of no post processing.
|
// care of disabling it in that case. It returns false in case of no post processing.
|
||||||
if (PostProcessing::ApplyShader())
|
if (PostProcessing::ApplyShader())
|
||||||
|
@ -968,7 +1019,6 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||||
TextureMngr::DisableStage(0);
|
TextureMngr::DisableStage(0);
|
||||||
}
|
|
||||||
|
|
||||||
// Wireframe
|
// Wireframe
|
||||||
if (g_Config.bWireFrame)
|
if (g_Config.bWireFrame)
|
||||||
|
@ -985,7 +1035,7 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
|
|
||||||
s_criticalScreenshot.Enter();
|
s_criticalScreenshot.Enter();
|
||||||
// Save screenshot
|
// Save screenshot
|
||||||
SaveRenderTarget(s_sScreenshotName.c_str(), rc.right, rc.bottom, (int)(v_min));
|
SaveRenderTarget(s_sScreenshotName.c_str(), s_efbSourceRc.right, s_efbSourceRc.bottom, (int)(v_min));
|
||||||
// Reset settings
|
// Reset settings
|
||||||
s_sScreenshotName = "";
|
s_sScreenshotName = "";
|
||||||
s_bScreenshot = false;
|
s_bScreenshot = false;
|
||||||
|
@ -1006,8 +1056,8 @@ void Renderer::Swap(const TRectangle& rc)
|
||||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||||
|
|
||||||
s_criticalScreenshot.Enter();
|
s_criticalScreenshot.Enter();
|
||||||
int w = rc.right;
|
int w = s_efbSourceRc.right;
|
||||||
int h = rc.bottom;
|
int h = s_efbSourceRc.bottom;
|
||||||
int t = (int)(v_min);
|
int t = (int)(v_min);
|
||||||
u8 *data = (u8 *) malloc(3 * w * h);
|
u8 *data = (u8 *) malloc(3 * w * h);
|
||||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||||
|
@ -1174,7 +1224,7 @@ void Renderer::SwapBuffers()
|
||||||
stats.ResetFrame();
|
stats.ResetFrame();
|
||||||
|
|
||||||
// Render to the framebuffer.
|
// Render to the framebuffer.
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
|
SetFramebuffer(0);
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,8 +88,11 @@ public:
|
||||||
static void FlipImageData(u8 *data, int w, int h);
|
static void FlipImageData(u8 *data, int w, int h);
|
||||||
static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0);
|
static bool SaveRenderTarget(const char *filename, int w, int h, int YOffset = 0);
|
||||||
|
|
||||||
|
static void DecodeFromXFB(u8* xfbInRam, u32 dstWidth, u32 dstHeight, s32 yOffset);
|
||||||
|
static void RenderToXFB(u8* xfbInRam, const TRectangle& sourceRc, u32 dstWidth, u32 dstHeight);
|
||||||
|
|
||||||
// Finish up the current frame, print some stats
|
// Finish up the current frame, print some stats
|
||||||
static void Swap(const TRectangle& rc);
|
static void Swap();
|
||||||
};
|
};
|
||||||
|
|
||||||
void ComputeBackbufferRectangle(TRectangle *rc);
|
void ComputeBackbufferRectangle(TRectangle *rc);
|
||||||
|
|
|
@ -321,6 +321,8 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture);
|
||||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0);
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0);
|
||||||
|
|
||||||
|
GL_REPORT_FBO_ERROR();
|
||||||
|
|
||||||
for (int i = 1; i < 8; ++i)
|
for (int i = 1; i < 8; ++i)
|
||||||
TextureMngr::DisableStage(i);
|
TextureMngr::DisableStage(i);
|
||||||
|
|
||||||
|
@ -349,10 +351,13 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur
|
||||||
|
|
||||||
// reset state
|
// reset state
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||||
|
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
|
||||||
TextureMngr::DisableStage(0);
|
TextureMngr::DisableStage(0);
|
||||||
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
VertexShaderManager::SetViewportChanged();
|
||||||
|
|
||||||
|
Renderer::SetFramebuffer(0);
|
||||||
|
|
||||||
Renderer::RestoreGLState();
|
Renderer::RestoreGLState();
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,55 +25,10 @@
|
||||||
// ----------------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
#include "Globals.h"
|
#include "Globals.h"
|
||||||
#include "GLUtil.h"
|
#include "XFB.h"
|
||||||
#include "MemoryUtil.h"
|
|
||||||
#include "Render.h"
|
#include "Render.h"
|
||||||
#include "TextureMngr.h"
|
|
||||||
#include "VertexShaderManager.h"
|
|
||||||
#include "XFBConvert.h"
|
|
||||||
#include "TextureConverter.h"
|
#include "TextureConverter.h"
|
||||||
|
|
||||||
#define XFB_USE_SHADERS 1
|
|
||||||
|
|
||||||
enum {
|
|
||||||
XFB_BUF_HEIGHT = 574, //480,
|
|
||||||
// TODO: figure out what to do with PAL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
#if XFB_USE_SHADERS
|
|
||||||
|
|
||||||
static GLuint xfb_decoded_texture;
|
|
||||||
static int XFBInitStatus = 0;
|
|
||||||
static struct
|
|
||||||
{
|
|
||||||
u8* pXFB;
|
|
||||||
u32 width;
|
|
||||||
u32 height;
|
|
||||||
s32 yOffset;
|
|
||||||
} tUpdateXFBArgs;
|
|
||||||
|
|
||||||
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset);
|
|
||||||
|
|
||||||
void XFB_Init()
|
|
||||||
{
|
|
||||||
glGenTextures(1, &xfb_decoded_texture);
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_BUF_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
|
|
||||||
XFBInitStatus = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_Shutdown()
|
|
||||||
{
|
|
||||||
glDeleteTextures(1, &xfb_decoded_texture);
|
|
||||||
XFBInitStatus = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int XFB_isInit()
|
|
||||||
{
|
|
||||||
return XFBInitStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
||||||
{
|
{
|
||||||
TRectangle renderSrcRc;
|
TRectangle renderSrcRc;
|
||||||
|
@ -84,181 +39,3 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
||||||
renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom;
|
renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom;
|
||||||
TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), renderSrcRc, xfb_in_ram, dstWd, dstHt);
|
TextureConverter::EncodeToRamYUYV(Renderer::ResolveAndGetRenderTarget(sourceRc), renderSrcRc, xfb_in_ram, dstWd, dstHt);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw the XFB straight to the OpenGL backbuffer.
|
|
||||||
void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset)
|
|
||||||
{
|
|
||||||
TextureConverter::DecodeToTexture(xfb_in_ram, width, height, xfb_decoded_texture);
|
|
||||||
|
|
||||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
|
||||||
Renderer::ResetGLState();
|
|
||||||
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_decoded_texture);
|
|
||||||
|
|
||||||
TRectangle back_rc;
|
|
||||||
ComputeBackbufferRectangle(&back_rc);
|
|
||||||
|
|
||||||
glViewport(back_rc.left, back_rc.top, back_rc.right - back_rc.left, back_rc.bottom - back_rc.top);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
float w = (float)width;
|
|
||||||
float h = (float)height;
|
|
||||||
float yOff = (float)yOffset;
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glTexCoord2f(w, 0 - yOff); glVertex2f(1, -1);
|
|
||||||
glTexCoord2f(w, h - yOff); glVertex2f(1, 1);
|
|
||||||
glTexCoord2f(0, h - yOff); glVertex2f(-1, 1);
|
|
||||||
glTexCoord2f(0, 0 - yOff); glVertex2f(-1,-1);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
TextureMngr::DisableStage(0);
|
|
||||||
|
|
||||||
Renderer::SwapBuffers();
|
|
||||||
|
|
||||||
Renderer::RestoreGLState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_Draw()
|
|
||||||
{
|
|
||||||
XFB_Draw(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset)
|
|
||||||
{
|
|
||||||
tUpdateXFBArgs.pXFB = _pXFB;
|
|
||||||
tUpdateXFBArgs.width = _dwWidth;
|
|
||||||
tUpdateXFBArgs.height = _dwHeight;
|
|
||||||
tUpdateXFBArgs.yOffset = _dwYOffset;
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
static GLuint xfb_texture;
|
|
||||||
static u8 *xfb_buffer = 0;
|
|
||||||
static u8 *efb_buffer = 0;
|
|
||||||
static GLuint s_xfbFrameBuffer = 0;
|
|
||||||
static GLuint s_xfbRenderBuffer = 0;
|
|
||||||
|
|
||||||
void XFB_Init()
|
|
||||||
{
|
|
||||||
// used to render XFB
|
|
||||||
xfb_buffer = new u8[XFB_WIDTH * XFB_BUF_HEIGHT * 4];
|
|
||||||
memset(xfb_buffer, 0, XFB_WIDTH * XFB_BUF_HEIGHT * 4);
|
|
||||||
glGenTextures(1, &xfb_texture);
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, XFB_WIDTH, XFB_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_BYTE, xfb_buffer);
|
|
||||||
|
|
||||||
// used to render EFB
|
|
||||||
glGenFramebuffersEXT(1, &s_xfbFrameBuffer);
|
|
||||||
glGenRenderbuffersEXT(1, &s_xfbRenderBuffer);
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
|
|
||||||
glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_RGBA, nBackbufferWidth, nBackbufferHeight);
|
|
||||||
|
|
||||||
// Ensure efb_buffer is aligned.
|
|
||||||
efb_buffer = (u8 *)AllocateMemoryPages(nBackbufferWidth * nBackbufferHeight * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_Shutdown()
|
|
||||||
{
|
|
||||||
glDeleteFramebuffersEXT(1, &s_xfbFrameBuffer);
|
|
||||||
|
|
||||||
glDeleteTextures(1, &xfb_texture);
|
|
||||||
xfb_texture = 0;
|
|
||||||
delete [] xfb_buffer;
|
|
||||||
xfb_buffer = 0;
|
|
||||||
FreeMemoryPages(efb_buffer, nBackbufferWidth * nBackbufferHeight * 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt)
|
|
||||||
{
|
|
||||||
Renderer::SetRenderMode(Renderer::RM_Normal);
|
|
||||||
Renderer::ResetGLState();
|
|
||||||
|
|
||||||
// Switch to XFB frame buffer.
|
|
||||||
Renderer::SetFramebuffer(s_xfbFrameBuffer);
|
|
||||||
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
|
|
||||||
glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_RENDERBUFFER_EXT, s_xfbRenderBuffer);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
glViewport(nXoff, nYoff, nBackbufferWidth, nBackbufferHeight);
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, Renderer::GetRenderTarget());
|
|
||||||
TextureMngr::EnableTexRECT(0);
|
|
||||||
for (int i = 1; i < 8; ++i)
|
|
||||||
TextureMngr::DisableStage(i);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glTexCoord2f(0, nBackbufferHeight); glVertex2f(-1,-1);
|
|
||||||
glTexCoord2f(0, 0); glVertex2f(-1,1);
|
|
||||||
glTexCoord2f(nBackbufferWidth, 0); glVertex2f(1,1);
|
|
||||||
glTexCoord2f(nBackbufferWidth, nBackbufferHeight); glVertex2f(1,-1);
|
|
||||||
glEnd();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
int width = sourceRc.right - sourceRc.left;
|
|
||||||
int height = sourceRc.bottom - sourceRc.top;
|
|
||||||
glReadPixels(sourceRc.left, sourceRc.top, width, height, GL_RGBA, GL_UNSIGNED_BYTE, efb_buffer);
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
Renderer::SetFramebuffer(0);
|
|
||||||
Renderer::RestoreGLState();
|
|
||||||
VertexShaderManager::SetViewportChanged();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
TextureMngr::DisableStage(0);
|
|
||||||
|
|
||||||
Renderer::RestoreGLState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
ConvertToXFB((u32 *)xfb_in_ram, efb_buffer, dstWd, dstHt);
|
|
||||||
}
|
|
||||||
|
|
||||||
void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset)
|
|
||||||
{
|
|
||||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
|
||||||
|
|
||||||
Renderer::SetRenderMode(Renderer::RM_Normal);
|
|
||||||
|
|
||||||
// render to the real buffer now
|
|
||||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer
|
|
||||||
glViewport(nXoff, nYoff, nBackbufferWidth, nBackbufferHeight);
|
|
||||||
|
|
||||||
Renderer::ResetGLState();
|
|
||||||
|
|
||||||
ConvertFromXFB((u32 *)xfb_buffer, xfb_in_ram, width, height);
|
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, xfb_texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, xfb_buffer);
|
|
||||||
TextureMngr::EnableTexRECT(0);
|
|
||||||
for (int i = 1; i < 8; ++i)
|
|
||||||
TextureMngr::DisableStage(i);
|
|
||||||
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
|
|
||||||
glBegin(GL_QUADS);
|
|
||||||
glTexCoord2f(width, height + yOffset); glVertex2f( 1,-1);
|
|
||||||
glTexCoord2f(width, 0 + yOffset); glVertex2f( 1, 1);
|
|
||||||
glTexCoord2f(0, 0 + yOffset); glVertex2f(-1, 1);
|
|
||||||
glTexCoord2f(0, height + yOffset); glVertex2f(-1,-1);
|
|
||||||
glEnd();
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
|
||||||
TextureMngr::DisableStage(0);
|
|
||||||
|
|
||||||
Renderer::SwapBuffers();
|
|
||||||
|
|
||||||
Renderer::RestoreGLState();
|
|
||||||
GL_REPORT_ERRORD();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
|
@ -18,21 +18,7 @@
|
||||||
#ifndef _XFB_H_
|
#ifndef _XFB_H_
|
||||||
#define _XFB_H_
|
#define _XFB_H_
|
||||||
|
|
||||||
#include "TextureMngr.h"
|
|
||||||
|
|
||||||
void XFB_Init();
|
|
||||||
|
|
||||||
// write the EFB to the XFB
|
// write the EFB to the XFB
|
||||||
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt);
|
void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt);
|
||||||
|
|
||||||
// draw the XFB to the screen
|
|
||||||
void XFB_Draw(u8 *xfb_in_ram, u32 width, u32 height, s32 yOffset);
|
|
||||||
void XFB_Draw();
|
|
||||||
|
|
||||||
void XFB_Shutdown();
|
|
||||||
|
|
||||||
int XFB_isInit();
|
|
||||||
|
|
||||||
void XFB_SetUpdateArgs(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset);
|
|
||||||
|
|
||||||
#endif // _XFB_H_
|
#endif // _XFB_H_
|
||||||
|
|
|
@ -94,6 +94,8 @@ PLUGIN_GLOBALS* globals = NULL;
|
||||||
// Logging
|
// Logging
|
||||||
int GLScissorX, GLScissorY, GLScissorW, GLScissorH;
|
int GLScissorX, GLScissorY, GLScissorW, GLScissorH;
|
||||||
|
|
||||||
|
static bool s_PluginInitialized = false;
|
||||||
|
|
||||||
#if defined(HAVE_WX) && HAVE_WX
|
#if defined(HAVE_WX) && HAVE_WX
|
||||||
void DllDebugger(HWND _hParent, bool Show)
|
void DllDebugger(HWND _hParent, bool Show)
|
||||||
{
|
{
|
||||||
|
@ -359,11 +361,15 @@ void Video_Prepare(void)
|
||||||
GL_REPORT_ERRORD();
|
GL_REPORT_ERRORD();
|
||||||
VertexLoaderManager::Init();
|
VertexLoaderManager::Init();
|
||||||
TextureConverter::Init();
|
TextureConverter::Init();
|
||||||
|
|
||||||
|
s_PluginInitialized = true;
|
||||||
INFO_LOG(VIDEO, "Video plugin initialized.");
|
INFO_LOG(VIDEO, "Video plugin initialized.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown(void)
|
void Shutdown(void)
|
||||||
{
|
{
|
||||||
|
s_PluginInitialized = false;
|
||||||
|
|
||||||
Fifo_Shutdown();
|
Fifo_Shutdown();
|
||||||
PostProcessing::Shutdown();
|
PostProcessing::Shutdown();
|
||||||
TextureConverter::Shutdown();
|
TextureConverter::Shutdown();
|
||||||
|
@ -409,29 +415,46 @@ void Video_AddMessage(const char* pstr, u32 milliseconds)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static volatile struct
|
||||||
|
{
|
||||||
|
u8* pXFB;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
s32 yOffset;
|
||||||
|
} tUpdateXFBArgs;
|
||||||
|
|
||||||
// Run from the CPU thread (from VideoInterface.cpp) for certain homebrew games only
|
// Run from the CPU thread (from VideoInterface.cpp) for certain homebrew games only
|
||||||
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)
|
void Video_UpdateXFB(u8* _pXFB, u32 _dwWidth, u32 _dwHeight, s32 _dwYOffset, bool scheduling)
|
||||||
{
|
{
|
||||||
if (g_Config.bUseXFB && XFB_isInit())
|
if (s_PluginInitialized)
|
||||||
{
|
{
|
||||||
if (scheduling) // from CPU in DC without fifo&CP (some 2D homebrews)
|
if (scheduling) // From CPU in DC mode
|
||||||
{
|
{
|
||||||
XFB_SetUpdateArgs(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
tUpdateXFBArgs.pXFB = _pXFB;
|
||||||
|
tUpdateXFBArgs.width = _dwWidth;
|
||||||
|
tUpdateXFBArgs.height = _dwHeight;
|
||||||
|
tUpdateXFBArgs.yOffset = _dwYOffset;
|
||||||
|
|
||||||
g_XFBUpdateRequested = TRUE;
|
g_XFBUpdateRequested = TRUE;
|
||||||
}
|
}
|
||||||
else
|
else // From CPU in SC mode or graphics thread in DC mode
|
||||||
{
|
{
|
||||||
if (_pXFB) // from CPU in SC mode
|
|
||||||
{
|
|
||||||
XFB_Draw(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
|
||||||
g_VideoInitialize.pCopiedToXFB();
|
|
||||||
}
|
|
||||||
else // from GP in DC without fifo&CP (some 2D homebrews)
|
|
||||||
{
|
|
||||||
XFB_Draw();
|
|
||||||
g_XFBUpdateRequested = FALSE;
|
g_XFBUpdateRequested = FALSE;
|
||||||
|
|
||||||
|
if (g_Config.bUseXFB)
|
||||||
|
{
|
||||||
|
if (!_pXFB)
|
||||||
|
// From graphics thread in DC mode
|
||||||
|
Renderer::DecodeFromXFB(tUpdateXFBArgs.pXFB, tUpdateXFBArgs.width, tUpdateXFBArgs.height, tUpdateXFBArgs.yOffset);
|
||||||
|
else
|
||||||
|
// From CPU in SC mode
|
||||||
|
Renderer::DecodeFromXFB(_pXFB, _dwWidth, _dwHeight, _dwYOffset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Use real XFB source parameters based on VI settings
|
||||||
|
Renderer::Swap();
|
||||||
|
|
||||||
|
g_VideoInitialize.pCopiedToXFB();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue