mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-31 01:59:52 -06:00
Some work on merging the video plugins: Added a new plugin to the solution(shouldn't build by default) which combines the DX9, DX11, and OGL plugins with their common code merged (and some things temporarily removed). In it's current state the plugin is hardly usable. Perhaps someone with knowledge of the video plugins will be able to fix the things I have broken more easily than me(or point me in the right direction). I will continue to work on it as well.
Main Issues: DX11 is functional with a ~2MB/s mem leak. OpenGL/DirectX9 have a black display while game runs. (DirectX 9 flashes good display on emulation stop) Too many virtual function calls. (once everything is working, I will work on removing them) Won't build on non-Windows in its current state. (mainly EmuWindow will need changes for Linux/OS X) Probably other stuff. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6219 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
985
Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp
Normal file
985
Source/Plugins/Plugin_VideoMerge/Src/OGL/OGL_Render.cpp
Normal file
@ -0,0 +1,985 @@
|
||||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
|
||||
#include <vector>
|
||||
#include <cmath>
|
||||
#include <cstdio>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <mmsystem.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
//#include "OS/Win32.h"
|
||||
//#include "AVIDump.h"
|
||||
|
||||
#include <wx/image.h>
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
#include <wx/image.h>
|
||||
#endif
|
||||
|
||||
// Common
|
||||
#include "Thread.h"
|
||||
#include "Atomic.h"
|
||||
#include "FileUtil.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "Timer.h"
|
||||
#include "StringUtil.h"
|
||||
|
||||
// VideoCommon
|
||||
#include "VideoConfig.h"
|
||||
#include "Profiler.h"
|
||||
#include "Statistics.h"
|
||||
#include "ImageWrite.h"
|
||||
#include "OpcodeDecoding.h"
|
||||
#include "BPStructs.h"
|
||||
#include "VertexShaderGen.h"
|
||||
#include "DLCache.h"
|
||||
#include "PixelShaderManager.h"
|
||||
#include "VertexShaderManager.h"
|
||||
#include "VertexLoaderManager.h"
|
||||
#include "VertexLoader.h"
|
||||
#include "OnScreenDisplay.h"
|
||||
#include "Fifo.h"
|
||||
|
||||
// OGL
|
||||
#include "OGL_GLUtil.h"
|
||||
#include "OGL_TextureCache.h"
|
||||
#include "OGL_RasterFont.h"
|
||||
#include "OGL_PixelShaderCache.h"
|
||||
#include "OGL_VertexShaderCache.h"
|
||||
#include "OGL_PostProcessing.h"
|
||||
#include "OGL_TextureConverter.h"
|
||||
#include "OGL_FramebufferManager.h"
|
||||
#include "OGL_XFB.h"
|
||||
#include "OGL_Render.h"
|
||||
|
||||
#include "../Main.h"
|
||||
|
||||
namespace OGL
|
||||
{
|
||||
|
||||
// Declarations and definitions
|
||||
// ----------------------------
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
CGcontext g_cgcontext;
|
||||
CGprofile g_cgvProf;
|
||||
CGprofile g_cgfProf;
|
||||
#endif
|
||||
|
||||
RasterFont* s_pfont = NULL;
|
||||
|
||||
static bool s_bLastFrameDumped = false;
|
||||
#ifdef _WIN32
|
||||
static bool s_bAVIDumping = false;
|
||||
#else
|
||||
static FILE* f_pFrameDump;
|
||||
#endif
|
||||
|
||||
// 1 for no MSAA. Use s_MSAASamples > 1 to check for MSAA.
|
||||
static int s_MSAASamples = 1;
|
||||
static int s_MSAACoverageSamples = 0;
|
||||
|
||||
bool s_bHaveFramebufferBlit = false; // export to FramebufferManager.cpp
|
||||
static bool s_bHaveCoverageMSAA = false;
|
||||
|
||||
// The custom resolution
|
||||
|
||||
static bool s_skipSwap = false;
|
||||
|
||||
// TODO: EmuWindow has these too, merge them
|
||||
int OSDChoice = 0 , OSDTime = 0, OSDInternalW = 0, OSDInternalH = 0;
|
||||
|
||||
#if defined(HAVE_WX) && HAVE_WX
|
||||
// Screenshot thread struct
|
||||
typedef struct
|
||||
{
|
||||
int W, H;
|
||||
std::string filename;
|
||||
wxImage *img;
|
||||
} ScrStrct;
|
||||
#endif
|
||||
|
||||
static const GLenum glSrcFactors[8] =
|
||||
{
|
||||
GL_ZERO,
|
||||
GL_ONE,
|
||||
GL_DST_COLOR,
|
||||
GL_ONE_MINUS_DST_COLOR,
|
||||
GL_SRC_ALPHA,
|
||||
GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL_DST_ALPHA,
|
||||
GL_ONE_MINUS_DST_ALPHA
|
||||
};
|
||||
|
||||
static const GLenum glDestFactors[8] = {
|
||||
GL_ZERO,
|
||||
GL_ONE,
|
||||
GL_SRC_COLOR,
|
||||
GL_ONE_MINUS_SRC_COLOR,
|
||||
GL_SRC_ALPHA,
|
||||
GL_ONE_MINUS_SRC_ALPHA,
|
||||
GL_DST_ALPHA,
|
||||
GL_ONE_MINUS_DST_ALPHA
|
||||
};
|
||||
|
||||
static const GLenum glCmpFuncs[8] = {
|
||||
GL_NEVER,
|
||||
GL_LESS,
|
||||
GL_EQUAL,
|
||||
GL_LEQUAL,
|
||||
GL_GREATER,
|
||||
GL_NOTEQUAL,
|
||||
GL_GEQUAL,
|
||||
GL_ALWAYS
|
||||
};
|
||||
|
||||
static const GLenum glLogicOpCodes[16] = {
|
||||
GL_CLEAR,
|
||||
GL_AND,
|
||||
GL_AND_REVERSE,
|
||||
GL_COPY,
|
||||
GL_AND_INVERTED,
|
||||
GL_NOOP,
|
||||
GL_XOR,
|
||||
GL_OR,
|
||||
GL_NOR,
|
||||
GL_EQUIV,
|
||||
GL_INVERT,
|
||||
GL_OR_REVERSE,
|
||||
GL_COPY_INVERTED,
|
||||
GL_OR_INVERTED,
|
||||
GL_NAND,
|
||||
GL_SET
|
||||
};
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
void HandleCgError(CGcontext ctx, CGerror err, void* appdata)
|
||||
{
|
||||
DEBUG_LOG(VIDEO, "Cg error: %s", cgGetErrorString(err));
|
||||
const char* listing = cgGetLastListing(g_cgcontext);
|
||||
if (listing != NULL)
|
||||
DEBUG_LOG(VIDEO, " last listing: %s", listing);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Init functions
|
||||
Renderer::Renderer()
|
||||
{
|
||||
// hmm
|
||||
if (!OpenGL_Create(g_VideoInitialize, 640, 480))
|
||||
{
|
||||
g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
|
||||
return;
|
||||
}
|
||||
|
||||
OpenGL_MakeCurrent();
|
||||
|
||||
//if (!Renderer::Init()) {
|
||||
// g_VideoInitialize.pLog("Renderer::Create failed\n", TRUE);
|
||||
// PanicAlert("Can't create opengl renderer. You might be missing some required opengl extensions, check the logs for more info");
|
||||
// exit(1);
|
||||
//}
|
||||
|
||||
bool bSuccess = true;
|
||||
s_MSAACoverageSamples = 0;
|
||||
GLint numvertexattribs = 0;
|
||||
|
||||
switch (g_ActiveConfig.iMultisampleMode)
|
||||
{
|
||||
case MULTISAMPLE_OFF:
|
||||
s_MSAASamples = 1;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_2X:
|
||||
s_MSAASamples = 2;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_4X:
|
||||
s_MSAASamples = 4;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_8X:
|
||||
s_MSAASamples = 8;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_CSAA_8X:
|
||||
s_MSAASamples = 4; s_MSAACoverageSamples = 8;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_CSAA_8XQ:
|
||||
s_MSAASamples = 8; s_MSAACoverageSamples = 8;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_CSAA_16X:
|
||||
s_MSAASamples = 4; s_MSAACoverageSamples = 16;
|
||||
break;
|
||||
|
||||
case MULTISAMPLE_CSAA_16XQ:
|
||||
s_MSAASamples = 8; s_MSAACoverageSamples = 16;
|
||||
break;
|
||||
|
||||
default:
|
||||
s_MSAASamples = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
g_cgcontext = cgCreateContext();
|
||||
cgGetError();
|
||||
cgSetErrorHandler(HandleCgError, NULL);
|
||||
#endif
|
||||
|
||||
// Look for required extensions.
|
||||
const char *const ptoken = (const char*)glGetString(GL_EXTENSIONS);
|
||||
if (!ptoken)
|
||||
{
|
||||
PanicAlert("Your OpenGL Driver seems to be not working.\n"
|
||||
"Please make sure your drivers are up-to-date and\n"
|
||||
"that your video hardware is OpenGL 2.x compatible.");
|
||||
//return false;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO_LOG(VIDEO, "Supported OpenGL Extensions:");
|
||||
INFO_LOG(VIDEO, ptoken); // write to the log file
|
||||
INFO_LOG(VIDEO, "");
|
||||
|
||||
OSD::AddMessage(StringFromFormat("Video Info: %s, %s, %s",
|
||||
glGetString(GL_VENDOR),
|
||||
glGetString(GL_RENDERER),
|
||||
glGetString(GL_VERSION)).c_str(), 5000);
|
||||
|
||||
glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &numvertexattribs);
|
||||
if (numvertexattribs < 11)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Number of attributes %d not enough.\n"
|
||||
"GPU: Does your video card support OpenGL 2.x?",
|
||||
numvertexattribs);
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
// Init extension support.
|
||||
if (glewInit() != GLEW_OK)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "glewInit() failed! Does your video card support OpenGL 2.x?");
|
||||
//return false;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (!GLEW_EXT_framebuffer_object)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GPU: ERROR: Need GL_EXT_framebufer_object for multiple render targets.\n"
|
||||
"GPU: Does your video card support OpenGL 2.x?");
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
if (!GLEW_EXT_secondary_color)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "GPU: OGL ERROR: Need GL_EXT_secondary_color.\n"
|
||||
"GPU: Does your video card support OpenGL 2.x?");
|
||||
bSuccess = false;
|
||||
}
|
||||
|
||||
s_bHaveFramebufferBlit = strstr(ptoken, "GL_EXT_framebuffer_blit") != NULL;
|
||||
if (!s_bHaveFramebufferBlit)
|
||||
{
|
||||
// MSAA ain't gonna work. turn it off if enabled.
|
||||
s_MSAASamples = 1;
|
||||
}
|
||||
|
||||
s_bHaveCoverageMSAA = strstr(ptoken, "GL_NV_framebuffer_multisample_coverage") != NULL;
|
||||
if (!s_bHaveCoverageMSAA)
|
||||
{
|
||||
s_MSAACoverageSamples = 0;
|
||||
}
|
||||
|
||||
if (!bSuccess)
|
||||
//return false;
|
||||
return;
|
||||
|
||||
// Handle VSync on/off
|
||||
#if defined USE_WX && USE_WX
|
||||
// TODO: FILL IN
|
||||
#elif defined _WIN32
|
||||
if (WGLEW_EXT_swap_control)
|
||||
wglSwapIntervalEXT(g_ActiveConfig.bVSync ? 1 : 0);
|
||||
else
|
||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
||||
#elif defined(HAVE_X11) && HAVE_X11
|
||||
if (glXSwapIntervalSGI)
|
||||
glXSwapIntervalSGI(g_ActiveConfig.bVSync ? 1 : 0);
|
||||
else
|
||||
ERROR_LOG(VIDEO, "No support for SwapInterval (framerate clamped to monitor refresh rate).");
|
||||
#endif
|
||||
|
||||
// check the max texture width and height
|
||||
GLint max_texture_size;
|
||||
glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint *)&max_texture_size);
|
||||
if (max_texture_size < 1024)
|
||||
ERROR_LOG(VIDEO, "GL_MAX_TEXTURE_SIZE too small at %i - must be at least 1024.",
|
||||
max_texture_size);
|
||||
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
bSuccess = false;
|
||||
|
||||
if (glDrawBuffers == NULL && !GLEW_ARB_draw_buffers)
|
||||
glDrawBuffers = glDrawBuffersARB;
|
||||
|
||||
if (!GLEW_ARB_texture_non_power_of_two)
|
||||
WARN_LOG(VIDEO, "ARB_texture_non_power_of_two not supported.");
|
||||
|
||||
// Decide frambuffer size
|
||||
FramebufferSize((int)OpenGL_GetBackbufferWidth(), (int)OpenGL_GetBackbufferHeight());
|
||||
|
||||
// Because of the fixed framebuffer size we need to disable the resolution
|
||||
// options while running
|
||||
g_Config.bRunning = true;
|
||||
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
bSuccess = false;
|
||||
|
||||
// Initialize the FramebufferManager
|
||||
g_framebuffer_manager = new FramebufferManager(s_backbuffer_width,
|
||||
s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples);
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
|
||||
if (GL_REPORT_ERROR() != GL_NO_ERROR)
|
||||
bSuccess = false;
|
||||
|
||||
s_pfont = new RasterFont();
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
// load the effect, find the best profiles (if any)
|
||||
if (cgGLIsProfileSupported(CG_PROFILE_ARBVP1) != CG_TRUE)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "arbvp1 not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (cgGLIsProfileSupported(CG_PROFILE_ARBFP1) != CG_TRUE)
|
||||
{
|
||||
ERROR_LOG(VIDEO, "arbfp1 not supported");
|
||||
return false;
|
||||
}
|
||||
|
||||
g_cgvProf = cgGLGetLatestProfile(CG_GL_VERTEX);
|
||||
g_cgfProf = cgGLGetLatestProfile(CG_GL_FRAGMENT);
|
||||
#if CG_VERSION_NUM == 2100
|
||||
// A bug was introduced in Cg2.1's handling of very large profile option values
|
||||
// so this will not work on ATI. ATI returns MAXINT = 2147483647 (0x7fffffff)
|
||||
// which is correct in OpenGL but Cg fails to handle it properly. As a result
|
||||
// -1 is used by Cg resulting (signedness incorrect) and compilation fails.
|
||||
if (strstr((const char*)glGetString(GL_VENDOR), "ATI") == NULL)
|
||||
#endif
|
||||
{
|
||||
cgGLSetOptimalOptions(g_cgvProf);
|
||||
cgGLSetOptimalOptions(g_cgfProf);
|
||||
}
|
||||
#endif // HAVE_CG
|
||||
|
||||
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_FRAGMENT_PROGRAM_ARB,
|
||||
GL_MAX_PROGRAM_ADDRESS_REGISTERS_ARB,
|
||||
(GLint *)&naddrregisters[1]);
|
||||
DEBUG_LOG(VIDEO, "Max program env parameters: vert=%d, frag=%d",
|
||||
nenvvertparams, nenvfragparams);
|
||||
DEBUG_LOG(VIDEO, "Max program address register parameters: vert=%d, frag=%d",
|
||||
naddrregisters[0], naddrregisters[1]);
|
||||
|
||||
if (nenvvertparams < 238)
|
||||
ERROR_LOG(VIDEO, "Not enough vertex shader environment constants!!");
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
INFO_LOG(VIDEO, "Max buffer sizes: %d %d",
|
||||
cgGetProgramBufferMaxSize(g_cgvProf),
|
||||
cgGetProgramBufferMaxSize(g_cgfProf));
|
||||
#ifndef _DEBUG
|
||||
cgGLSetDebugMode(GL_FALSE);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
glStencilFunc(GL_ALWAYS, 0, 0);
|
||||
glBlendFunc(GL_ONE, GL_ONE);
|
||||
|
||||
glViewport(0, 0, GetTargetWidth(), GetTargetHeight()); // Reset The Current Viewport
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
glShadeModel(GL_SMOOTH);
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClearDepth(1.0f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 4); // 4-byte pixel alignment
|
||||
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
|
||||
glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
|
||||
glBlendColorEXT(0, 0, 0, 0.5f);
|
||||
glClearDepth(1.0f);
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
// legacy multitexturing: select texture channel only.
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glClientActiveTexture(GL_TEXTURE0);
|
||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
|
||||
UpdateActiveConfig();
|
||||
//return GL_REPORT_ERROR() == GL_NO_ERROR && bSuccess;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
g_Config.bRunning = false;
|
||||
UpdateActiveConfig();
|
||||
delete s_pfont;
|
||||
s_pfont = 0;
|
||||
|
||||
#if defined HAVE_CG && HAVE_CG
|
||||
if (g_cgcontext)
|
||||
{
|
||||
cgDestroyContext(g_cgcontext);
|
||||
g_cgcontext = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
delete g_framebuffer_manager;
|
||||
|
||||
//#ifdef _WIN32
|
||||
// if(s_bAVIDumping)
|
||||
// AVIDump::Stop();
|
||||
//#else
|
||||
// if(f_pFrameDump != NULL)
|
||||
// fclose(f_pFrameDump);
|
||||
//#endif
|
||||
|
||||
OpenGL_Shutdown();
|
||||
}
|
||||
|
||||
// For the OSD menu's live resolution change
|
||||
bool Renderer::Allow2x()
|
||||
{
|
||||
if (GetFrameBufferWidth() >= 1280 && GetFrameBufferHeight() >= 960)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Renderer::AllowCustom()
|
||||
{
|
||||
//if (GetCustomWidth() <= GetFrameBufferWidth() && GetCustomHeight() <= GetFrameBufferHeight())
|
||||
// return true;
|
||||
//else
|
||||
// return false;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void Renderer::ResetAPIState()
|
||||
{
|
||||
// Gets us to a reasonably sane state where it's possible to do things like
|
||||
// image copies with textured quads, etc.
|
||||
VertexShaderCache::DisableShader();
|
||||
PixelShaderCache::DisableShader();
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_BLEND);
|
||||
glDepthMask(GL_FALSE);
|
||||
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
|
||||
}
|
||||
|
||||
void UpdateViewport();
|
||||
|
||||
void Renderer::RestoreAPIState()
|
||||
{
|
||||
// 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);
|
||||
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
SetScissorRect();
|
||||
SetColorMask();
|
||||
SetBlendMode(true);
|
||||
|
||||
VertexShaderCache::SetCurrentShader(0);
|
||||
PixelShaderCache::SetCurrentShader(0);
|
||||
}
|
||||
|
||||
void Renderer::SetColorMask()
|
||||
{
|
||||
GLenum ColorMask = (bpmem.blendmode.colorupdate) ? GL_TRUE : GL_FALSE;
|
||||
GLenum AlphaMask = (bpmem.blendmode.alphaupdate) ? GL_TRUE : GL_FALSE;
|
||||
glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask);
|
||||
}
|
||||
|
||||
void Renderer::SetBlendMode(bool forceUpdate)
|
||||
{
|
||||
// blend mode bit mask
|
||||
// 0 - blend enable
|
||||
// 2 - reverse subtract enable (else add)
|
||||
// 3-5 - srcRGB function
|
||||
// 6-8 - dstRGB function
|
||||
|
||||
u32 newval = bpmem.blendmode.subtract << 2;
|
||||
|
||||
if (bpmem.blendmode.subtract)
|
||||
newval |= 0x0049; // enable blending src 1 dst 1
|
||||
else if (bpmem.blendmode.blendenable)
|
||||
{
|
||||
newval |= 1; // enable blending
|
||||
newval |= bpmem.blendmode.srcfactor << 3;
|
||||
newval |= bpmem.blendmode.dstfactor << 6;
|
||||
}
|
||||
|
||||
u32 changes = forceUpdate ? 0xFFFFFFFF : newval ^ s_blendMode;
|
||||
|
||||
if (changes & 1)
|
||||
// blend enable change
|
||||
(newval & 1) ? glEnable(GL_BLEND) : glDisable(GL_BLEND);
|
||||
|
||||
if (changes & 4)
|
||||
// subtract enable change
|
||||
glBlendEquation(newval & 4 ? GL_FUNC_REVERSE_SUBTRACT : GL_FUNC_ADD);
|
||||
|
||||
if (changes & 0x1F8)
|
||||
// blend RGB change
|
||||
glBlendFunc(glSrcFactors[(newval >> 3) & 7], glDestFactors[(newval >> 6) & 7]);
|
||||
|
||||
s_blendMode = newval;
|
||||
}
|
||||
|
||||
u32 Renderer::AccessEFB(EFBAccessType type, int x, int y)
|
||||
{
|
||||
if(!g_ActiveConfig.bEFBAccessEnable)
|
||||
return 0;
|
||||
|
||||
// Get the rectangular target region covered by the EFB pixel.
|
||||
EFBRectangle efbPixelRc;
|
||||
efbPixelRc.left = x;
|
||||
efbPixelRc.top = y;
|
||||
efbPixelRc.right = x + 1;
|
||||
efbPixelRc.bottom = y + 1;
|
||||
|
||||
TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc);
|
||||
|
||||
// TODO (FIX) : currently, AA path is broken/offset and doesn't return the correct pixel
|
||||
switch (type)
|
||||
{
|
||||
|
||||
case PEEK_Z:
|
||||
{
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBDepthTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
}
|
||||
|
||||
// Sample from the center of the target region.
|
||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
|
||||
u32 z = 0;
|
||||
glReadPixels(srcX, srcY, 1, 1, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, &z);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// Scale the 32-bit value returned by glReadPixels to a 24-bit
|
||||
// value (GC uses a 24-bit Z-buffer).
|
||||
// TODO: in RE0 this value is often off by one, which causes lighting to disappear
|
||||
return z >> 8;
|
||||
}
|
||||
|
||||
case POKE_Z:
|
||||
// TODO: Implement
|
||||
break;
|
||||
|
||||
case PEEK_COLOR: // GXPeekARGB
|
||||
{
|
||||
// Although it may sound strange, this really is A8R8G8B8 and not RGBA or 24-bit...
|
||||
|
||||
// Tested in Killer 7, the first 8bits represent the alpha value which is used to
|
||||
// determine if we're aiming at an enemy (0x80 / 0x88) or not (0x70)
|
||||
// Wind Waker is also using it for the pictograph to determine the color of each pixel
|
||||
|
||||
if (s_MSAASamples > 1)
|
||||
{
|
||||
// Resolve our rectangle.
|
||||
FramebufferManager::GetEFBColorTexture(efbPixelRc);
|
||||
glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, FramebufferManager::GetResolvedFramebuffer());
|
||||
}
|
||||
|
||||
// Sample from the center of the target region.
|
||||
int srcX = (targetPixelRc.left + targetPixelRc.right) / 2;
|
||||
int srcY = (targetPixelRc.top + targetPixelRc.bottom) / 2;
|
||||
|
||||
// Read back pixel in BGRA format, then byteswap to get GameCube's ARGB Format.
|
||||
u32 color = 0;
|
||||
glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color);
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
case POKE_COLOR:
|
||||
// TODO: Implement. One way is to draw a tiny pixel-sized rectangle at
|
||||
// the exact location. Note: EFB pokes are susceptible to Z-buffering
|
||||
// and perhaps blending.
|
||||
//WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering");
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Function: This function handles the OpenGL glScissor() function
|
||||
// ----------------------------
|
||||
// Call browser: OpcodeDecoding.cpp ExecuteDisplayList > Decode() > LoadBPReg()
|
||||
// case 0x52 > SetScissorRect()
|
||||
// ----------------------------
|
||||
// bpmem.scissorTL.x, y = 342x342
|
||||
// bpmem.scissorBR.x, y = 981x821
|
||||
// GetTargetHeight() = the fixed ini file setting
|
||||
// donkopunchstania - it appears scissorBR is the bottom right pixel inside the scissor box
|
||||
// therefore the width and height are (scissorBR + 1) - scissorTL
|
||||
bool Renderer::SetScissorRect()
|
||||
{
|
||||
EFBRectangle rc;
|
||||
if (g_renderer->SetScissorRect(rc))
|
||||
{
|
||||
glScissor(
|
||||
(int)(rc.left * EFBxScale), // x = 0 for example
|
||||
(int)((EFB_HEIGHT - rc.bottom) * EFByScale), // y = 0 for example
|
||||
(int)((rc.right - rc.left) * EFBxScale), // width = 640 for example
|
||||
(int)((rc.bottom - rc.top) * EFByScale) // height = 480 for example
|
||||
);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
glScissor(0, 0, GetTargetWidth(), GetTargetHeight());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable,
|
||||
bool alphaEnable, bool zEnable, u32 color, u32 z)
|
||||
{
|
||||
// Update the view port for clearing the picture
|
||||
TargetRectangle targetRc = ConvertEFBRectangle(rc);
|
||||
glViewport(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
||||
glScissor(targetRc.left, targetRc.bottom, targetRc.GetWidth(), targetRc.GetHeight());
|
||||
|
||||
// Always set the scissor in case it was set by the game and has not been reset
|
||||
|
||||
VertexShaderManager::SetViewportChanged();
|
||||
|
||||
GLbitfield bits = 0;
|
||||
if (colorEnable)
|
||||
{
|
||||
bits |= GL_COLOR_BUFFER_BIT;
|
||||
glClearColor(
|
||||
((color >> 16) & 0xFF) / 255.0f,
|
||||
((color >> 8) & 0xFF) / 255.0f,
|
||||
(color & 0xFF) / 255.0f,
|
||||
((color >> 24) & 0xFF) / 255.0f
|
||||
);
|
||||
}
|
||||
if (zEnable)
|
||||
{
|
||||
bits |= GL_DEPTH_BUFFER_BIT;
|
||||
glClearDepth((z & 0xFFFFFF) / float(0xFFFFFF));
|
||||
}
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
glClear(bits);
|
||||
SetScissorRect();
|
||||
}
|
||||
|
||||
void Renderer::PrepareXFBCopy(const TargetRectangle &dst_rect)
|
||||
{
|
||||
// Update GLViewPort
|
||||
glViewport(dst_rect.left, dst_rect.bottom, dst_rect.GetWidth(), dst_rect.GetHeight());
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// Copy the framebuffer to screen.
|
||||
|
||||
// Texture map s_xfbTexture onto the main buffer
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glEnable(GL_TEXTURE_RECTANGLE_ARB);
|
||||
// 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);
|
||||
}
|
||||
|
||||
void Renderer::Draw(const XFBSourceBase* xfbSource, const TargetRectangle& sourceRc,
|
||||
const MathUtil::Rectangle<float>& drawRc, const EFBRectangle& rc)
|
||||
{
|
||||
// testing
|
||||
//glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
|
||||
|
||||
if (xfbSource)
|
||||
{
|
||||
// Texture map xfbSource->texture onto the main buffer
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, ((XFBSource*)xfbSource)->texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Render to the real buffer now.
|
||||
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0); // switch to the window backbuffer
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, FramebufferManager::ResolveAndGetRenderTarget(rc));
|
||||
}
|
||||
|
||||
// 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.
|
||||
bool applyShader = PostProcessing::ApplyShader();
|
||||
if (applyShader)
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(sourceRc.left, sourceRc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 0);
|
||||
glVertex2f(drawRc.left, drawRc.bottom);
|
||||
|
||||
glTexCoord2f(sourceRc.left, sourceRc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 0, 1);
|
||||
glVertex2f(drawRc.left, drawRc.top);
|
||||
|
||||
glTexCoord2f(sourceRc.right, sourceRc.top);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 1);
|
||||
glVertex2f(drawRc.right, drawRc.top);
|
||||
|
||||
glTexCoord2f(sourceRc.right, sourceRc.bottom);
|
||||
glMultiTexCoord2fARB(GL_TEXTURE1, 1, 0);
|
||||
glVertex2f(drawRc.right, drawRc.bottom);
|
||||
glEnd();
|
||||
PixelShaderCache::DisableShader();
|
||||
}
|
||||
else
|
||||
{
|
||||
glBegin(GL_QUADS);
|
||||
glTexCoord2f(sourceRc.left, sourceRc.bottom);
|
||||
glVertex2f(drawRc.left, drawRc.bottom);
|
||||
|
||||
glTexCoord2f(sourceRc.left, sourceRc.top);
|
||||
glVertex2f(drawRc.left, drawRc.top);
|
||||
|
||||
glTexCoord2f(sourceRc.right, sourceRc.top);
|
||||
glVertex2f(drawRc.right, drawRc.top);
|
||||
|
||||
glTexCoord2f(sourceRc.right, sourceRc.bottom);
|
||||
glVertex2f(drawRc.right, drawRc.bottom);
|
||||
glEnd();
|
||||
}
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0);
|
||||
TextureCache::DisableStage(0);
|
||||
|
||||
// TODO: silly place for this
|
||||
// Wireframe
|
||||
if (g_ActiveConfig.bWireFrame)
|
||||
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
void Renderer::EndFrame()
|
||||
{
|
||||
// Copy the rendered frame to the real window
|
||||
OpenGL_SwapBuffers();
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
|
||||
// Clear framebuffer
|
||||
glClearColor(0, 0, 0, 0);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
void Renderer::Present()
|
||||
{
|
||||
// Render to the framebuffer.
|
||||
FramebufferManager::SetFramebuffer(0);
|
||||
|
||||
GL_REPORT_ERRORD();
|
||||
}
|
||||
|
||||
bool Renderer::CheckForResize()
|
||||
{
|
||||
// TODO: temp
|
||||
|
||||
OpenGL_Update(); // just updates the render window position and the backbuffer size
|
||||
return true;
|
||||
}
|
||||
|
||||
void Renderer::GetBackBufferSize(int* w, int* h)
|
||||
{
|
||||
*w = (int)OpenGL_GetBackbufferWidth();
|
||||
*h = (int)OpenGL_GetBackbufferHeight();
|
||||
}
|
||||
|
||||
void Renderer::RecreateFramebufferManger()
|
||||
{
|
||||
delete g_framebuffer_manager;
|
||||
g_framebuffer_manager = new FramebufferManager(s_backbuffer_width,
|
||||
s_backbuffer_height, s_MSAASamples, s_MSAACoverageSamples);
|
||||
|
||||
glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
|
||||
}
|
||||
|
||||
void Renderer::BeginFrame()
|
||||
{
|
||||
// TODO: silly place for this
|
||||
g_Config.iSaveTargetId = 0;
|
||||
|
||||
bool last_copy_efb_to_Texture = g_ActiveConfig.bCopyEFBToTexture;
|
||||
UpdateActiveConfig();
|
||||
if (last_copy_efb_to_Texture != g_ActiveConfig.bCopyEFBToTexture)
|
||||
TextureCache::ClearRenderTargets();
|
||||
}
|
||||
|
||||
// Called from VertexShaderManager
|
||||
void Renderer::UpdateViewport()
|
||||
{
|
||||
// reversed gxsetviewport(xorig, yorig, width, height, nearz, farz)
|
||||
// [0] = width/2
|
||||
// [1] = height/2
|
||||
// [2] = 16777215 * (farz - nearz)
|
||||
// [3] = xorig + width/2 + 342
|
||||
// [4] = yorig + height/2 + 342
|
||||
// [5] = 16777215 * farz
|
||||
float scissorXOff = float(bpmem.scissorOffset.x) * 2.0f; // 342
|
||||
float scissorYOff = float(bpmem.scissorOffset.y) * 2.0f; // 342
|
||||
|
||||
// Stretch picture with increased internal resolution
|
||||
int GLx = (int)ceil((xfregs.rawViewport[3] - xfregs.rawViewport[0] - scissorXOff) *
|
||||
EFBxScale);
|
||||
int GLy = (int)ceil(
|
||||
(float(EFB_HEIGHT) - xfregs.rawViewport[4] + xfregs.rawViewport[1] + scissorYOff) *
|
||||
EFByScale);
|
||||
int GLWidth = (int)ceil(2.0f * xfregs.rawViewport[0] * EFBxScale);
|
||||
int GLHeight = (int)ceil(-2.0f * xfregs.rawViewport[1] * EFByScale);
|
||||
double GLNear = (xfregs.rawViewport[5] - xfregs.rawViewport[2]) / 16777216.0f;
|
||||
double GLFar = xfregs.rawViewport[5] / 16777216.0f;
|
||||
if(GLWidth < 0)
|
||||
{
|
||||
GLx += GLWidth;
|
||||
GLWidth*=-1;
|
||||
}
|
||||
if(GLHeight < 0)
|
||||
{
|
||||
GLy += GLHeight;
|
||||
GLHeight *= -1;
|
||||
}
|
||||
// Update the view port
|
||||
glViewport(GLx, GLy, GLWidth, GLHeight);
|
||||
glDepthRange(GLNear, GLFar);
|
||||
}
|
||||
|
||||
void Renderer::SetGenerationMode()
|
||||
{
|
||||
// none, ccw, cw, ccw
|
||||
if (bpmem.genMode.cullmode > 0)
|
||||
{
|
||||
glEnable(GL_CULL_FACE);
|
||||
glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW);
|
||||
}
|
||||
else
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
|
||||
void Renderer::SetDepthMode()
|
||||
{
|
||||
if (bpmem.zmode.testenable)
|
||||
{
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE);
|
||||
glDepthFunc(glCmpFuncs[bpmem.zmode.func]);
|
||||
}
|
||||
else
|
||||
{
|
||||
// if the test is disabled write is disabled too
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDepthMask(GL_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::SetLogicOpMode()
|
||||
{
|
||||
if (bpmem.blendmode.logicopenable && bpmem.blendmode.logicmode != 3)
|
||||
{
|
||||
glEnable(GL_COLOR_LOGIC_OP);
|
||||
glLogicOp(glLogicOpCodes[bpmem.blendmode.logicmode]);
|
||||
}
|
||||
else
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
}
|
||||
|
||||
void Renderer::SetDitherMode()
|
||||
{
|
||||
if (bpmem.blendmode.dither)
|
||||
glEnable(GL_DITHER);
|
||||
else
|
||||
glDisable(GL_DITHER);
|
||||
}
|
||||
|
||||
void Renderer::SetLineWidth()
|
||||
{
|
||||
float fratio = xfregs.rawViewport[0] != 0 ?
|
||||
((float)GetTargetWidth() / EFB_WIDTH) : 1.0f;
|
||||
if (bpmem.lineptwidth.linesize > 0)
|
||||
// scale by ratio of widths
|
||||
glLineWidth((float)bpmem.lineptwidth.linesize * fratio / 6.0f);
|
||||
if (bpmem.lineptwidth.pointsize > 0)
|
||||
glPointSize((float)bpmem.lineptwidth.pointsize * fratio / 6.0f);
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user