2018-11-15 23:31:39 +00:00
/*****************************************************************************\
Snes9x - Portable Super Nintendo Entertainment System ( TM ) emulator .
This file is licensed under the Snes9x License .
For further information , consult the LICENSE file in the root directory .
\ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-03-20 22:53:39 +00:00
2010-09-25 17:35:19 +00:00
# include "COpenGL.h"
# include "win32_display.h"
# include "../snes9x.h"
# include "../gfx.h"
# include "../display.h"
# include "wsnes9x.h"
2010-10-22 19:51:50 +00:00
# include <msxml2.h>
2010-09-25 17:35:19 +00:00
# include "../filter/hq2x.h"
# include "../filter/2xsai.h"
2023-05-04 22:36:36 +00:00
# include "snes9x_imgui.h"
# include "imgui_impl_opengl3.h"
2010-09-25 17:35:19 +00:00
COpenGL : : COpenGL ( void )
{
hDC = NULL ;
hRC = NULL ;
hWnd = NULL ;
drawTexture = 0 ;
initDone = false ;
afterRenderWidth = 0 ;
afterRenderHeight = 0 ;
2018-05-24 13:49:05 +00:00
outTextureWidth = 0 ;
outTextureHeight = 0 ;
2010-09-25 17:35:19 +00:00
fullscreen = false ;
shaderFunctionsLoaded = false ;
2011-02-24 00:26:42 +00:00
shader_type = OGL_SHADER_NONE ;
2010-09-25 17:35:19 +00:00
pboFunctionsLoaded = false ;
shaderProgram = 0 ;
vertexShader = 0 ;
fragmentShader = 0 ;
2011-02-24 00:26:42 +00:00
cgContext = NULL ;
cgVertexProgram = cgFragmentProgram = NULL ;
2011-03-20 22:21:12 +00:00
cgAvailable = false ;
2011-05-11 19:39:06 +00:00
frameCount = 0 ;
2011-07-02 02:25:13 +00:00
cgShader = NULL ;
2018-05-20 17:48:38 +00:00
glslShader = NULL ;
2019-01-31 23:07:09 +00:00
* currentShaderFile = _T ( ' \0 ' ) ;
2010-09-25 17:35:19 +00:00
}
COpenGL : : ~ COpenGL ( void )
{
DeInitialize ( ) ;
}
bool COpenGL : : Initialize ( HWND hWnd )
{
int pfdIndex ;
RECT windowRect ;
this - > hWnd = hWnd ;
this - > hDC = GetDC ( hWnd ) ;
PIXELFORMATDESCRIPTOR pfd =
{
sizeof ( PIXELFORMATDESCRIPTOR ) , // Size Of This Pixel Format Descriptor
1 , // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER , // Must Support Double Buffering
PFD_TYPE_RGBA , // Request An RGBA Format
2023-02-10 22:15:00 +00:00
32 , // Select Our Color Depth
2010-09-25 17:35:19 +00:00
0 , 0 , 0 , 0 , 0 , 0 , // Color Bits Ignored
0 , // No Alpha Buffer
0 , // Shift Bit Ignored
0 , // No Accumulation Buffer
0 , 0 , 0 , 0 , // Accumulation Bits Ignored
16 , // 16Bit Z-Buffer (Depth Buffer)
0 , // No Stencil Buffer
0 , // No Auxiliary Buffer
PFD_MAIN_PLANE , // Main Drawing Layer
0 , // Reserved
0 , 0 , 0 // Layer Masks Ignored
} ;
PIXELFORMATDESCRIPTOR pfdSel ;
if ( ! ( pfdIndex = ChoosePixelFormat ( hDC , & pfd ) ) ) {
DeInitialize ( ) ;
return false ;
}
if ( ! SetPixelFormat ( hDC , pfdIndex , & pfd ) ) {
2023-02-10 22:03:05 +00:00
// SetPixelFormat can only be called once per window. Vulkan WSI will do
// this automatically and fall back if it's already been set. Since Vulkan
// has similar requirements, we don't need to set it any more anyway.
// DeInitialize();
// return false;
2010-09-25 17:35:19 +00:00
}
if ( ! ( hRC = wglCreateContext ( hDC ) ) ) {
DeInitialize ( ) ;
return false ;
}
if ( ! wglMakeCurrent ( hDC , hRC ) ) {
DeInitialize ( ) ;
return false ;
}
2018-05-20 15:25:39 +00:00
ogl_LoadFunctions ( ) ;
2010-09-25 17:35:19 +00:00
LoadPBOFunctions ( ) ;
wglSwapIntervalEXT = ( PFNWGLSWAPINTERVALEXTPROC ) wglGetProcAddress ( " wglSwapIntervalEXT " ) ;
2023-02-23 01:14:05 +00:00
2010-10-04 15:36:17 +00:00
glEnableClientState ( GL_VERTEX_ARRAY ) ;
glEnableClientState ( GL_TEXTURE_COORD_ARRAY ) ;
2010-09-25 17:35:19 +00:00
glEnable ( GL_BLEND ) ;
glEnable ( GL_TEXTURE_2D ) ;
glMatrixMode ( GL_PROJECTION ) ;
glLoadIdentity ( ) ;
glOrtho ( 0.0 , 1.0 , 0.0 , 1.0 , - 1 , 1 ) ;
2023-02-23 01:14:05 +00:00
2010-09-25 17:35:19 +00:00
glVertexPointer ( 2 , GL_FLOAT , 0 , vertices ) ;
glTexCoordPointer ( 2 , GL_FLOAT , 0 , texcoords ) ;
2011-03-20 22:21:12 +00:00
cgAvailable = loadCgFunctions ( ) ;
if ( cgAvailable ) {
cgContext = cgCreateContext ( ) ;
2011-07-02 02:25:13 +00:00
cgShader = new CGLCG ( cgContext ) ;
2011-03-20 22:21:12 +00:00
}
2011-02-24 00:26:42 +00:00
2019-02-19 22:57:42 +00:00
if ( ShaderAvailable ( ) & & NPOTAvailable ( ) ) {
2018-05-20 17:48:38 +00:00
glslShader = new GLSLShader ( ) ;
}
2011-07-03 21:12:41 +00:00
ApplyDisplayChanges ( ) ;
2010-09-25 17:35:19 +00:00
glClearColor ( 0.0f , 0.0f , 0.0f , 0.5f ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
SwapBuffers ( hDC ) ;
2023-05-04 22:36:36 +00:00
if ( ogl_GetMajorVersion ( ) > = 3 & & ! Settings . AutoDisplayMessages )
{
auto defaults = S9xImGuiGetDefaults ( ) ;
defaults . font_size = GUI . OSDSize ;
defaults . spacing = defaults . font_size / 2.4 ;
S9xImGuiInit ( & defaults ) ;
ImGui_ImplOpenGL3_Init ( ) ;
Settings . DisplayIndicators = true ;
}
2010-09-25 17:35:19 +00:00
initDone = true ;
return true ;
}
void COpenGL : : DeInitialize ( )
{
initDone = false ;
2023-05-04 22:36:36 +00:00
if ( S9xImGuiRunning ( ) )
{
ImGui_ImplOpenGL3_Shutdown ( ) ;
S9xImGuiDeinit ( ) ;
}
2011-02-24 00:26:42 +00:00
SetShaders ( NULL ) ;
2010-09-25 17:35:19 +00:00
DestroyDrawSurface ( ) ;
wglMakeCurrent ( NULL , NULL ) ;
if ( hRC ) {
wglDeleteContext ( hRC ) ;
hRC = NULL ;
}
2023-02-23 01:14:05 +00:00
if ( hDC )
{
ReleaseDC ( hWnd , hDC ) ;
hDC = NULL ;
}
2010-09-25 17:35:19 +00:00
hWnd = NULL ;
afterRenderWidth = 0 ;
afterRenderHeight = 0 ;
2018-05-24 13:49:05 +00:00
outTextureWidth = 0 ;
outTextureHeight = 0 ;
2010-09-25 17:35:19 +00:00
shaderFunctionsLoaded = false ;
2011-02-24 00:26:42 +00:00
shader_type = OGL_SHADER_NONE ;
2018-05-20 17:48:38 +00:00
if ( glslShader ) {
delete glslShader ;
glslShader = NULL ;
}
2011-07-02 02:25:13 +00:00
if ( cgShader ) {
delete cgShader ;
cgShader = NULL ;
}
2011-07-03 21:12:41 +00:00
if ( cgAvailable )
unloadCgLibrary ( ) ;
cgAvailable = false ;
2010-09-25 17:35:19 +00:00
}
2018-05-22 19:27:40 +00:00
void COpenGL : : CreateDrawSurface ( unsigned int width , unsigned int height )
2010-09-25 17:35:19 +00:00
{
HRESULT hr ;
2018-05-22 19:27:40 +00:00
if ( ! NPOTAvailable ( ) ) {
unsigned int neededSize = max ( width , height ) ;
//we need at least 512 pixels (SNES_WIDTH * 2) so we can start with that value
unsigned int quadTextureSize = 512 ;
while ( quadTextureSize < neededSize )
quadTextureSize * = 2 ;
width = height = quadTextureSize ;
}
2010-09-25 17:35:19 +00:00
if ( ! drawTexture ) {
2018-05-22 19:27:40 +00:00
outTextureWidth = width ;
outTextureHeight = height ;
2010-09-25 17:35:19 +00:00
glGenTextures ( 1 , & drawTexture ) ;
glBindTexture ( GL_TEXTURE_2D , drawTexture ) ;
2019-02-19 22:57:42 +00:00
glTexImage2D ( GL_TEXTURE_2D , 0 , GL_RGBA , outTextureWidth , outTextureHeight , 0 , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , NULL ) ;
2010-09-25 17:35:19 +00:00
if ( pboFunctionsLoaded ) {
glGenBuffers ( 1 , & drawBuffer ) ;
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , drawBuffer ) ;
2018-05-22 19:27:40 +00:00
glBufferData ( GL_PIXEL_UNPACK_BUFFER , outTextureWidth * outTextureHeight * 2 , NULL , GL_STREAM_DRAW ) ;
2011-07-03 21:12:41 +00:00
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , 0 ) ;
2010-09-25 17:35:19 +00:00
} else {
2018-05-22 19:27:40 +00:00
noPboBuffer = new BYTE [ outTextureWidth * outTextureHeight * 2 ] ;
2010-09-25 17:35:19 +00:00
}
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_S , GL_CLAMP_TO_BORDER ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_WRAP_T , GL_CLAMP_TO_BORDER ) ;
}
}
void COpenGL : : DestroyDrawSurface ( )
{
if ( drawTexture ) {
glDeleteTextures ( 1 , & drawTexture ) ;
drawTexture = NULL ;
}
if ( drawBuffer ) {
glDeleteBuffers ( 1 , & drawBuffer ) ;
drawBuffer = NULL ;
}
if ( noPboBuffer ) {
delete [ ] noPboBuffer ;
noPboBuffer = NULL ;
}
}
2018-05-22 19:27:40 +00:00
bool COpenGL : : ChangeDrawSurfaceSize ( unsigned int width , unsigned int height )
2010-09-25 17:35:19 +00:00
{
DestroyDrawSurface ( ) ;
2018-05-22 19:27:40 +00:00
CreateDrawSurface ( width , height ) ;
2010-09-25 17:35:19 +00:00
SetupVertices ( ) ;
return true ;
}
void COpenGL : : SetupVertices ( )
{
vertices [ 0 ] = 0.0f ;
vertices [ 1 ] = 0.0f ;
vertices [ 2 ] = 1.0f ;
vertices [ 3 ] = 0.0f ;
vertices [ 4 ] = 1.0f ;
vertices [ 5 ] = 1.0f ;
vertices [ 6 ] = 0.0f ;
vertices [ 7 ] = 1.0f ;
2018-05-22 19:27:40 +00:00
float tX = ( float ) afterRenderWidth / ( float ) outTextureWidth ;
float tY = ( float ) afterRenderHeight / ( float ) outTextureHeight ;
2010-09-25 17:35:19 +00:00
texcoords [ 0 ] = 0.0f ;
texcoords [ 1 ] = tY ;
texcoords [ 2 ] = tX ;
texcoords [ 3 ] = tY ;
texcoords [ 4 ] = tX ;
texcoords [ 5 ] = 0.0f ;
texcoords [ 6 ] = 0.0f ;
texcoords [ 7 ] = 0.0f ;
2011-07-02 02:25:13 +00:00
glTexCoordPointer ( 2 , GL_FLOAT , 0 , texcoords ) ;
2010-09-25 17:35:19 +00:00
}
2018-05-22 19:27:40 +00:00
void wOGLViewportCallback ( int source_width , int source_height ,
int viewport_x , int viewport_y ,
int viewport_width , int viewport_height ,
int * out_dst_x , int * out_dst_y ,
int * out_dst_width , int * out_dst_height )
{
/* get window size here instead of using viewport passed in - we limited the viewport before the glsl render
call already , this is simply to position smaller outputs correctly in the actual viewport
*/
RECT windowSize ;
GetClientRect ( GUI . hWnd , & windowSize ) ;
RECT displayRect = CalculateDisplayRect ( source_width , source_height , windowSize . right , windowSize . bottom ) ;
* out_dst_x = displayRect . left ;
* out_dst_y = displayRect . top ;
* out_dst_width = displayRect . right - displayRect . left ;
* out_dst_height = displayRect . bottom - displayRect . top ;
}
2010-09-25 17:35:19 +00:00
void COpenGL : : Render ( SSurface Src )
{
SSurface Dst ;
RECT dstRect ;
unsigned int newFilterScale ;
GLenum error ;
if ( ! initDone ) return ;
//create a new draw surface if the filter scale changes
2018-05-22 19:27:40 +00:00
dstRect = GetFilterOutputSize ( Src ) ;
if ( outTextureWidth ! = dstRect . right | | outTextureHeight ! = dstRect . bottom )
ChangeDrawSurfaceSize ( dstRect . right , dstRect . bottom ) ;
2010-09-25 17:35:19 +00:00
if ( pboFunctionsLoaded ) {
2011-07-02 02:25:13 +00:00
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , drawBuffer ) ;
2019-02-19 22:57:42 +00:00
Dst . Surface = ( unsigned char * ) glMapBuffer ( GL_PIXEL_UNPACK_BUFFER , GL_WRITE_ONLY ) ;
2010-09-25 17:35:19 +00:00
} else {
Dst . Surface = noPboBuffer ;
}
2018-05-22 19:27:40 +00:00
Dst . Height = outTextureHeight ;
Dst . Width = outTextureWidth ;
Dst . Pitch = outTextureWidth * 2 ;
2010-09-25 17:35:19 +00:00
RenderMethod ( Src , Dst , & dstRect ) ;
if ( pboFunctionsLoaded )
glUnmapBuffer ( GL_PIXEL_UNPACK_BUFFER ) ;
if ( afterRenderHeight ! = dstRect . bottom | | afterRenderWidth ! = dstRect . right ) {
afterRenderHeight = dstRect . bottom ;
afterRenderWidth = dstRect . right ;
2011-07-03 18:42:28 +00:00
2011-07-03 21:12:41 +00:00
ChangeRenderSize ( 0 , 0 ) ;
2010-09-25 17:35:19 +00:00
}
2011-07-02 02:25:13 +00:00
glBindTexture ( GL_TEXTURE_2D , drawTexture ) ;
2018-05-22 19:27:40 +00:00
glPixelStorei ( GL_UNPACK_ROW_LENGTH , outTextureWidth ) ;
2011-07-02 02:25:13 +00:00
glTexSubImage2D ( GL_TEXTURE_2D , 0 , 0 , 0 , dstRect . right - dstRect . left , dstRect . bottom - dstRect . top , GL_RGB , GL_UNSIGNED_SHORT_5_6_5 , pboFunctionsLoaded ? 0 : noPboBuffer ) ;
if ( pboFunctionsLoaded )
glBindBuffer ( GL_PIXEL_UNPACK_BUFFER , 0 ) ;
2010-09-25 17:35:19 +00:00
2018-05-21 18:39:11 +00:00
RECT windowSize , displayRect ;
GetClientRect ( hWnd , & windowSize ) ;
//Get maximum rect respecting AR setting
2018-06-12 22:50:24 +00:00
displayRect = CalculateDisplayRect ( afterRenderWidth , afterRenderHeight , windowSize . right , windowSize . bottom ) ;
2018-05-21 18:39:11 +00:00
2018-05-22 19:43:51 +00:00
// GLSL class does all the rendering, no output needed
2018-05-21 18:39:11 +00:00
if ( shader_type = = OGL_SHADER_GLSL ) {
2018-05-22 19:27:40 +00:00
glslShader - > render ( drawTexture , afterRenderWidth , afterRenderHeight , displayRect . left , displayRect . top , displayRect . right - displayRect . left , displayRect . bottom - displayRect . top , wOGLViewportCallback ) ;
2018-05-21 18:39:11 +00:00
}
2018-05-22 19:43:51 +00:00
else { // for CG shaders and old style .shader files the last pass is done here, same as no shader
2018-05-21 18:39:11 +00:00
if ( shader_type = = OGL_SHADER_CG ) {
2011-07-02 02:25:13 +00:00
xySize inputSize = { ( float ) afterRenderWidth , ( float ) afterRenderHeight } ;
xySize xywindowSize = { ( double ) windowSize . right , ( double ) windowSize . bottom } ;
xySize viewportSize = { ( double ) ( displayRect . right - displayRect . left ) ,
( double ) ( displayRect . bottom - displayRect . top ) } ;
2018-05-22 19:27:40 +00:00
xySize textureSize = { ( double ) outTextureWidth , ( double ) outTextureHeight } ;
2011-07-02 02:25:13 +00:00
cgShader - > Render ( drawTexture , textureSize , inputSize , viewportSize , xywindowSize ) ;
2011-02-24 00:26:42 +00:00
}
2018-05-22 19:43:51 +00:00
else if ( shader_type = = OGL_SHADER_GLSL_OLD ) {
GLint location ;
float inputSize [ 2 ] = { ( float ) afterRenderWidth , ( float ) afterRenderHeight } ;
float outputSize [ 2 ] = { ( float ) ( GUI . Stretch ? windowSize . right : afterRenderWidth ) ,
( float ) ( GUI . Stretch ? windowSize . bottom : afterRenderHeight ) } ;
float textureSize [ 2 ] = { ( float ) outTextureWidth , ( float ) outTextureHeight } ;
float frameCnt = ( float ) + + frameCount ;
location = glGetUniformLocation ( shaderProgram , " rubyInputSize " ) ;
glUniform2fv ( location , 1 , inputSize ) ;
location = glGetUniformLocation ( shaderProgram , " rubyOutputSize " ) ;
glUniform2fv ( location , 1 , outputSize ) ;
location = glGetUniformLocation ( shaderProgram , " rubyTextureSize " ) ;
glUniform2fv ( location , 1 , textureSize ) ;
}
2018-05-21 18:39:11 +00:00
if ( Settings . BilinearFilter ) {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_LINEAR ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_LINEAR ) ;
}
else {
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MAG_FILTER , GL_NEAREST ) ;
glTexParameteri ( GL_TEXTURE_2D , GL_TEXTURE_MIN_FILTER , GL_NEAREST ) ;
}
2010-09-25 17:35:19 +00:00
2018-05-21 18:39:11 +00:00
glClearColor ( 0.0f , 0.0f , 0.0f , 0.5f ) ;
glClear ( GL_COLOR_BUFFER_BIT ) ;
glDrawArrays ( GL_QUADS , 0 , 4 ) ;
}
2010-09-25 17:35:19 +00:00
glFlush ( ) ;
2023-02-23 23:20:35 +00:00
2023-05-04 22:36:36 +00:00
if ( S9xImGuiRunning ( ) )
{
ImGui_ImplOpenGL3_NewFrame ( ) ;
if ( S9xImGuiDraw ( windowSize . right , windowSize . bottom ) )
{
auto * draw_data = ImGui : : GetDrawData ( ) ;
ImGui_ImplOpenGL3_RenderDrawData ( draw_data ) ;
}
}
2023-02-23 23:20:35 +00:00
WinThrottleFramerate ( ) ;
2010-09-25 17:35:19 +00:00
SwapBuffers ( hDC ) ;
2018-05-05 21:31:54 +00:00
if ( GUI . ReduceInputLag )
glFinish ( ) ;
2010-09-25 17:35:19 +00:00
}
bool COpenGL : : ChangeRenderSize ( unsigned int newWidth , unsigned int newHeight )
{
2011-07-03 21:12:41 +00:00
RECT displayRect , windowSize ;
if ( newWidth = = 0 | | newHeight = = 0 ) {
GetClientRect ( hWnd , & windowSize ) ;
newWidth = windowSize . right ;
newHeight = windowSize . bottom ;
}
displayRect = CalculateDisplayRect ( afterRenderWidth , afterRenderHeight , newWidth , newHeight ) ;
2010-09-25 17:35:19 +00:00
glViewport ( displayRect . left , newHeight - displayRect . bottom , displayRect . right - displayRect . left , displayRect . bottom - displayRect . top ) ;
SetupVertices ( ) ;
return true ;
}
2019-03-05 20:25:50 +00:00
void COpenGL : : SetSwapInterval ( int frames )
{
if ( wglSwapIntervalEXT )
wglSwapIntervalEXT ( frames ) ;
}
2023-03-11 20:49:10 +00:00
std : : vector < ShaderParam > * COpenGL : : GetShaderParameters ( void )
2023-02-01 20:47:42 +00:00
{
if ( shader_type = = OGL_SHADER_GLSL & & initDone )
2023-03-11 20:49:10 +00:00
{
// GLSLParam currently equal ShaderParam, so no conversion is neccessary
return ( std : : vector < ShaderParam > * ) & glslShader - > param ;
}
2023-02-01 20:47:42 +00:00
return nullptr ;
}
std : : function < void ( const char * ) > COpenGL : : GetShaderParametersSaveFunction ( )
{
return [ & ] ( const char * filename ) {
this - > glslShader - > save ( filename ) ;
} ;
}
2010-09-25 17:35:19 +00:00
bool COpenGL : : ApplyDisplayChanges ( void )
{
if ( wglSwapIntervalEXT ) {
wglSwapIntervalEXT ( GUI . Vsync ? 1 : 0 ) ;
}
2011-02-24 00:26:42 +00:00
if ( GUI . shaderEnabled & & GUI . OGLshaderFileName )
SetShaders ( GUI . OGLshaderFileName ) ;
2010-09-25 17:35:19 +00:00
else
2010-10-22 19:51:50 +00:00
SetShaders ( NULL ) ;
2010-09-25 17:35:19 +00:00
2011-07-03 21:12:41 +00:00
ChangeRenderSize ( 0 , 0 ) ;
2010-09-25 17:35:19 +00:00
return true ;
}
bool COpenGL : : SetFullscreen ( bool fullscreen )
{
if ( ! initDone )
return false ;
if ( this - > fullscreen = = fullscreen )
return true ;
this - > fullscreen = fullscreen ;
if ( fullscreen ) {
DEVMODE dmScreenSettings = { 0 } ;
dmScreenSettings . dmSize = sizeof ( dmScreenSettings ) ;
dmScreenSettings . dmPelsWidth = GUI . FullscreenMode . width ;
dmScreenSettings . dmPelsHeight = GUI . FullscreenMode . height ;
dmScreenSettings . dmBitsPerPel = GUI . FullscreenMode . depth ;
dmScreenSettings . dmDisplayFrequency = GUI . FullscreenMode . rate ;
dmScreenSettings . dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT | DM_DISPLAYFREQUENCY ;
if ( ChangeDisplaySettings ( & dmScreenSettings , CDS_FULLSCREEN ) ! = DISP_CHANGE_SUCCESSFUL ) {
this - > fullscreen = false ;
return false ;
}
ChangeRenderSize ( GUI . FullscreenMode . width , GUI . FullscreenMode . height ) ;
} else {
ChangeDisplaySettings ( NULL , 0 ) ;
}
2023-02-23 01:14:05 +00:00
2010-09-25 17:35:19 +00:00
return true ;
}
void COpenGL : : SetSnes9xColorFormat ( )
{
GUI . ScreenDepth = 16 ;
GUI . BlueShift = 0 ;
GUI . GreenShift = 6 ;
GUI . RedShift = 11 ;
S9xBlit2xSaIFilterInit ( ) ;
S9xBlitHQ2xFilterInit ( ) ;
GUI . NeedDepthConvert = FALSE ;
GUI . DepthConverted = TRUE ;
return ;
}
void COpenGL : : EnumModes ( std : : vector < dMode > * modeVector )
{
DISPLAY_DEVICE dd ;
dd . cb = sizeof ( dd ) ;
DWORD dev = 0 ;
int iMode = 0 ;
dMode mode ;
while ( EnumDisplayDevices ( 0 , dev , & dd , 0 ) )
{
if ( ! ( dd . StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER ) & & ( dd . StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE ) )
{
DEVMODE dm ;
2012-01-23 17:12:47 +00:00
memset ( & dm , 0 , sizeof ( dm ) ) ;
2010-09-25 17:35:19 +00:00
dm . dmSize = sizeof ( dm ) ;
iMode = 0 ;
while ( EnumDisplaySettings ( dd . DeviceName , iMode , & dm ) ) {
if ( dm . dmBitsPerPel > = 16 ) {
mode . width = dm . dmPelsWidth ;
mode . height = dm . dmPelsHeight ;
mode . rate = dm . dmDisplayFrequency ;
mode . depth = dm . dmBitsPerPel ;
modeVector - > push_back ( mode ) ;
}
iMode + + ;
}
}
dev + + ;
}
}
bool COpenGL : : LoadPBOFunctions ( )
{
2011-05-08 01:39:25 +00:00
if ( GUI . OGLdisablePBOs )
return false ;
2010-09-25 17:35:19 +00:00
if ( pboFunctionsLoaded )
return true ;
const char * extensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
if ( extensions & & strstr ( extensions , " pixel_buffer_object " ) ) {
if ( glGenBuffers & & glBindBuffer & & glBufferData & & glDeleteBuffers & & glMapBuffer ) {
pboFunctionsLoaded = true ;
}
2023-02-23 01:14:05 +00:00
2010-09-25 17:35:19 +00:00
}
return pboFunctionsLoaded ;
}
bool COpenGL : : LoadShaderFunctions ( )
{
if ( shaderFunctionsLoaded )
return true ;
const char * extensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
if ( extensions & & strstr ( extensions , " fragment_program " ) ) {
if ( glCreateProgram & &
glCreateShader & &
glCompileShader & &
glDeleteShader & &
glDeleteProgram & &
glAttachShader & &
glDetachShader & &
glLinkProgram & &
glUseProgram & &
glShaderSource & &
glGetUniformLocation & &
glUniform2fv ) {
shaderFunctionsLoaded = true ;
}
}
return shaderFunctionsLoaded ;
}
2011-02-24 00:26:42 +00:00
bool COpenGL : : SetShaders ( const TCHAR * file )
{
2019-01-31 23:07:09 +00:00
if ( file & & lstrcmp ( file , currentShaderFile ) = = 0 )
return true ;
2011-02-24 00:26:42 +00:00
SetShadersCG ( NULL ) ;
SetShadersGLSL ( NULL ) ;
2018-05-22 19:43:51 +00:00
SetShadersGLSL_OLD ( NULL ) ;
2011-02-24 00:26:42 +00:00
shader_type = OGL_SHADER_NONE ;
2019-01-31 23:07:09 +00:00
if ( file ) {
lstrcpy ( currentShaderFile , file ) ;
if ( ( lstrlen ( file ) > 3 & & _tcsncicmp ( & file [ lstrlen ( file ) - 3 ] , TEXT ( " .cg " ) , 3 ) = = 0 ) | |
( lstrlen ( file ) > 4 & & _tcsncicmp ( & file [ lstrlen ( file ) - 4 ] , TEXT ( " .cgp " ) , 4 ) = = 0 ) ) {
return SetShadersCG ( file ) ;
}
else if ( ( lstrlen ( file ) > 7 & & _tcsncicmp ( & file [ lstrlen ( file ) - 7 ] , TEXT ( " .shader " ) , 7 ) = = 0 ) ) {
return SetShadersGLSL_OLD ( file ) ;
}
else {
return SetShadersGLSL ( file ) ;
}
2011-02-24 00:26:42 +00:00
}
2019-01-31 23:07:09 +00:00
* currentShaderFile = _T ( ' \0 ' ) ;
return true ;
2011-02-24 00:26:42 +00:00
}
2011-03-04 01:11:36 +00:00
void COpenGL : : checkForCgError ( const char * situation )
{
char buffer [ 4096 ] ;
CGerror error = cgGetError ( ) ;
const char * string = cgGetErrorString ( error ) ;
if ( error ! = CG_NO_ERROR ) {
sprintf ( buffer ,
" Situation: %s \n "
" Error: %s \n \n "
" Cg compiler output... \n " , situation , string ) ;
MessageBoxA ( 0 , buffer ,
" Cg error " , MB_OK | MB_ICONEXCLAMATION ) ;
if ( error = = CG_COMPILER_ERROR ) {
MessageBoxA ( 0 , cgGetLastListing ( cgContext ) ,
" Cg compilation error " , MB_OK | MB_ICONEXCLAMATION ) ;
}
}
}
2011-02-24 00:26:42 +00:00
bool COpenGL : : SetShadersCG ( const TCHAR * file )
2010-09-25 17:35:19 +00:00
{
2011-03-20 22:21:12 +00:00
if ( ! cgAvailable ) {
2011-09-09 21:52:35 +00:00
if ( file )
MessageBox ( NULL , TEXT ( " The CG runtime is unavailable, CG shaders will not run. \n Consult the snes9x readme for information on how to obtain the runtime. " ) , TEXT ( " CG Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
2011-03-20 22:21:12 +00:00
return false ;
}
2011-07-02 02:25:13 +00:00
if ( ! cgShader - > LoadShader ( file ) )
2011-02-24 00:26:42 +00:00
return false ;
shader_type = OGL_SHADER_CG ;
return true ;
2010-09-25 17:35:19 +00:00
}
2011-02-24 00:26:42 +00:00
bool COpenGL : : SetShadersGLSL ( const TCHAR * glslFileName )
2010-09-25 17:35:19 +00:00
{
2018-05-22 19:43:51 +00:00
if ( ! glslShader )
return false ;
glslShader - > destroy ( ) ;
if ( ! glslFileName )
2010-09-25 17:35:19 +00:00
return false ;
2018-05-24 14:14:50 +00:00
if ( ! glslShader - > load_shader ( _tToChar ( glslFileName ) ) ) {
return false ;
}
2010-10-22 19:51:50 +00:00
2018-05-20 17:48:38 +00:00
shader_type = OGL_SHADER_GLSL ;
2010-11-13 19:41:38 +00:00
2018-05-20 17:48:38 +00:00
return true ;
}
2010-10-22 19:51:50 +00:00
2018-05-22 19:43:51 +00:00
bool COpenGL : : SetShadersGLSL_OLD ( const TCHAR * glslFileName )
{
char * fragment = NULL , * vertex = NULL ;
IXMLDOMDocument * pXMLDoc = NULL ;
IXMLDOMElement * pXDE = NULL ;
IXMLDOMNode * pXDN = NULL ;
HRESULT hr ;
BSTR queryString , nodeContent ;
TCHAR errorMsg [ MAX_PATH + 50 ] ;
if ( fragmentShader ) {
glDetachShader ( shaderProgram , fragmentShader ) ;
glDeleteShader ( fragmentShader ) ;
fragmentShader = 0 ;
}
if ( vertexShader ) {
glDetachShader ( shaderProgram , vertexShader ) ;
glDeleteShader ( vertexShader ) ;
vertexShader = 0 ;
}
if ( shaderProgram ) {
glUseProgram ( 0 ) ;
glDeleteProgram ( shaderProgram ) ;
shaderProgram = 0 ;
}
if ( glslFileName = = NULL | | * glslFileName = = TEXT ( ' \0 ' ) )
return true ;
if ( ! LoadShaderFunctions ( ) ) {
MessageBox ( NULL , TEXT ( " Unable to load OpenGL shader functions " ) , TEXT ( " Shader Loading Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
hr = CoCreateInstance ( CLSID_DOMDocument , NULL , CLSCTX_INPROC_SERVER , IID_PPV_ARGS ( & pXMLDoc ) ) ;
if ( FAILED ( hr ) ) {
MessageBox ( NULL , TEXT ( " Error creating XML Parser " ) , TEXT ( " Shader Loading Error " ) ,
MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
VARIANT fileName ;
VARIANT_BOOL ret ;
fileName . vt = VT_BSTR ;
# ifdef UNICODE
fileName . bstrVal = SysAllocString ( glslFileName ) ;
# else
wchar_t tempfilename [ MAX_PATH ] ;
MultiByteToWideChar ( CP_UTF8 , 0 , glslFileName , - 1 , tempfilename , MAX_PATH ) ;
fileName . bstrVal = SysAllocString ( tempfilename ) ;
# endif
hr = pXMLDoc - > load ( fileName , & ret ) ;
SysFreeString ( fileName . bstrVal ) ;
if ( FAILED ( hr ) | | hr = = S_FALSE ) {
_stprintf ( errorMsg , TEXT ( " Error loading GLSL shader file: \n %s " ) , glslFileName ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
VARIANT attributeValue ;
BSTR attributeName ;
hr = pXMLDoc - > get_documentElement ( & pXDE ) ;
if ( FAILED ( hr ) | | hr = = S_FALSE ) {
_stprintf ( errorMsg , TEXT ( " Error loading root element from file: \n %s " ) , glslFileName ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
attributeName = SysAllocString ( L " language " ) ;
pXDE - > getAttribute ( attributeName , & attributeValue ) ;
SysFreeString ( attributeName ) ;
pXDE - > Release ( ) ;
if ( attributeValue . vt ! = VT_BSTR | | lstrcmpiW ( attributeValue . bstrVal , L " glsl " ) ) {
_stprintf ( errorMsg , TEXT ( " Shader language is <%s>, expected <GLSL> in file: \n %s " ) , attributeValue . bstrVal , glslFileName ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
if ( attributeValue . vt = = VT_BSTR ) SysFreeString ( attributeValue . bstrVal ) ;
pXMLDoc - > Release ( ) ;
return false ;
}
if ( attributeValue . vt = = VT_BSTR ) SysFreeString ( attributeValue . bstrVal ) ;
queryString = SysAllocString ( L " /shader/fragment " ) ;
hr = pXMLDoc - > selectSingleNode ( queryString , & pXDN ) ;
SysFreeString ( queryString ) ;
if ( hr = = S_OK ) {
hr = pXDN - > get_text ( & nodeContent ) ;
if ( hr = = S_OK ) {
int requiredChars = WideCharToMultiByte ( CP_ACP , 0 , nodeContent , - 1 , fragment , 0 , NULL , NULL ) ;
fragment = new char [ requiredChars ] ;
WideCharToMultiByte ( CP_UTF8 , 0 , nodeContent , - 1 , fragment , requiredChars , NULL , NULL ) ;
}
SysFreeString ( nodeContent ) ;
pXDN - > Release ( ) ;
pXDN = NULL ;
}
queryString = SysAllocString ( L " /shader/vertex " ) ;
hr = pXMLDoc - > selectSingleNode ( queryString , & pXDN ) ;
SysFreeString ( queryString ) ;
if ( hr = = S_OK ) {
hr = pXDN - > get_text ( & nodeContent ) ;
if ( hr = = S_OK ) {
int requiredChars = WideCharToMultiByte ( CP_ACP , 0 , nodeContent , - 1 , vertex , 0 , NULL , NULL ) ;
vertex = new char [ requiredChars ] ;
WideCharToMultiByte ( CP_UTF8 , 0 , nodeContent , - 1 , vertex , requiredChars , NULL , NULL ) ;
}
SysFreeString ( nodeContent ) ;
pXDN - > Release ( ) ;
pXDN = NULL ;
}
pXMLDoc - > Release ( ) ;
if ( ! fragment & & ! vertex ) {
_stprintf ( errorMsg , TEXT ( " No vertex or fragment program in file: \n %s " ) , glslFileName ) ;
MessageBox ( NULL , errorMsg , TEXT ( " Shader Loading Error " ) , MB_OK | MB_ICONEXCLAMATION ) ;
return false ;
}
shaderProgram = glCreateProgram ( ) ;
if ( vertex ) {
vertexShader = glCreateShader ( GL_VERTEX_SHADER ) ;
glShaderSource ( vertexShader , 1 , ( const GLchar * * ) & vertex , NULL ) ;
glCompileShader ( vertexShader ) ;
glAttachShader ( shaderProgram , vertexShader ) ;
delete [ ] vertex ;
}
if ( fragment ) {
fragmentShader = glCreateShader ( GL_FRAGMENT_SHADER ) ;
glShaderSource ( fragmentShader , 1 , ( const GLchar * * ) & fragment , NULL ) ;
glCompileShader ( fragmentShader ) ;
glAttachShader ( shaderProgram , fragmentShader ) ;
delete [ ] fragment ;
}
glLinkProgram ( shaderProgram ) ;
glUseProgram ( shaderProgram ) ;
shader_type = OGL_SHADER_GLSL_OLD ;
return true ;
}
2019-02-19 22:57:42 +00:00
bool COpenGL : : ShaderAvailable ( )
2018-05-20 17:48:38 +00:00
{
const char * extensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
2010-11-13 19:41:38 +00:00
2018-05-20 17:48:38 +00:00
if ( ! extensions )
return false ;
2010-09-25 17:35:19 +00:00
2018-05-20 17:48:38 +00:00
if ( strstr ( extensions , " fragment_program " ) | |
strstr ( extensions , " fragment_shader " ) )
{
return true ;
}
2010-10-22 19:51:50 +00:00
2018-05-20 17:48:38 +00:00
return false ;
}
2010-10-22 19:51:50 +00:00
2018-05-20 17:48:38 +00:00
bool COpenGL : : NPOTAvailable ( )
{
const char * extensions = ( const char * ) glGetString ( GL_EXTENSIONS ) ;
2018-05-28 23:40:29 +00:00
const char * version = ( const char * ) glGetString ( GL_VERSION ) ;
2010-10-22 19:51:50 +00:00
2018-05-20 17:48:38 +00:00
if ( ! extensions )
return false ;
2010-09-25 17:35:19 +00:00
2018-05-20 17:48:38 +00:00
int glVersionMajor = 0 ;
2018-05-28 23:40:29 +00:00
glVersionMajor = atoi ( version ) ;
2010-09-25 17:35:19 +00:00
2018-05-20 17:48:38 +00:00
if ( glVersionMajor > = 2 )
return true ;
2010-09-25 17:35:19 +00:00
2018-05-20 17:48:38 +00:00
if ( strstr ( extensions , " non_power_of_two " ) | |
strstr ( extensions , " npot " ) )
{
return true ;
}
2010-09-25 17:35:19 +00:00
2018-05-20 17:48:38 +00:00
return false ;
2010-09-25 17:35:19 +00:00
}