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;
|
||||
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)
|
||||
{
|
||||
NextXFBRender = LinesPerField;
|
||||
|
@ -1118,7 +1115,6 @@ void Update()
|
|||
video->Video_UpdateXFB(xfbPtr, fbWidth, fbHeight, yOffset, FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check INT_PRERETRACE
|
||||
if (m_InterruptRegister[0].VCT == m_VBeamPos)
|
||||
|
|
|
@ -143,7 +143,6 @@ void Fifo_EnterLoop(const SVideoInitialize &video_initialize)
|
|||
if (g_XFBUpdateRequested)
|
||||
{
|
||||
Video_UpdateXFB(NULL, 0, 0, 0, FALSE);
|
||||
video_initialize.pCopiedToXFB();
|
||||
}
|
||||
|
||||
// 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)
|
||||
{
|
||||
// EFB to XFB
|
||||
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();
|
||||
Renderer::RenderToXFB(pXFB, multirc, dstWidth, dstHeight);
|
||||
}
|
||||
void ClearScreen(const Bypass &bp, const TRectangle &multirc)
|
||||
{
|
||||
|
|
|
@ -49,6 +49,7 @@
|
|||
#include "VertexLoaderManager.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "PostProcessing.h"
|
||||
#include "TextureConverter.h"
|
||||
#include "XFB.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "Timer.h"
|
||||
|
@ -122,6 +123,10 @@ static GLuint s_DepthBuffer = 0;
|
|||
static GLuint s_ResolvedRenderTarget = 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_bHaveFramebufferBlit = false;
|
||||
static bool s_bHaveCoverageMSAA = false;
|
||||
|
@ -319,6 +324,12 @@ bool Renderer::Init()
|
|||
if (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);
|
||||
if (s_uFramebuffer == 0) {
|
||||
ERROR_LOG(VIDEO, "failed to create the renderbufferDoes your video card support OpenGL 2.x?");
|
||||
|
@ -365,6 +376,17 @@ bool Renderer::Init()
|
|||
}
|
||||
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.
|
||||
// First set up the boring multisampled rendertarget.
|
||||
glGenRenderbuffersEXT(1, &s_RenderTarget);
|
||||
|
@ -466,12 +488,7 @@ bool Renderer::Init()
|
|||
if (!InitializeGL())
|
||||
return false;
|
||||
|
||||
XFB_Init();
|
||||
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)
|
||||
|
@ -479,24 +496,28 @@ void Renderer::Shutdown(void)
|
|||
delete s_pfont;
|
||||
s_pfont = 0;
|
||||
|
||||
XFB_Shutdown();
|
||||
|
||||
if (g_cgcontext) {
|
||||
cgDestroyContext(g_cgcontext);
|
||||
g_cgcontext = 0;
|
||||
}
|
||||
if (s_RenderTarget) {
|
||||
glDeleteTextures(1, &s_RenderTarget);
|
||||
s_RenderTarget = 0;
|
||||
}
|
||||
if (s_DepthTarget) {
|
||||
glDeleteRenderbuffersEXT(1, &s_DepthTarget);
|
||||
s_DepthTarget = 0;
|
||||
}
|
||||
if (s_uFramebuffer) {
|
||||
|
||||
// Note: OpenGL delete functions automatically ignore if parameter is 0
|
||||
|
||||
glDeleteFramebuffersEXT(1, &s_uFramebuffer);
|
||||
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
|
||||
if(s_bAVIDumping) {
|
||||
AVIDump::Stop();
|
||||
|
@ -579,6 +600,9 @@ float Renderer::GetTargetScaleY()
|
|||
// Various supporting functions
|
||||
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,
|
||||
targ != 0 ? targ : s_RenderTarget, 0);
|
||||
}
|
||||
|
@ -603,9 +627,14 @@ void Renderer::ResetGLState()
|
|||
glDisable(GL_FRAGMENT_PROGRAM_ARB);
|
||||
}
|
||||
|
||||
void UpdateViewport();
|
||||
|
||||
void Renderer::RestoreGLState()
|
||||
{
|
||||
// Gets us back into a more game-like state.
|
||||
|
||||
UpdateViewport();
|
||||
|
||||
if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE);
|
||||
if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST);
|
||||
if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE);
|
||||
|
@ -849,11 +878,66 @@ void ComputeBackbufferRectangle(TRectangle *rc)
|
|||
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.
|
||||
void Renderer::Swap(const TRectangle& rc)
|
||||
void Renderer::Swap()
|
||||
{
|
||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
||||
DVSTARTPROFILE();
|
||||
|
@ -868,8 +952,8 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
float v_max;
|
||||
if (g_Config.bAutoScale)
|
||||
{
|
||||
u_max = (rc.right - rc.left);
|
||||
v_min = (float)GetTargetHeight() - (rc.bottom - rc.top);
|
||||
u_max = (s_efbSourceRc.right - s_efbSourceRc.left);
|
||||
v_min = (float)GetTargetHeight() - (s_efbSourceRc.bottom - s_efbSourceRc.top);
|
||||
v_max = (float)GetTargetHeight();
|
||||
}
|
||||
else
|
||||
|
@ -879,37 +963,14 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
}
|
||||
|
||||
// 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.
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
// Resolve the multisampled rendertarget into the normal one.
|
||||
// ¯¯¯¯¯¯¯¯¯¯¯¯¯
|
||||
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.
|
||||
// Textured triangles are necessary because of post-processing shaders
|
||||
|
||||
// Disable all other stages
|
||||
for (int i = 1; i < 8; ++i)
|
||||
TextureMngr::DisableStage(i);
|
||||
|
||||
|
@ -920,28 +981,18 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
GL_REPORT_ERRORD();
|
||||
|
||||
// Copy the framebuffer to screen.
|
||||
// TODO: Use glBlitFramebufferEXT.
|
||||
|
||||
// Render to the real buffer now.
|
||||
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);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget);
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_xfbTexture);
|
||||
// Use linear filtering.
|
||||
glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_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
|
||||
// care of disabling it in that case. It returns false in case of no post processing.
|
||||
if (PostProcessing::ApplyShader())
|
||||
|
@ -968,7 +1019,6 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
TextureMngr::DisableStage(0);
|
||||
}
|
||||
|
||||
// Wireframe
|
||||
if (g_Config.bWireFrame)
|
||||
|
@ -985,7 +1035,7 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
|
||||
s_criticalScreenshot.Enter();
|
||||
// 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
|
||||
s_sScreenshotName = "";
|
||||
s_bScreenshot = false;
|
||||
|
@ -1006,8 +1056,8 @@ void Renderer::Swap(const TRectangle& rc)
|
|||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||
|
||||
s_criticalScreenshot.Enter();
|
||||
int w = rc.right;
|
||||
int h = rc.bottom;
|
||||
int w = s_efbSourceRc.right;
|
||||
int h = s_efbSourceRc.bottom;
|
||||
int t = (int)(v_min);
|
||||
u8 *data = (u8 *) malloc(3 * w * h);
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, 1);
|
||||
|
@ -1174,7 +1224,7 @@ void Renderer::SwapBuffers()
|
|||
stats.ResetFrame();
|
||||
|
||||
// Render to the framebuffer.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer);
|
||||
SetFramebuffer(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
|
|
@ -88,8 +88,11 @@ public:
|
|||
static void FlipImageData(u8 *data, int w, int h);
|
||||
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
|
||||
static void Swap(const TRectangle& rc);
|
||||
static void Swap();
|
||||
};
|
||||
|
||||
void ComputeBackbufferRectangle(TRectangle *rc);
|
||||
|
|
|
@ -321,6 +321,8 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur
|
|||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture);
|
||||
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)
|
||||
TextureMngr::DisableStage(i);
|
||||
|
||||
|
@ -349,10 +351,13 @@ void DecodeToTexture(u8* srcAddr, int srcWidth, int srcHeight, GLuint destTextur
|
|||
|
||||
// reset state
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0);
|
||||
TextureMngr::DisableStage(0);
|
||||
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
Renderer::SetFramebuffer(0);
|
||||
|
||||
Renderer::RestoreGLState();
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
|
|
@ -25,55 +25,10 @@
|
|||
// ----------------------------------------------------------------------------------------------------------
|
||||
|
||||
#include "Globals.h"
|
||||
#include "GLUtil.h"
|
||||
#include "MemoryUtil.h"
|
||||
#include "XFB.h"
|
||||
#include "Render.h"
|
||||
#include "TextureMngr.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "XFBConvert.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)
|
||||
{
|
||||
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;
|
||||
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_
|
||||
#define _XFB_H_
|
||||
|
||||
#include "TextureMngr.h"
|
||||
|
||||
void XFB_Init();
|
||||
|
||||
// write the EFB to the XFB
|
||||
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_
|
||||
|
|
|
@ -94,6 +94,8 @@ PLUGIN_GLOBALS* globals = NULL;
|
|||
// Logging
|
||||
int GLScissorX, GLScissorY, GLScissorW, GLScissorH;
|
||||
|
||||
static bool s_PluginInitialized = false;
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
void DllDebugger(HWND _hParent, bool Show)
|
||||
{
|
||||
|
@ -359,11 +361,15 @@ void Video_Prepare(void)
|
|||
GL_REPORT_ERRORD();
|
||||
VertexLoaderManager::Init();
|
||||
TextureConverter::Init();
|
||||
|
||||
s_PluginInitialized = true;
|
||||
INFO_LOG(VIDEO, "Video plugin initialized.");
|
||||
}
|
||||
|
||||
void Shutdown(void)
|
||||
{
|
||||
s_PluginInitialized = false;
|
||||
|
||||
Fifo_Shutdown();
|
||||
PostProcessing::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
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
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