mirror of
https://github.com/ZDoom/gzdoom-gles.git
synced 2024-12-16 23:31:10 +00:00
467 lines
12 KiB
C++
467 lines
12 KiB
C++
/*
|
|
** sdlglvideo.cpp
|
|
**
|
|
**---------------------------------------------------------------------------
|
|
** Copyright 2005-2016 Christoph Oelckers et.al.
|
|
** All rights reserved.
|
|
**
|
|
** Redistribution and use in source and binary forms, with or without
|
|
** modification, are permitted provided that the following conditions
|
|
** are met:
|
|
**
|
|
** 1. Redistributions of source code must retain the above copyright
|
|
** notice, this list of conditions and the following disclaimer.
|
|
** 2. Redistributions in binary form must reproduce the above copyright
|
|
** notice, this list of conditions and the following disclaimer in the
|
|
** documentation and/or other materials provided with the distribution.
|
|
** 3. The name of the author may not be used to endorse or promote products
|
|
** derived from this software without specific prior written permission.
|
|
**
|
|
** THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
|
** IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
** OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
|
** IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
** INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
|
** NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
|
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
|
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
|
** THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
**---------------------------------------------------------------------------
|
|
**
|
|
*/
|
|
|
|
// HEADER FILES ------------------------------------------------------------
|
|
|
|
#include "doomtype.h"
|
|
|
|
#include "templates.h"
|
|
#include "i_system.h"
|
|
#include "i_video.h"
|
|
#include "m_argv.h"
|
|
#include "v_video.h"
|
|
#include "v_pfx.h"
|
|
#include "stats.h"
|
|
#include "version.h"
|
|
#include "c_console.h"
|
|
|
|
#include "videomodes.h"
|
|
#include "sdlglvideo.h"
|
|
#include "gl/system/gl_system.h"
|
|
#include "r_defs.h"
|
|
#include "gl/gl_functions.h"
|
|
//#include "gl/gl_intern.h"
|
|
|
|
#include "gl/renderer/gl_renderer.h"
|
|
#include "gl/system/gl_framebuffer.h"
|
|
#include "gl/shaders/gl_shader.h"
|
|
#include "gl/utility/gl_templates.h"
|
|
#include "gl/textures/gl_material.h"
|
|
#include "gl/system/gl_cvars.h"
|
|
|
|
// MACROS ------------------------------------------------------------------
|
|
|
|
// TYPES -------------------------------------------------------------------
|
|
|
|
// PUBLIC FUNCTION PROTOTYPES ----------------------------------------------
|
|
|
|
// PRIVATE FUNCTION PROTOTYPES ---------------------------------------------
|
|
|
|
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
|
|
|
|
extern IVideo *Video;
|
|
// extern int vid_renderer;
|
|
|
|
EXTERN_CVAR (Float, Gamma)
|
|
EXTERN_CVAR (Int, vid_adapter)
|
|
EXTERN_CVAR (Int, vid_displaybits)
|
|
EXTERN_CVAR (Int, vid_renderer)
|
|
EXTERN_CVAR (Int, vid_maxfps)
|
|
EXTERN_CVAR (Bool, cl_capfps)
|
|
|
|
DFrameBuffer *CreateGLSWFrameBuffer(int width, int height, bool bgra, bool fullscreen);
|
|
|
|
// PUBLIC DATA DEFINITIONS -------------------------------------------------
|
|
|
|
CUSTOM_CVAR(Bool, gl_debug, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
|
{
|
|
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
|
}
|
|
#ifdef __arm__
|
|
CUSTOM_CVAR(Bool, gl_es, false, CVAR_NOINITCALL)
|
|
{
|
|
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
|
}
|
|
#else
|
|
CUSTOM_CVAR(Bool, gl_es, false, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
|
|
{
|
|
Printf("This won't take effect until " GAMENAME " is restarted.\n");
|
|
}
|
|
#endif
|
|
|
|
// PRIVATE DATA DEFINITIONS ------------------------------------------------
|
|
|
|
// CODE --------------------------------------------------------------------
|
|
|
|
SDLGLVideo::SDLGLVideo (int parm)
|
|
{
|
|
IteratorBits = 0;
|
|
if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) {
|
|
fprintf( stderr, "Video initialization failed: %s\n",
|
|
SDL_GetError( ) );
|
|
}
|
|
}
|
|
|
|
SDLGLVideo::~SDLGLVideo ()
|
|
{
|
|
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
|
}
|
|
|
|
void SDLGLVideo::StartModeIterator (int bits, bool fs)
|
|
{
|
|
IteratorMode = 0;
|
|
IteratorBits = bits;
|
|
}
|
|
|
|
bool SDLGLVideo::NextMode (int *width, int *height, bool *letterbox)
|
|
{
|
|
if (IteratorBits != 8)
|
|
return false;
|
|
|
|
if ((unsigned)IteratorMode < sizeof(VideoModes)/sizeof(VideoModes[0]))
|
|
{
|
|
*width = VideoModes[IteratorMode].width;
|
|
*height = VideoModes[IteratorMode].height;
|
|
++IteratorMode;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
DFrameBuffer *SDLGLVideo::CreateFrameBuffer (int width, int height, bool bgra, bool fullscreen, DFrameBuffer *old)
|
|
{
|
|
static int retry = 0;
|
|
static int owidth, oheight;
|
|
|
|
PalEntry flashColor;
|
|
// int flashAmount;
|
|
|
|
if (old != NULL)
|
|
{ // Reuse the old framebuffer if its attributes are the same
|
|
SDLBaseFB *fb = static_cast<SDLBaseFB *> (old);
|
|
if (fb->Width == width &&
|
|
fb->Height == height)
|
|
{
|
|
bool fsnow = (SDL_GetWindowFlags (fb->GetSDLWindow()) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
|
|
|
if (fsnow != fullscreen)
|
|
{
|
|
SDL_SetWindowFullscreen (fb->GetSDLWindow(), fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
|
|
}
|
|
return old;
|
|
}
|
|
// old->GetFlash (flashColor, flashAmount);
|
|
delete old;
|
|
}
|
|
else
|
|
{
|
|
flashColor = 0;
|
|
// flashAmount = 0;
|
|
}
|
|
|
|
SDLBaseFB *fb;
|
|
fb = new OpenGLFrameBuffer(0, width, height, 32, 60, fullscreen);
|
|
|
|
retry = 0;
|
|
|
|
// If we could not create the framebuffer, try again with slightly
|
|
// different parameters in this order:
|
|
// 1. Try with the closest size
|
|
// 2. Try in the opposite screen mode with the original size
|
|
// 3. Try in the opposite screen mode with the closest size
|
|
// This is a somewhat confusing mass of recursion here.
|
|
|
|
while (fb == NULL)
|
|
{
|
|
switch (retry)
|
|
{
|
|
case 0:
|
|
owidth = width;
|
|
oheight = height;
|
|
case 2:
|
|
// Try a different resolution. Hopefully that will work.
|
|
I_ClosestResolution (&width, &height, 8);
|
|
break;
|
|
|
|
case 1:
|
|
// Try changing fullscreen mode. Maybe that will work.
|
|
width = owidth;
|
|
height = oheight;
|
|
fullscreen = !fullscreen;
|
|
break;
|
|
|
|
default:
|
|
// I give up!
|
|
I_FatalError ("Could not create new screen (%d x %d)", owidth, oheight);
|
|
|
|
fprintf( stderr, "!!! [SDLGLVideo::CreateFrameBuffer] Got beyond I_FatalError !!!" );
|
|
return NULL; //[C] actually this shouldn't be reached; probably should be replaced with an ASSERT
|
|
}
|
|
|
|
++retry;
|
|
fb = static_cast<SDLBaseFB *>(CreateFrameBuffer (width, height, false, fullscreen, NULL));
|
|
}
|
|
|
|
// fb->SetFlash (flashColor, flashAmount);
|
|
return fb;
|
|
}
|
|
|
|
void SDLGLVideo::SetWindowedScale (float scale)
|
|
{
|
|
}
|
|
|
|
bool SDLGLVideo::SetResolution (int width, int height, int bits)
|
|
{
|
|
// FIXME: Is it possible to do this without completely destroying the old
|
|
// interface?
|
|
#ifndef NO_GL
|
|
|
|
if (GLRenderer != NULL) GLRenderer->FlushTextures();
|
|
I_ShutdownGraphics();
|
|
|
|
Video = new SDLGLVideo(0);
|
|
if (Video == NULL) I_FatalError ("Failed to initialize display");
|
|
|
|
#if (defined(WINDOWS)) || defined(WIN32)
|
|
bits=32;
|
|
#else
|
|
bits=24;
|
|
#endif
|
|
|
|
V_DoModeSetup(width, height, bits);
|
|
#endif
|
|
return true; // We must return true because the old video context no longer exists.
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
void SDLGLVideo::SetupPixelFormat(bool allowsoftware, int multisample, const int *glver)
|
|
{
|
|
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 24 );
|
|
SDL_GL_SetAttribute( SDL_GL_STENCIL_SIZE, 8 );
|
|
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
|
if (multisample > 0) {
|
|
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 );
|
|
SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, multisample );
|
|
}
|
|
if (gl_debug)
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
|
|
|
|
if (gl_es)
|
|
{
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
|
}
|
|
else if (glver[0] > 2)
|
|
{
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, glver[0]);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, glver[1]);
|
|
}
|
|
else
|
|
{
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_COMPATIBILITY);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
|
}
|
|
}
|
|
|
|
|
|
// FrameBuffer implementation -----------------------------------------------
|
|
|
|
SDLGLFB::SDLGLFB (void *, int width, int height, int, int, bool fullscreen, bool bgra)
|
|
: SDLBaseFB (width, height, bgra)
|
|
{
|
|
// NOTE: Core profiles were added with GL 3.2, so there's no sense trying
|
|
// to set core 3.1 or 3.0. We could try a forward-compatible context
|
|
// instead, but that would be too restrictive (w.r.t. shaders).
|
|
static const int glvers[][2] = {
|
|
{ 4, 5 }, { 4, 4 }, { 4, 3 }, { 4, 2 }, { 4, 1 }, { 4, 0 },
|
|
{ 3, 3 }, { 3, 2 }, { 2, 0 },
|
|
{ 0, 0 },
|
|
};
|
|
int glveridx = 0;
|
|
int i;
|
|
|
|
UpdatePending = false;
|
|
|
|
const char *version = Args->CheckValue("-glversion");
|
|
if (version != NULL)
|
|
{
|
|
double gl_version = strtod(version, NULL) + 0.01;
|
|
int vermaj = (int)gl_version;
|
|
int vermin = (int)(gl_version*10.0) % 10;
|
|
|
|
while (glvers[glveridx][0] > vermaj || (glvers[glveridx][0] == vermaj &&
|
|
glvers[glveridx][1] > vermin))
|
|
{
|
|
glveridx++;
|
|
if (glvers[glveridx][0] == 0)
|
|
{
|
|
glveridx = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
FString caption;
|
|
caption.Format(GAMESIG " %s (%s)", GetVersionString(), GetGitTime());
|
|
|
|
for ( ; glvers[glveridx][0] > 0; ++glveridx)
|
|
{
|
|
static_cast<SDLGLVideo*>(Video)->SetupPixelFormat(false, 0, glvers[glveridx]);
|
|
|
|
Screen = SDL_CreateWindow (caption,
|
|
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
|
|
SDL_WINDOWPOS_UNDEFINED_DISPLAY(vid_adapter),
|
|
width, height, (fullscreen ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0)|SDL_WINDOW_OPENGL
|
|
);
|
|
if (Screen != NULL)
|
|
{
|
|
GLContext = SDL_GL_CreateContext(Screen);
|
|
if (GLContext != NULL)
|
|
{
|
|
m_supportsGamma = -1 != SDL_GetWindowGammaRamp(Screen,
|
|
m_origGamma[0], m_origGamma[1], m_origGamma[2]
|
|
);
|
|
return;
|
|
}
|
|
|
|
SDL_DestroyWindow(Screen);
|
|
Screen = NULL;
|
|
}
|
|
}
|
|
}
|
|
|
|
SDLGLFB::~SDLGLFB ()
|
|
{
|
|
if (Screen)
|
|
{
|
|
ResetGammaTable();
|
|
|
|
if (GLContext)
|
|
{
|
|
SDL_GL_DeleteContext(GLContext);
|
|
}
|
|
|
|
SDL_DestroyWindow(Screen);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
void SDLGLFB::InitializeState()
|
|
{
|
|
}
|
|
|
|
#if 0
|
|
bool SDLGLFB::CanUpdate ()
|
|
{
|
|
if (m_Lock != 1)
|
|
{
|
|
if (m_Lock > 0)
|
|
{
|
|
UpdatePending = true;
|
|
--m_Lock;
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
void SDLGLFB::SetGammaTable(uint16_t *tbl)
|
|
{
|
|
if (m_supportsGamma)
|
|
{
|
|
SDL_SetWindowGammaRamp(Screen, &tbl[0], &tbl[256], &tbl[512]);
|
|
}
|
|
}
|
|
|
|
void SDLGLFB::ResetGammaTable()
|
|
{
|
|
if (m_supportsGamma)
|
|
{
|
|
SDL_SetWindowGammaRamp(Screen, m_origGamma[0], m_origGamma[1], m_origGamma[2]);
|
|
}
|
|
}
|
|
|
|
bool SDLGLFB::IsFullscreen ()
|
|
{
|
|
return (SDL_GetWindowFlags (Screen) & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
|
|
}
|
|
|
|
|
|
bool SDLGLFB::IsValid ()
|
|
{
|
|
return DFrameBuffer::IsValid() && Screen != NULL;
|
|
}
|
|
|
|
void SDLGLFB::SetVSync( bool vsync )
|
|
{
|
|
#if defined (__APPLE__)
|
|
const GLint value = vsync ? 1 : 0;
|
|
CGLSetParameter( CGLGetCurrentContext(), kCGLCPSwapInterval, &value );
|
|
#else
|
|
if (vsync)
|
|
{
|
|
if (SDL_GL_SetSwapInterval(-1) == -1)
|
|
SDL_GL_SetSwapInterval(1);
|
|
}
|
|
else
|
|
{
|
|
SDL_GL_SetSwapInterval(0);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void SDLGLFB::NewRefreshRate ()
|
|
{
|
|
}
|
|
|
|
void SDLGLFB::SwapBuffers()
|
|
{
|
|
#if !defined(__APPLE__) && !defined(__OpenBSD__)
|
|
if (vid_maxfps && !cl_capfps)
|
|
{
|
|
SEMAPHORE_WAIT(FPSLimitSemaphore)
|
|
}
|
|
#endif
|
|
|
|
SDL_GL_SwapWindow (Screen);
|
|
}
|
|
|
|
int SDLGLFB::GetClientWidth()
|
|
{
|
|
int width = 0;
|
|
SDL_GL_GetDrawableSize(Screen, &width, nullptr);
|
|
return width;
|
|
}
|
|
|
|
int SDLGLFB::GetClientHeight()
|
|
{
|
|
int height = 0;
|
|
SDL_GL_GetDrawableSize(Screen, nullptr, &height);
|
|
return height;
|
|
}
|
|
|