From 75390c55bdcbd708ac03c06c273532a552868390 Mon Sep 17 00:00:00 2001 From: hrydgard Date: Thu, 5 Mar 2009 23:11:13 +0000 Subject: [PATCH] GL plugin: VSync option, some renaming, a little bit of MSAA preparations (not there yet) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2563 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Plugins/Plugin_VideoOGL/Src/BPStructs.cpp | 84 +++--- Source/Plugins/Plugin_VideoOGL/Src/Config.cpp | 2 + Source/Plugins/Plugin_VideoOGL/Src/Config.h | 1 + .../Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp | 24 +- .../Plugin_VideoOGL/Src/GUI/ConfigDlg.h | 2 + .../Plugins/Plugin_VideoOGL/Src/Globals.cpp | 2 +- .../Plugin_VideoOGL/Src/PixelShaderCache.cpp | 4 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 281 +++++++++--------- Source/Plugins/Plugin_VideoOGL/Src/Render.h | 64 +--- .../Plugin_VideoOGL/Src/TextureConverter.cpp | 18 +- .../Plugin_VideoOGL/Src/TextureMngr.cpp | 54 ++-- .../Plugins/Plugin_VideoOGL/Src/TextureMngr.h | 2 +- .../Plugin_VideoOGL/Src/VertexManager.cpp | 2 +- .../Plugin_VideoOGL/Src/VertexShaderCache.cpp | 4 +- Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp | 4 +- Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 6 +- Source/Plugins/Plugin_VideoOGL/Src/main.h | 3 - 17 files changed, 268 insertions(+), 289 deletions(-) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp index f30dd08088..a7ea708065 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/BPStructs.cpp @@ -84,7 +84,7 @@ void BPWritten(int addr, int changes, int newval) glEnable(GL_CULL_FACE); glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); } - else if (glIsEnabled(GL_CULL_FACE) == GL_TRUE) + else glDisable(GL_CULL_FACE); PixelShaderManager::SetGenModeChanged(); } @@ -159,7 +159,7 @@ void BPWritten(int addr, int changes, int newval) case BPMEM_LINEPTWIDTH: { - float fratio = xfregs.rawViewport[0] != 0 ? (float)Renderer::GetTargetWidth() / 640.0f : 1.0f; + float fratio = xfregs.rawViewport[0] != 0 ? ((float)Renderer::GetTargetWidth() / EFB_WIDTH) : 1.0f; if (bpmem.lineptwidth.linesize > 0) glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f); // scale by ratio of widths if (bpmem.lineptwidth.pointsize > 0) @@ -243,13 +243,6 @@ void BPWritten(int addr, int changes, int newval) break; case BPMEM_FOGRANGE: - if (changes) { - // TODO(XK): Fog range format - //glFogi(GL_FOG_START, ... - //glFogi(GL_FOG_END, ... - } - break; - case BPMEM_FOGPARAM0: case BPMEM_FOGBEXPONENT: case BPMEM_FOGBMAGNITUDE: @@ -363,9 +356,9 @@ void BPWritten(int addr, int changes, int newval) case BPMEM_SETGPMETRIC: // Set gp metric? break; - // =============================================================== - // This case writes to bpmem.triggerEFBCopy and may apparently prompt us to update glScissor() // ------------------------ + // EFB copy command. This copies a rectangle from the EFB to either RAM in a texture format or to XFB as YUYV. + // It can also optionally clear the EFB while copying from it. To emulate this, we of course copy first and clear afterwards. case BPMEM_TRIGGER_EFB_COPY: { DVSTARTSUBPROFILE("LoadBPReg:swap"); @@ -395,33 +388,30 @@ void BPWritten(int addr, int changes, int newval) PE_copy.Hex = bpmem.triggerEFBCopy; // -------------------------------------------------------- - // Check if we should copy the picture to XFB or not + // Check to where we should copy the image data from the EFB. // -------------------------- if (PE_copy.copy_to_xfb == 0) { // EFB to texture // for some reason it sets bpmem.zcontrol.pixel_format to PIXELFMT_Z24 every time a zbuffer format is given as a dest to GXSetTexCopyDst - if (g_Config.bEFBCopyDisable) + if (!g_Config.bEFBCopyDisable) { - /* We already have this in Render.cpp that we call when (PE_copy.clear) is true. But we need a separate one - here because UpdateViewport() is not run when this option is set? */ - glViewport(rc.left, rc.bottom, rc.right,rc.top); - glScissor(rc.left, rc.bottom, rc.right,rc.top); - // Logging - GLScissorX = rc.left; - GLScissorY = rc.bottom; - GLScissorW = rc.right; - GLScissorH = rc.top; - } - else if (g_Config.bCopyEFBToRAM) - { - TextureConverter::EncodeToRam(bpmem.copyTexDest<<5, bpmem.zcontrol.pixel_format==PIXELFMT_Z24, PE_copy.intensity_fmt>0, - (PE_copy.target_pixel_format/2)+((PE_copy.target_pixel_format&1)*8), PE_copy.half_scale>0, rc); - } - else - { - TextureMngr::CopyRenderTargetToTexture(bpmem.copyTexDest<<5, bpmem.zcontrol.pixel_format==PIXELFMT_Z24, PE_copy.intensity_fmt>0, - (PE_copy.target_pixel_format/2)+((PE_copy.target_pixel_format&1)*8), PE_copy.half_scale>0, &rc); + if (g_Config.bCopyEFBToRAM) + { + TextureConverter::EncodeToRam(bpmem.copyTexDest<<5, + bpmem.zcontrol.pixel_format==PIXELFMT_Z24, + PE_copy.intensity_fmt > 0, + (PE_copy.target_pixel_format/2) + ((PE_copy.target_pixel_format&1) * 8), // ?? + PE_copy.half_scale>0, rc); + } + else + { + TextureMngr::CopyRenderTargetToTexture(bpmem.copyTexDest<<5, + bpmem.zcontrol.pixel_format==PIXELFMT_Z24, + PE_copy.intensity_fmt > 0, + (PE_copy.target_pixel_format/2) + ((PE_copy.target_pixel_format & 1)*8), // ?? + PE_copy.half_scale > 0, rc); + } } } else @@ -446,6 +436,8 @@ void BPWritten(int addr, int changes, int newval) } 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(); @@ -459,16 +451,12 @@ void BPWritten(int addr, int changes, int newval) // Clear color Renderer::SetRenderMode(Renderer::RM_Normal); // Clear Z-Buffer target - u32 nRestoreZBufferTarget = Renderer::GetZBufferTarget(); + bool bRestoreZBufferTarget = Renderer::GetFakeZTarget() != 0; - // ----------------------------------------------------------------- // Update the view port for clearing the picture - // ----------------------- glViewport(0, 0, Renderer::GetTargetWidth(), Renderer::GetTargetHeight()); // Always set the scissor in case it was set by the game and has not been reset - /* We will also do this at the end of this section, in SetScissorRect(), but that is for creating the new picture - this is for clearing the picture */ glScissor(multirc.left, (Renderer::GetTargetHeight() - multirc.bottom), (multirc.right - multirc.left), (multirc.bottom - multirc.top)); // --------------------------- @@ -484,23 +472,23 @@ void BPWritten(int addr, int changes, int newval) { u32 clearColor = (bpmem.clearcolorAR << 16) | bpmem.clearcolorGB; glClearColor(((clearColor>>16) & 0xff)*(1/255.0f), - ((clearColor>>8 ) & 0xff)*(1/255.0f), - ((clearColor>>0 ) & 0xff)*(1/255.0f), - ((clearColor>>24) & 0xff)*(1/255.0f)); + ((clearColor>>8 ) & 0xff)*(1/255.0f), + ((clearColor>>0 ) & 0xff)*(1/255.0f), + ((clearColor>>24) & 0xff)*(1/255.0f)); bits |= GL_COLOR_BUFFER_BIT; } if (bpmem.zmode.updateenable) { - glClearDepth((float)(bpmem.clearZValue&0xFFFFFF) / float(0xFFFFFF)); + glClearDepth((float)(bpmem.clearZValue & 0xFFFFFF) / float(0xFFFFFF)); bits |= GL_DEPTH_BUFFER_BIT; } - if (nRestoreZBufferTarget ) - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); // don't clear ztarget here + if (bRestoreZBufferTarget) + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); // don't clear ztarget here glClear(bits); } // Have to clear the target zbuffer - if (bpmem.zmode.updateenable && nRestoreZBufferTarget) + if (bpmem.zmode.updateenable && bRestoreZBufferTarget) { glDrawBuffer(GL_COLOR_ATTACHMENT1_EXT); GL_REPORT_ERRORD(); @@ -515,16 +503,14 @@ void BPWritten(int addr, int changes, int newval) GL_REPORT_ERRORD(); } - if (nRestoreZBufferTarget) + if (bRestoreZBufferTarget) { // restore target GLenum s_drawbuffers[2] = {GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT}; glDrawBuffers(2, s_drawbuffers); } - - Renderer::SetScissorRect(); // reset the scissor rectangle } - // ------------------------------ + Renderer::RestoreGLState(); } break; // ================================== @@ -643,7 +629,7 @@ void BPWritten(int addr, int changes, int newval) break; default: - switch(addr&0xF0) { + switch (addr&0xF0) { case 0x10: // tevindirect 0-15 if (changes) { VertexManager::Flush(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp index a8d556639d..34ea0722ef 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.cpp @@ -41,6 +41,7 @@ void Config::Load() strncpy(iFSResolution, temp.c_str(), 16); iniFile.Get("Hardware", "Fullscreen", &bFullscreen, 0); // Hardware + iniFile.Get("Hardware", "VSync", &bVSync, 0); // Hardware iniFile.Get("Hardware", "RenderToMainframe", &renderToMainframe, false); iniFile.Get("Settings", "StretchToFit", &bNativeResolution, true); iniFile.Get("Settings", "KeepAR_4_3", &bKeepAR43, false); @@ -93,6 +94,7 @@ void Config::Save() iniFile.Set("Hardware", "WindowedRes", iWindowedRes); iniFile.Set("Hardware", "FullscreenRes", iFSResolution); iniFile.Set("Hardware", "Fullscreen", bFullscreen); + iniFile.Set("Hardware", "VSync", bVSync); iniFile.Set("Hardware", "RenderToMainframe", renderToMainframe); iniFile.Set("Settings", "StretchToFit", bNativeResolution); iniFile.Set("Settings", "KeepAR_4_3", bKeepAR43); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Config.h b/Source/Plugins/Plugin_VideoOGL/Src/Config.h index 0ad4801bf7..11285b8d05 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Config.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Config.h @@ -38,6 +38,7 @@ struct Config bool bFullscreen; bool bHideCursor; bool renderToMainframe; + bool bVSync; // Resolution control char iFSResolution[16]; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp index 1094938cdd..da12415570 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.cpp @@ -27,6 +27,7 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_BUTTON(ID_CLOSE, ConfigDialog::CloseClick) EVT_BUTTON(ID_ABOUTOGL, ConfigDialog::AboutClick) EVT_CHECKBOX(ID_FULLSCREEN, ConfigDialog::GeneralSettingsChanged) + EVT_CHECKBOX(ID_VSYNC, ConfigDialog::GeneralSettingsChanged) EVT_CHECKBOX(ID_RENDERTOMAINWINDOW, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_FULLSCREENCB, ConfigDialog::GeneralSettingsChanged) EVT_COMBOBOX(ID_WINDOWRESOLUTIONCB, ConfigDialog::GeneralSettingsChanged) @@ -161,6 +162,8 @@ void ConfigDialog::CreateGUIControls() sbBasic = new wxStaticBoxSizer(wxVERTICAL, m_PageGeneral, wxT("Basic Settings")); m_Fullscreen = new wxCheckBox(m_PageGeneral, ID_FULLSCREEN, wxT("Fullscreen"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_Fullscreen->SetValue(g_Config.bFullscreen); + m_VSync = new wxCheckBox(m_PageGeneral, ID_VSYNC, wxT("VSync (req. restart)"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); + m_VSync->SetValue(g_Config.bVSync); m_RenderToMainWindow = new wxCheckBox(m_PageGeneral, ID_RENDERTOMAINWINDOW, wxT("Render to main window"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); m_RenderToMainWindow->SetValue(g_Config.renderToMainframe); m_NativeResolution = new wxCheckBox(m_PageGeneral, ID_NATIVERESOLUTION, wxT("Native resolution"), wxDefaultPosition, wxDefaultSize, 0, wxDefaultValidator); @@ -239,16 +242,17 @@ void ConfigDialog::CreateGUIControls() sGeneral = new wxBoxSizer(wxVERTICAL); sBasic = new wxGridBagSizer(0, 0); sBasic->Add(m_Fullscreen, wxGBPosition(0, 0), wxGBSpan(1, 3), wxALL, 5); - sBasic->Add(m_RenderToMainWindow, wxGBPosition(1, 0), wxGBSpan(1, 3), wxALL, 5); - sBasic->Add(m_AutoScale, wxGBPosition(2, 0), wxGBSpan(1, 3), wxALL, 5); - sBasic->Add(m_NativeResolution, wxGBPosition(3, 0), wxGBSpan(1, 3), wxALL, 5); - sBasic->Add(m_UseXFB, wxGBPosition(4, 0), wxGBSpan(1, 3), wxALL, 5); - sBasic->Add(m_KeepAR43, wxGBPosition(5, 0), wxGBSpan(1, 1), wxALL, 5); - sBasic->Add(m_KeepAR169, wxGBPosition(5, 1), wxGBSpan(1, 1), wxALL, 5); - sBasic->Add(m_Crop, wxGBPosition(5, 2), wxGBSpan(1, 1), wxALL, 5); + sBasic->Add(m_VSync, wxGBPosition(1, 0), wxGBSpan(1, 3), wxALL, 5); + sBasic->Add(m_RenderToMainWindow, wxGBPosition(2, 0), wxGBSpan(1, 3), wxALL, 5); + sBasic->Add(m_AutoScale, wxGBPosition(3, 0), wxGBSpan(1, 3), wxALL, 5); + sBasic->Add(m_NativeResolution, wxGBPosition(4, 0), wxGBSpan(1, 3), wxALL, 5); + sBasic->Add(m_UseXFB, wxGBPosition(5, 0), wxGBSpan(1, 3), wxALL, 5); + sBasic->Add(m_KeepAR43, wxGBPosition(6, 0), wxGBSpan(1, 1), wxALL, 5); + sBasic->Add(m_KeepAR169, wxGBPosition(6, 1), wxGBSpan(1, 1), wxALL, 5); + sBasic->Add(m_Crop, wxGBPosition(6, 2), wxGBSpan(1, 1), wxALL, 5); // Because of the ifdef here we need this variable for the row number - int Row = 6; + int Row = 7; #ifndef _WIN32 sBasic->Add(m_HideCursor, wxGBPosition(Row++, 0), wxGBSpan(1, 3), wxALL, 5); #endif @@ -430,7 +434,9 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event) case ID_NATIVERESOLUTION: g_Config.bNativeResolution = m_NativeResolution->IsChecked(); break; - + case ID_VSYNC: + g_Config.bVSync = m_VSync->IsChecked(); + break; case ID_USEXFB: g_Config.bUseXFB = m_UseXFB->IsChecked(); break; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h index 882338059b..7edffb4b6b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/GUI/ConfigDlg.h @@ -75,6 +75,7 @@ class ConfigDialog : public wxDialog wxPanel *m_PageGeneral; wxPanel *m_PageAdvanced; wxCheckBox *m_Fullscreen; + wxCheckBox *m_VSync; wxCheckBox *m_RenderToMainWindow; wxCheckBox *m_NativeResolution; wxCheckBox *m_KeepAR43, *m_KeepAR169, *m_Crop; @@ -125,6 +126,7 @@ class ConfigDialog : public wxDialog ID_PAGEADVANCED, ID_FULLSCREEN, + ID_VSYNC, ID_RENDERTOMAINWINDOW, ID_NATIVERESOLUTION, ID_KEEPAR_4_3, ID_KEEPAR_16_9, ID_CROP, diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Globals.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Globals.cpp index 43e82bc6f3..639ad284c0 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Globals.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Globals.cpp @@ -63,7 +63,7 @@ bool LocalLogFile = true; #if LOGLEVEL > 0 void __Log(const char *fmt, ...) { - int len = strlen(fmt); + size_t len = strlen(fmt); if (!len) return; char* Msg = (char*)alloca(len + 512); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp index e174bcaa09..e065e5c12b 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/PixelShaderCache.cpp @@ -109,7 +109,7 @@ FRAGMENTSHADER* PixelShaderCache::GetShader() { DVSTARTPROFILE(); PIXELSHADERUID uid; - u32 zbufrender = (Renderer::GetZBufferTarget() && bpmem.zmode.updateenable) ? 1 : 0; + u32 zbufrender = (Renderer::GetFakeZTarget() && bpmem.zmode.updateenable) ? 1 : 0; u32 zBufRenderToCol0 = Renderer::GetRenderMode() != Renderer::RM_Normal; GetPixelShaderId(uid, PixelShaderManager::GetTextureMask(), zbufrender, zBufRenderToCol0); @@ -127,7 +127,7 @@ FRAGMENTSHADER* PixelShaderCache::GetShader() PSCacheEntry& newentry = pshaders[uid]; const char *code = GeneratePixelShader(PixelShaderManager::GetTextureMask(), - Renderer::GetZBufferTarget() != 0, + Renderer::GetFakeZTarget() != 0, Renderer::GetRenderMode() != Renderer::RM_Normal); #if defined(_DEBUG) || defined(DEBUGFAST) diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 1381060246..5d14460a7e 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -15,8 +15,8 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ - #include "Globals.h" + #include #include @@ -63,7 +63,6 @@ #else #endif - CGcontext g_cgcontext; CGprofile g_cgvProf; CGprofile g_cgfProf; @@ -72,15 +71,38 @@ RasterFont* s_pfont = NULL; static bool s_bFullscreen = false; -static int nZBufferRender = 0; // if > 0, then use zbuffer render, and count down. +static int nZBufferRender = 0; // if > 0, then use zbuffer render, and count down. + +static bool MSAA = false; + +// Normal Mode +// s_RenderTarget is a texture_rect +// s_DepthTarget is a Z renderbuffer +// s_FakeZTarget is a texture_rect + +// MSAA mode +// s_uFramebuffer is a FBO +// s_RenderTarget is a MSAA renderbuffer +// s_FakeZBufferTarget is a MSAA renderbuffer +// s_DepthTarget is a real MSAA z/stencilbuffer +// +// s_ResolvedFramebuffer is a FBO +// s_ResolvedColorTarget is a texture +// s_ResolvedFakeZTarget is a texture +// s_ResolvedDepthTarget is a Z renderbuffer // A framebuffer is a set of render targets: a color and a z buffer. They can be either RenderBuffers or Textures. static GLuint s_uFramebuffer = 0; -// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn'.t +// The size of these should be a (not necessarily even) multiple of the EFB size, 640x528, but isn't. +// These are all texture IDs. Bind them as rect arb textures. static GLuint s_RenderTarget = 0; -static GLuint s_DepthTarget = 0; -static GLuint s_ZBufferTarget = 0; +static GLuint s_FakeZTarget = 0; +static GLuint s_DepthTarget = 0; + +static GLuint s_ResolvedRenderTarget = 0; +static GLuint s_ResolvedFakeZTarget = 0; +static GLuint s_ResolvedDepthTarget = 0; static bool s_bATIDrawBuffers = false; static bool s_bHaveStencilBuffer = false; @@ -96,13 +118,16 @@ bool g_bBlendSeparate = false; int frameCount; static int s_fps = 0; -// These STAY CONSTANT during execution, no matter how much you resize the game window. +// These STAY CONSTANT during execution, no matter how much you resize the game window.\ +// TODO: Add functionality to reinit all the render targets when the window is resized. static int s_targetwidth; // Size of render buffer FBO. static int s_targetheight; static u32 s_blendMode; -void HandleCgError(CGcontext ctx, CGerror err, void *appdata); +extern void HandleCgError(CGcontext ctx, CGerror err, void *appdata); + +namespace { static const GLenum glSrcFactors[8] = { @@ -121,6 +146,24 @@ static const GLenum glDestFactors[8] = { GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_DST_ALPHA, GL_ONE_MINUS_DST_ALPHA }; +void SetDefaultRectTexParams() +{ + // Set some standard texture filter modes. + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + if (glGetError() != GL_NO_ERROR) { + GLenum err; + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); + GL_REPORT_ERROR(); + } + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); +} + +} // namespace + + bool Renderer::Init() { bool bSuccess = true; @@ -132,6 +175,7 @@ bool Renderer::Init() cgGetError(); cgSetErrorHandler(HandleCgError, NULL); + // Look for required extensions. const char *ptoken = (const char*)glGetString(GL_EXTENSIONS); if (!ptoken) @@ -143,9 +187,10 @@ bool Renderer::Init() INFO_LOG(VIDEO, ptoken); // write to the log file INFO_LOG(VIDEO, "\n"); - if (strstr(ptoken, "GL_EXT_blend_func_separate") != NULL && strstr(ptoken, - "GL_EXT_blend_equation_separate") != NULL) + if (strstr(ptoken, "GL_EXT_blend_func_separate") != NULL && + strstr(ptoken, "GL_EXT_blend_equation_separate") != NULL) g_bBlendSeparate = true; + // Checks if it ONLY has the ATI_draw_buffers extension, some have both if (GLEW_ATI_draw_buffers && !GLEW_ARB_draw_buffers) s_bATIDrawBuffers = true; @@ -176,20 +221,17 @@ bool Renderer::Init() if (!bSuccess) return false; + // Handle VSync on/off #ifdef _WIN32 if (WGLEW_EXT_swap_control) - wglSwapIntervalEXT(0); + wglSwapIntervalEXT(g_Config.bVSync ? 1 : 0); else ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)\nDoes your video card support OpenGL 2.x?"); #elif defined(HAVE_X11) && HAVE_X11 if (glXSwapIntervalSGI) - glXSwapIntervalSGI(0); + glXSwapIntervalSGI(g_Config.bVSync ? 1 : 0); else ERROR_LOG(VIDEO, "no support for SwapInterval (framerate clamped to monitor refresh rate)\n"); -#else - - //TODO - #endif // check the max texture width and height @@ -229,83 +271,60 @@ bool Renderer::Init() if (s_targetheight < EFB_HEIGHT) s_targetheight = EFB_HEIGHT; - // Create the framebuffer target texture - glGenTextures(1, (GLuint *)&s_RenderTarget); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); + if (!MSAA) { + // Create the framebuffer target texture + glGenTextures(1, (GLuint *)&s_RenderTarget); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget); + // Create our main color render target as a texture rectangle of the desired size. + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + SetDefaultRectTexParams(); - // Setup the texture params - // initialize to default - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (glGetError() != GL_NO_ERROR) { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); - GL_REPORT_ERROR(); - } - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + GL_REPORT_ERROR(); - GL_REPORT_ERROR(); + GLint nMaxMRT = 0; + glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &nMaxMRT); + if (nMaxMRT > 1) + { + // There's MRT support. Create a color texture image to use as secondary render target. + // We use MRT to render Z into this one, for various purposes (mostly copy Z to texture). + glGenTextures(1, (GLuint *)&s_FakeZTarget); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget); + glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + SetDefaultRectTexParams(); + } - GLint nMaxMRT = 0; - glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS_EXT, &nMaxMRT); - if (nMaxMRT > 1) - { - // Create zbuffer target. - glGenTextures(1, (GLuint *)&s_ZBufferTarget); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget); - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, s_targetwidth, s_targetheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - if (glGetError() != GL_NO_ERROR) { - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP); - GL_REPORT_ERROR(); - } - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } + // Create the real depth/stencil buffer. It's a renderbuffer, not a texture. + glGenRenderbuffersEXT(1, &s_DepthTarget); + glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget); + glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, s_targetwidth, s_targetheight); + GL_REPORT_ERROR(); + + // Our framebuffer object is still bound here. Attach the two render targets, color and Z/stencil, to the framebuffer object. + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0); + glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget); + GL_REPORT_ERROR(); - // create the depth buffer - glGenRenderbuffersEXT(1, &s_DepthTarget); - glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, s_DepthTarget); - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH24_STENCIL8_EXT, s_targetwidth, s_targetheight); - if (glGetError() != GL_NO_ERROR) - { - glRenderbufferStorageEXT(GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, s_targetwidth, s_targetheight); - s_bHaveStencilBuffer = false; - } - else - { - s_bHaveStencilBuffer = true; + if (s_FakeZTarget != 0) { + // We do a simple test to make sure that MRT works. I don't really know why - this is probably a workaround for + // some terribly buggy ancient driver. + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, 0); + bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT; + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); + if (bFailed) { + glDeleteTextures(1, (GLuint *)&s_FakeZTarget); + s_FakeZTarget = 0; + } + } + + if (s_FakeZTarget == 0) + ERROR_LOG(VIDEO, "Disabling ztarget MRT feature (max MRT = %d)\n", nMaxMRT); + } else { + // TODO MSAA rendertarget init } + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - GL_REPORT_ERROR(); - // Select our render and depth targets as render targets. - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, s_RenderTarget, 0); - glFramebufferRenderbufferEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, s_DepthTarget); - - GL_REPORT_ERROR(); - - if (s_ZBufferTarget != 0) { - // test to make sure it works - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0); - bool bFailed = glGetError() != GL_NO_ERROR || glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) != GL_FRAMEBUFFER_COMPLETE_EXT; - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - - if (bFailed) { - glDeleteTextures(1, (GLuint *)&s_ZBufferTarget); - s_ZBufferTarget = 0; - } - } - - if (s_ZBufferTarget == 0) - ERROR_LOG(VIDEO, "Disabling ztarget MRT feature (max MRT = %d)\n", nMaxMRT); - - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); - nZBufferRender = 0; + nZBufferRender = 0; // Initialize the Z render shutoff countdown. We only render Z if it's desired, to save GPU power. GL_REPORT_ERROR(); if (err != GL_NO_ERROR) @@ -331,9 +350,9 @@ bool Renderer::Init() INFO_LOG(VIDEO, "Max buffer sizes: %d %d\n", cgGetProgramBufferMaxSize(g_cgvProf), cgGetProgramBufferMaxSize(g_cgfProf)); int nenvvertparams, nenvfragparams, naddrregisters[2]; - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, (GLint *)&nenvvertparams); - glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, (GLint *)&nenvfragparams); - glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, (GLint *)&naddrregisters[0]); + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, (GLint *)&nenvvertparams); + glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ENV_PARAMETERS_ARB, (GLint *)&nenvfragparams); + glGetProgramivARB(GL_VERTEX_PROGRAM_ARB, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, (GLint *)&naddrregisters[0]); glGetProgramivARB(GL_FRAGMENT_PROGRAM_ARB, GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB, (GLint *)&naddrregisters[1]); DEBUG_LOG(VIDEO, "Max program env parameters: vert=%d, frag=%d\n", nenvvertparams, nenvfragparams); DEBUG_LOG(VIDEO, "Max program address register parameters: vert=%d, frag=%d\n", naddrregisters[0], naddrregisters[1]); @@ -344,14 +363,8 @@ bool Renderer::Init() #ifndef _DEBUG cgGLSetDebugMode(GL_FALSE); #endif - - if (cgGetError() != CG_NO_ERROR) { - ERROR_LOG(VIDEO, "cg error\n"); - return false; - } s_RenderMode = Renderer::RM_Normal; - if (!InitializeGL()) return false; @@ -406,13 +419,13 @@ bool Renderer::InitializeGL() glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // perspective correct interpolation of colors and tex coords - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE); // Polygon smoothing is ancient junk that doesn't work anymore. MSAA is modern AA. glDisable(GL_STENCIL_TEST); glEnable(GL_SCISSOR_TEST); - // Do we really need to set this initial glScissor() value? Wont it be called all the time while the game is running? - //glScissor(0, 0, (int)OpenGL_GetWidth(), (int)OpenGL_GetHeight()); + + glScissor(0, 0, GetTargetWidth(), GetTargetHeight()); glBlendColorEXT(0, 0, 0, 0.5f); glClearDepth(1.0f); @@ -438,12 +451,12 @@ bool Renderer::InitializeGL() // ------------------------ int Renderer::GetTargetWidth() { - return (g_Config.bNativeResolution ? EFB_WIDTH : s_targetwidth); + return g_Config.bNativeResolution ? EFB_WIDTH : s_targetwidth; } int Renderer::GetTargetHeight() { - return (g_Config.bNativeResolution ? EFB_HEIGHT : s_targetheight); + return g_Config.bNativeResolution ? EFB_HEIGHT : s_targetheight; } float Renderer::GetTargetScaleX() @@ -476,13 +489,21 @@ void Renderer::SetFramebuffer(GLuint fb) fb != 0 ? fb : s_uFramebuffer); } -GLuint Renderer::GetRenderTarget() +GLuint Renderer::ResolveAndGetRenderTarget(const TRectangle &source_rect) { return s_RenderTarget; } -GLuint Renderer::GetZBufferTarget() + +GLuint Renderer::ResolveAndGetFakeZTarget(const TRectangle &source_rect) { - return nZBufferRender > 0 ? s_ZBufferTarget : 0; + // This logic should be moved elsewhere. + return s_FakeZTarget; +} + +GLuint Renderer::GetFakeZTarget() +{ + // This logic should be moved elsewhere. + return nZBufferRender > 0 ? s_FakeZTarget : 0; } void Renderer::ResetGLState() @@ -503,16 +524,17 @@ void Renderer::ResetGLState() void Renderer::RestoreGLState() { // Gets us back into a more game-like state. - glEnable(GL_SCISSOR_TEST); - if (bpmem.genMode.cullmode > 0) glEnable(GL_CULL_FACE); - if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); - if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); + if (bpmem.zmode.testenable) glEnable(GL_DEPTH_TEST); + if (bpmem.zmode.updateenable) glDepthMask(GL_TRUE); - glEnable(GL_VERTEX_PROGRAM_ARB); - glEnable(GL_FRAGMENT_PROGRAM_ARB); + glEnable(GL_SCISSOR_TEST); + SetScissorRect(); SetColorMask(); SetBlendMode(true); + + glEnable(GL_VERTEX_PROGRAM_ARB); + glEnable(GL_FRAGMENT_PROGRAM_ARB); } void Renderer::SetColorMask() @@ -546,7 +568,6 @@ void Renderer::SetBlendMode(bool forceUpdate) if (bpmem.blendmode.blendenable) { newval |= 1; - if (bpmem.blendmode.subtract) { newval |= 0x0048; // src 1 dst 1 } else { @@ -560,7 +581,7 @@ void Renderer::SetBlendMode(bool forceUpdate) u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode; if (changes & 1) { - newval & 1 ? glEnable(GL_BLEND) : glDisable(GL_BLEND); + (newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND); } bool dstAlphaEnable = g_bBlendSeparate && newval & 2; @@ -635,8 +656,8 @@ bool Renderer::SetScissorRect() glScissor( (int)rc_left, // x = 0 for example Renderer::GetTargetHeight() - (int)(rc_bottom), // y = 0 for example - (int)(rc_right-rc_left), // width = 640 for example - (int)(rc_bottom-rc_top) // height = 480 for example + (int)(rc_right - rc_left), // width = 640 for example + (int)(rc_bottom - rc_top) // height = 480 for example ); return true; } @@ -656,16 +677,18 @@ bool Renderer::HaveStencilBuffer() void Renderer::SetZBufferRender() { - nZBufferRender = 10; // give it 10 frames + nZBufferRender = 10; // The game asked for Z. Give it 10 frames, then turn it off for speed. GLenum s_drawbuffers[2] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT }; glDrawBuffers(2, s_drawbuffers); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, 0); + glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, 0); _assert_(glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT) == GL_FRAMEBUFFER_COMPLETE_EXT); } + +// Does this function even work correctly??? void Renderer::FlushZBufferAlphaToTarget() { ResetGLState(); @@ -673,12 +696,11 @@ void Renderer::FlushZBufferAlphaToTarget() SetRenderTarget(0); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE); - glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // texture map s_RenderTargets[s_curtarget] onto the main buffer glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget); + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget); TextureMngr::EnableTexRECT(0); // disable all other stages for (int i = 1; i < 8; ++i) @@ -691,7 +713,6 @@ void Renderer::FlushZBufferAlphaToTarget() // TODO: This code should not have to bother with stretchtofit checking - // all necessary scale initialization should be done elsewhere. - // TODO: Investigate BlitFramebufferEXT. if (g_Config.bNativeResolution) { //TODO: Do Correctly in a bit @@ -748,7 +769,6 @@ void Renderer::SetRenderMode(RenderMode mode) else if (s_RenderMode == RM_Normal) { // setup buffers _assert_(GetZBufferTarget() && bpmem.zmode.updateenable); - if (mode == RM_ZBufferAlpha) { glEnable(GL_STENCIL_TEST); glClearStencil(0); @@ -771,7 +791,7 @@ void Renderer::SetRenderMode(RenderMode mode) FlushZBufferAlphaToTarget(); glDisable(GL_STENCIL_TEST); - SetRenderTarget(s_ZBufferTarget); + SetRenderTarget(s_FakeZTarget); glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); GL_REPORT_ERRORD(); } @@ -797,11 +817,6 @@ Renderer::RenderMode Renderer::GetRenderMode() void ComputeBackbufferRectangle(TRectangle *rc) { - // ----------------------------------------------------------------------- - // GLViewPort variables - // ------------------ - // Work with float values for the XFB supplement and aspect ratio functions. These are default - // values that are used if the XFB supplement and the keep aspect ratio function are unused. float FloatGLWidth = (float)OpenGL_GetBackbufferWidth(); float FloatGLHeight = (float)OpenGL_GetBackbufferHeight(); float FloatXOffset = 0; @@ -833,7 +848,7 @@ void ComputeBackbufferRectangle(TRectangle *rc) } // ----------------------------------------------------------------------- - /* Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10. */ + // Crop the picture from 4:3 to 5:4 or from 16:9 to 16:10. // Output: FloatGLWidth, FloatGLHeight, FloatXOffset, FloatYOffset // ------------------ if ((g_Config.bKeepAR43 || g_Config.bKeepAR169) && g_Config.bCrop) @@ -858,7 +873,7 @@ void ComputeBackbufferRectangle(TRectangle *rc) //Console::Print("Crop Ratio:%1.2f IncreasedHeight:%3.0f YOffset:%3.0f\n", Ratio, IncreasedHeight, FloatYOffset); } - // Because there is no round() function we use round(float) = floor(float + 0.5) instead + // round(float) = floor(float + 0.5) int XOffset = floor(FloatXOffset + 0.5); int YOffset = floor(FloatYOffset + 0.5); rc->left = XOffset; @@ -885,12 +900,8 @@ void Renderer::Swap(const TRectangle& rc) // glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, s_uFramebuffer); // render to the real buffer now - glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the backbuffer + glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer - // ----------------------------------------------------------------------- - // Show the finished picture - // -------------------- - // Reset GL state ResetGLState(); // Texture map s_RenderTargets[s_curtarget] onto the main buffer @@ -901,7 +912,7 @@ void Renderer::Swap(const TRectangle& rc) glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR); TextureMngr::EnableTexRECT(0); - // Disable all other stages + // Disable all other stages. for (int i = 1; i < 8; ++i) TextureMngr::DisableStage(i); @@ -973,7 +984,7 @@ void Renderer::Swap(const TRectangle& rc) // For testing zbuffer targets. // Renderer::SetZBufferRender(); - // SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_ZBufferTarget, GetTargetWidth(), GetTargetHeight()); + // SaveTexture("tex.tga", GL_TEXTURE_RECTANGLE_ARB, s_FakeZTarget, GetTargetWidth(), GetTargetHeight()); } //////////////////////////////////////////////// diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.h b/Source/Plugins/Plugin_VideoOGL/Src/Render.h index f9efacc1fa..b1ac48c8d2 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.h @@ -15,54 +15,14 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ -// How the non-true-XFB mode COULD work: -// -// The game renders to the EFB: -// -// ----------------------+ -// | | -// | | -// | | -// | | -// | | -// | | efb_height -// | | -// | | -// | - - - - - - - - - - | -// | | -// +---------------------+ -// efb_width -// -// At XFB blit time, the top 640-xxx X XXX part of the above buffer (size dotted below), -// should be stretch blitted into the inner rectangle of the window: -// +-----------------------------------------+ -// | | | | -// | | . | | -// | | | | -// | | . | | -// | | | | -// | | . | | OpenGL_Height() -// | | | | -// | | . | | -// | | - - - - - - - - - - | | -// | | \ | | -// +-------+---------------------------------+ -// OpenGL_Width() -// -// -// efb_width and efb_height can even be adjusted so that the last blit will result -// in a 1:1 rather than a stretch. That would require creating a bigger efb from the -// start though. -// -// The above is not how it works today. -/* -int win_w = OpenGL_Width(); -int win_h = OpenGL_Height(); +// GC graphics pipeline -int blit_w_640 = last_xfb_specified_width; -int blit_h_640 = last_xfb_specified_height; -*/ +// 3d commands are issued through the fifo. The gpu draws to the 2MB EFB. +// The efb can be copied back into ram in two forms: as textures or as XFB. +// The XFB is the region in RAM that the VI chip scans out to the television. +// So, after all rendering to EFB is done, the image is copied into one of two XFBs in RAM. +// Next frame, that one is scanned out and the other one gets the copy. = double buffering. #ifndef GCOGL_RENDER #define GCOGL_RENDER @@ -116,7 +76,7 @@ public: static int GetTargetWidth(); static int GetTargetHeight(); - // Multiply any 0-640 / 0-480 coordinates by these when rendering. + // Multiply any 2D EFB coordinates by these when rendering. static float GetTargetScaleX(); static float GetTargetScaleY(); @@ -125,8 +85,14 @@ public: static void SetRenderTarget(GLuint targ); // if targ is 0, sets to original render target static void SetDepthTarget(GLuint targ); - static GLuint GetRenderTarget(); - static GLuint GetZBufferTarget(); + // If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. + // Thus, this call may be expensive. Don't repeat it unnecessarily. + // If not in MSAA mode, will just return the render target texture ID. + static GLuint ResolveAndGetRenderTarget(const TRectangle &rect); + + // Same as above but for the FakeZ Target. + static GLuint ResolveAndGetFakeZTarget(const TRectangle &rect); + static GLuint GetFakeZTarget(); // This is used by some functions to check for Z target existence. Should be changed to a bool. // Random utilities static void RenderText(const char* pstr, int left, int top, u32 color); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp index 846563530e..52c18e6c0a 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureConverter.cpp @@ -159,8 +159,8 @@ void Shutdown() s_texConvFrameBuffer = 0; } -void EncodeToRam(GLuint srcTexture, const TRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight, bool linearFilter, FRAGMENTSHADER& shader) +void EncodeToRamUsingShader(FRAGMENTSHADER& shader, GLuint srcTexture, const TRectangle& sourceRc, + u8* destAddr, int dstWidth, int dstHeight, bool linearFilter) { Renderer::SetRenderMode(Renderer::RM_Normal); @@ -241,20 +241,22 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf format |= _GX_TF_CTF; } - FRAGMENTSHADER& fs = GetOrCreateEncodingShader(format); - if (fs.glprogid == 0) + FRAGMENTSHADER& texconv_shader = GetOrCreateEncodingShader(format); + if (texconv_shader.glprogid == 0) return; u8* ptr = Memory_GetPtr(address); - u32 target = bFromZBuffer ? Renderer::GetZBufferTarget() : Renderer::GetRenderTarget(); - + u32 source_texture = bFromZBuffer ? Renderer::ResolveAndGetFakeZTarget(source) : Renderer::ResolveAndGetRenderTarget(source); s32 width = source.right - source.left; s32 height = source.bottom - source.top; if (bScaleByHalf) { // Hm. Shouldn't this only scale destination, not source? + // The bloom in Beyond Good & Evil is a good test case - due to this problem, + // it goes very wrong. Compare by switching back and forth between Copy textures to RAM and GL Texture. + // This also affects the shadows in Burnout 2 badly. width /= 2; height /= 2; } @@ -278,7 +280,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf scaledSource.left = 0; scaledSource.right = expandedWidth / samples; - EncodeToRam(target, scaledSource, ptr, expandedWidth / samples, expandedHeight, bScaleByHalf, fs); + EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, ptr, expandedWidth / samples, expandedHeight, bScaleByHalf); if (bFromZBuffer) Renderer::SetZBufferRender(); // notify for future settings @@ -287,7 +289,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf void EncodeToRamYUYV(GLuint srcTexture, const TRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight) { - EncodeToRam(srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, false, s_rgbToYuyvProgram); + EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, false); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp index c2961765d5..c9d7e50772 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.cpp @@ -239,14 +239,12 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width * The problem here was just the sparse hash on the texture. This texture is partly overwrited (what is needed only) * so lot's of remaning old text. Thin white chars on black bg too. */ - // TODO: - clean this up when ready to kill old "unsafe texture cache" // - fix the key index situation with CopyRenderTargetToTexture. // Could happen only for GX_TF_C4, GX_TF_C8 and GX_TF_C14X2 fmt. // Wonder if we can't use tex width&height to know if EFB might be copied to it... // raw idea: TOCHECK if addresses are aligned we have few bits left... - if (address == 0) return NULL; @@ -259,19 +257,24 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width u32 texID = address; if (g_Config.bSafeTextureCache) { - hash_value = TexDecoder_GetSafeTextureHash(ptr, expandedWidth, height, format, 0); // remove last arg - if ( (format == GX_TF_C4) || (format == GX_TF_C8) || (format == GX_TF_C14X2) ) + hash_value = TexDecoder_GetSafeTextureHash(ptr, expandedWidth, height, format, 0); // remove last arg + if ((format == GX_TF_C4) || (format == GX_TF_C8) || (format == GX_TF_C14X2)) { // WARNING! texID != address now => may break CopyRenderTargetToTexture (cf. TODO up) // tlut size can be up to 32768B (GX_TF_C14X2) but Safer == Slower. //texID ^= TexDecoder_GetTlutHash(&texMem[tlutaddr], TexDecoder_GetPaletteSize(format)); + + // This trick (to change the texID depending on the TLUT addr) is a trick to get around + // an issue with metroid prime's fonts, where it has multiple sets of fonts on top of + // each other stored in a single texture, and uses the palette to make different characters + // visible or invisible. Thus, unless we want to recreate the textures for every drawn character, + // we must make sure that texture with different tluts get different IDs. texID ^= TexDecoder_GetTlutHash(&texMem[tlutaddr], (format == GX_TF_C4) ? 32 : 128); //DebugLog("addr: %08x | texID: %08x | texHash: %08x", address, texID, hash_value); } } bool skip_texture_create = false; - TexCache::iterator iter = textures.find(texID); if (iter != textures.end()) { @@ -280,10 +283,12 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width if (!g_Config.bSafeTextureCache) hash_value = ((u32 *)ptr)[entry.hashoffset]; - if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash))) { + if (entry.isRenderTarget || ((address == entry.addr) && (hash_value == entry.hash))) + { entry.frameCount = frameCount; - //glEnable(entry.isNonPow2?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D); - glBindTexture(entry.isNonPow2 ? GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D, entry.texture); + //glEnable(entry.isNonPow2?GL_TEXTURE_RECTANGLE_ARB:GL_TEXTURE_2D); +// entry.isNonPow2 ? TextureMngr::EnableTex2D(texstage) : TextureMngr::EnableTexRECT(texstage); + glBindTexture(entry.isNonPow2 ? GL_TEXTURE_RECTANGLE_ARB : GL_TEXTURE_2D, entry.texture); if (entry.mode.hex != tm0.hex) entry.SetTextureParameters(tm0); //DebugLog("%cC addr: %08x | fmt: %i | e.hash: %08x | w:%04i h:%04i", g_Config.bSafeTextureCache ? 'S' : 'U' @@ -406,7 +411,8 @@ TextureMngr::TCacheEntry* TextureMngr::Load(int texstage, u32 address, int width return &entry; } -void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, TRectangle *source) + +void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source_rect) { DVSTARTPROFILE(); GL_REPORT_ERRORD(); @@ -431,8 +437,8 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool entry.frameCount = frameCount; int mult = bScaleByHalf?2:1; - int w = (abs(source->right-source->left)/mult); - int h = (abs(source->bottom-source->top)/mult); + int w = (abs(source_rect.GetWidth())/mult); + int h = (abs(source_rect.GetHeight())/mult); GL_REPORT_ERRORD(); @@ -600,7 +606,7 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool Renderer::SetRenderMode(Renderer::RM_Normal); // set back to normal GL_REPORT_ERRORD(); - // have to run a pixel shader + // We have to run a pixel shader, for color conversion. Renderer::ResetGLState(); // reset any game specific settings @@ -632,7 +638,11 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, bFromZBuffer?Renderer::GetZBufferTarget():Renderer::GetRenderTarget()); + if (bFromZBuffer) { + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, Renderer::ResolveAndGetFakeZTarget(source_rect)); + } else { + glBindTexture(GL_TEXTURE_RECTANGLE_ARB, Renderer::ResolveAndGetRenderTarget(source_rect)); + } TextureMngr::EnableTexRECT(0); glViewport(0, 0, w, h); @@ -645,10 +655,10 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool glBegin(GL_QUADS); float MValueX = Renderer::GetTargetScaleX(); float MValueY = Renderer::GetTargetScaleY(); - glTexCoord2f((float)source->left * MValueX, Renderer::GetTargetHeight()-(float)source->bottom * MValueY); glVertex2f(-1, 1); - glTexCoord2f((float)source->left * MValueX, Renderer::GetTargetHeight()-(float)source->top * MValueY); glVertex2f(-1, -1); - glTexCoord2f((float)source->right * MValueX, Renderer::GetTargetHeight()-(float)source->top * MValueY); glVertex2f( 1, -1); - glTexCoord2f((float)source->right * MValueX, Renderer::GetTargetHeight()-(float)source->bottom * MValueY); glVertex2f( 1, 1); + glTexCoord2f((float)source_rect.left * MValueX, Renderer::GetTargetHeight()-(float)source_rect.bottom * MValueY); glVertex2f(-1, 1); + glTexCoord2f((float)source_rect.left * MValueX, Renderer::GetTargetHeight()-(float)source_rect.top * MValueY); glVertex2f(-1, -1); + glTexCoord2f((float)source_rect.right * MValueX, Renderer::GetTargetHeight()-(float)source_rect.top * MValueY); glVertex2f( 1, -1); + glTexCoord2f((float)source_rect.right * MValueX, Renderer::GetTargetHeight()-(float)source_rect.bottom * MValueY); glVertex2f( 1, 1); glEnd(); GL_REPORT_ERRORD(); @@ -669,14 +679,14 @@ void TextureMngr::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool void TextureMngr::EnableTex2D(int stage) { - if (!(nTex2DEnabled & (1<second.isRenderTarget = false; } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h index 1f0eb067f1..5cd2637fca 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/TextureMngr.h @@ -74,7 +74,7 @@ public: static void Shutdown(); static void Invalidate(bool shutdown); static TCacheEntry* Load(int texstage, u32 address, int width, int height, int format, int tlutaddr, int tlutfmt); - static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, TRectangle *source); + static void CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, bool bScaleByHalf, const TRectangle &source); static void EnableTex2D(int stage); static void EnableTexRECT(int stage); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp index 6f83287953..ab4ccaba04 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexManager.cpp @@ -242,7 +242,7 @@ void Flush() VERTEXSHADER* vs = VertexShaderCache::GetShader(g_nativeVertexFmt->m_components); bool bRestoreBuffers = false; - if (Renderer::GetZBufferTarget()) { + if (Renderer::GetFakeZTarget()) { if (bpmem.zmode.updateenable) { if (!bpmem.blendmode.colorupdate) { Renderer::SetRenderMode(bpmem.blendmode.alphaupdate ? Renderer::RM_ZBufferAlpha : Renderer::RM_ZBufferOnly); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp index 7361727874..da20a54397 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/VertexShaderCache.cpp @@ -72,7 +72,7 @@ VERTEXSHADER* VertexShaderCache::GetShader(u32 components) { DVSTARTPROFILE(); VERTEXSHADERUID uid; - u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetZBufferTarget() != 0; + u32 zbufrender = (bpmem.ztex2.op == ZTEXTURE_ADD) || Renderer::GetFakeZTarget() != 0; GetVertexShaderId(uid, components, zbufrender); VSCache::iterator iter = vshaders.find(uid); @@ -87,7 +87,7 @@ VERTEXSHADER* VertexShaderCache::GetShader(u32 components) } VSCacheEntry& entry = vshaders[uid]; - const char *code = GenerateVertexShader(components, Renderer::GetZBufferTarget() != 0); + const char *code = GenerateVertexShader(components, Renderer::GetFakeZTarget() != 0); #if defined(_DEBUG) || defined(DEBUGFAST) if (g_Config.iLog & CONF_SAVESHADERS && code) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp index bb775fa976..05c0f67e86 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/XFB.cpp @@ -86,7 +86,7 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) // OpenGL upside down as usual... renderSrcRc.top = Renderer::GetTargetHeight() - sourceRc.top; renderSrcRc.bottom = Renderer::GetTargetHeight() - sourceRc.bottom; - TextureConverter::EncodeToRamYUYV(Renderer::GetRenderTarget(), 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. @@ -208,7 +208,7 @@ void XFB_Write(u8 *xfb_in_ram, const TRectangle& sourceRc, u32 dstWd, u32 dstHt) glEnd(); GL_REPORT_ERRORD(); - int width = sourceRc.right - sourceRc.left; + 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(); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index 5b3be7b2b1..1758abd0bd 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -189,7 +189,7 @@ void DllConfig(HWND _hParent) { for (int i = 0; i < modeNum; i++) { - if(px != modes[i]->hdisplay && py != modes[i]->vdisplay) + if (px != modes[i]->hdisplay && py != modes[i]->vdisplay) { char temp[32]; sprintf(temp,"%dx%d", modes[i]->hdisplay, modes[i]->vdisplay); @@ -219,8 +219,6 @@ void DllConfig(HWND _hParent) void Initialize(void *init) { - //Console::Open(); - frameCount = 0; SVideoInitialize *_pVideoInitialize = (SVideoInitialize*)init; g_VideoInitialize = *(_pVideoInitialize); // Create a shortcut to _pVideoInitialize that can also update it @@ -250,8 +248,6 @@ void DoState(unsigned char **ptr, int mode) { #endif // Clear all caches that touch RAM TextureMngr::Invalidate(false); - // DisplayListManager::Invalidate(); - VertexLoaderManager::MarkAllDirty(); PointerWrap p(ptr, mode); diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.h b/Source/Plugins/Plugin_VideoOGL/Src/main.h index 2e4980df1e..2c488e25d5 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.h +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.h @@ -22,7 +22,4 @@ extern SVideoInitialize g_VideoInitialize; -// Logging -extern int GLScissorX, GLScissorY, GLScissorW, GLScissorH; - #endif