5 1 new backport x11 fs rework (#1485)

* Use XRandR 1.2 to set fullscreen resolution for single output

Squash of roothorick's PR #497
(also includes Kyzentun's CMake changes from PR #716)

* Cherry-pick json c++1x stuff (b9e3d7174e)

* Cherry-pick c++11 support from 5bba5c0038 and 9f8b045309

* rework Linux (X11) fullscreen, improve display-related Graphics Options

Implement option to select between monitors for exclusive fullscreen mode
on X11 (using XRandR 1.2), or use a fullscreen borderless window.

Reimplement resolution/refresh rate/display mode-related option rows
using Lua, update choices dynamically so only known-good groupings of
resolution/refresh rate/aspect ratio can be selected.

Minimally update Windows/MacOS LowLevelWindow implementations to support
changes made for Linux side. Fullscreen Borderless Window/multi monitor
support from X11 not implemented for those in this commit.

* allow forcibly disabling xinerama use on Linux

When libXinerama is available, SM tries to use it to find the proper
monitor indexes to use to set _NET_WM_FULLSCREEN_MONITORS (on borderless
fullscreen). xfwm4 seems to assume that monitors are numbered in increasing
order from left to right (rather than using the Xinerama-assigned numbers),
so _NET_WM_FULLSCREEN_MONITORS misbehaves on Xfce.

This commit bypasses use of libXinerama, and instead forces SM to induce fullscreen
on the desired monitor in the backup, hacky way: remove all window hints, move window
to desired monitor, then add _NET_WM_STATE_FULLSCREEN hint. This works on
mutter and Xfce.

* Remove multiple warnings on redundant define.

This used to be hard-coded due to pthread related items, but now it's dynamically determined.

* fix _fallback menu behavior for unrecognized aspect ratios

* Fix error recreating existing FS texture

* Bump deployment target to 10.7 to use libc++ on XCode 8

* Add explicit casts to please clang

* Update changelog
This commit is contained in:
Drew Barbarello
2017-06-18 08:55:16 -07:00
committed by Colby Klein
parent 7ef14c340d
commit 557be7cf1b
57 changed files with 2616 additions and 370 deletions
+73
View File
@@ -258,6 +258,79 @@ Actor::Actor( const Actor &cpy ):
#undef CPY
}
Actor &Actor::operator=(Actor other)
{
/* Don't copy an Actor in the middle of rendering. */
ASSERT( other.m_pTempState == nullptr );
m_pTempState = nullptr;
using std::swap;
#define SWAP(x) swap(x, other.x)
SWAP( m_sName );
SWAP( m_pParent );
SWAP( m_FakeParent );
SWAP( m_pLuaInstance );
SWAP( m_WrapperStates );
SWAP( m_baseRotation );
SWAP( m_baseScale );
SWAP( m_fBaseAlpha );
SWAP( m_internalDiffuse );
SWAP( m_internalGlow );
SWAP( m_size );
SWAP( m_current );
SWAP( m_start );
SWAP( m_Tweens );
SWAP( m_bFirstUpdate );
SWAP( m_fHorizAlign );
SWAP( m_fVertAlign );
#if defined(SSC_FUTURES)
SWAP( M_Effects );
#else
SWAP( m_Effect );
#endif
SWAP( m_fSecsIntoEffect );
SWAP( m_fEffectDelta );
SWAP(m_effect_ramp_to_half);
SWAP(m_effect_hold_at_half);
SWAP(m_effect_ramp_to_full);
SWAP(m_effect_hold_at_full);
SWAP(m_effect_hold_at_zero);
SWAP(m_effect_period);
SWAP( m_fEffectOffset );
SWAP( m_EffectClock );
SWAP( m_effectColor1 );
SWAP( m_effectColor2 );
SWAP( m_vEffectMagnitude );
SWAP( m_bVisible );
SWAP( m_fHibernateSecondsLeft );
SWAP( m_fShadowLengthX );
SWAP( m_fShadowLengthY );
SWAP( m_ShadowColor );
SWAP( m_bIsAnimating );
SWAP( m_iDrawOrder );
SWAP( m_bTextureWrapping );
SWAP( m_bTextureFiltering );
SWAP( m_BlendMode );
SWAP( m_bClearZBuffer );
SWAP( m_ZTestMode );
SWAP( m_bZWrite );
SWAP( m_fZBias );
SWAP( m_CullMode );
SWAP( m_mapNameToCommands );
#undef SWAP
return *this;
}
/* XXX: This calls InitCommand, which must happen after all other
* initialization (eg. ActorFrame loading children). However, it
* also loads input variables, which should happen first. The
+1
View File
@@ -111,6 +111,7 @@ public:
* @brief Copy a new Actor to the old one.
* @param cpy the new Actor to use in place of this one. */
Actor( const Actor &cpy );
Actor &operator=( Actor other );
virtual ~Actor();
virtual Actor *Copy() const;
virtual void InitState();
+2 -1
View File
@@ -167,6 +167,7 @@ list(APPEND SM_DATA_REST_SRC
"CryptHelpers.cpp"
"DateTime.cpp"
"Difficulty.cpp"
"DisplaySpec.cpp"
"EnumHelper.cpp"
"FileDownload.cpp"
"Game.cpp"
@@ -218,7 +219,7 @@ list(APPEND SM_DATA_REST_HPP
"CryptHelpers.h"
"CubicSpline.h"
"DateTime.h"
"DisplayResolutions.h"
"DisplaySpec.h"
"Difficulty.h"
"EnumHelper.h"
"FileDownload.h"
+6
View File
@@ -8,6 +8,12 @@ add_library("GtkModule"
"arch/LoadingWindow/LoadingWindow_GtkModule.h"
)
sm_add_compile_flag("GtkModule" "-std=${SM_CPP_STANDARD}")
if (CMAKE_CXX_COMPILER MATCHES "clang")
sm_add_compile_flag("GtkModule" "-stdlib=libc++")
set_target_properties("GtkModule" PROPERTIES LINK_FLAGS "-stdlib=libc++")
endif()
# It is normally not appropriate to set the prefix to the empty string.
# This is to maintain compatibility with the current source.
# At some point, it may be worth being more flexible.
+25 -8
View File
@@ -165,7 +165,7 @@ if(WIN32)
sm_add_compile_definition("${SM_EXE_NAME}" _CRT_SECURE_NO_WARNINGS)
sm_add_compile_definition("${SM_EXE_NAME}" _WINSOCK_DEPRECATED_NO_WARNINGS)
sm_add_compile_definition("${SM_EXE_NAME}" GLEW_STATIC)
set_target_properties("${SM_EXE_NAME}" PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${SM_PROGRAM_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELEASE "${SM_PROGRAM_DIR}"
@@ -173,7 +173,7 @@ if(WIN32)
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${SM_PROGRAM_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${SM_PROGRAM_DIR}"
)
if(MSVC)
# Allow for getting a virtualdub stack trace.
add_custom_command(TARGET "${SM_EXE_NAME}"
@@ -190,6 +190,8 @@ elseif(APPLE)
RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL "${SM_ROOT_DIR}"
RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO "${SM_ROOT_DIR}"
MACOSX_BUNDLE_INFO_PLIST "${SM_XCODE_DIR}/Info.StepMania.plist"
XCODE_ATTRIBUTE_CLANG_CXX_LANGUAGE_STANDARD "${SM_CPP_STANDARD}"
XCODE_ATTRIBUTE_CLANG_CXX_LIBRARY "libc++"
XCODE_ATTRIBUTE_INFOPLIST_FILE "${SM_XCODE_DIR}/Info.StepMania.plist"
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESS "YES"
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESSOR_DEFINITIONS[variant=Release] "RELEASE"
@@ -198,6 +200,7 @@ elseif(APPLE)
XCODE_ATTRIBUTE_INFOPLIST_PREPROCESSOR_DEFINITIONS[variant=RelWithDebInfo] "RELWITHDEBINFO"
XCODE_ATTRIBUTE_INFOPLIST_PREFIX_HEADER "${SM_XCODE_DIR}/plistHelper.hpp"
XCODE_ATTRIBUTE_GCC_PREFIX_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/archutils/Darwin/StepMania.pch"
XCODE_ATTRIBUTE_GCC_ENABLE_CPP_EXCEPTIONS "NO"
XCODE_ATTRIBUTE_LIBRARY_SEARCH_PATHS "${SM_XCODE_DIR}/Libraries"
)
@@ -304,6 +307,13 @@ else() # Linux
if (${HAS_FFMPEG})
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_FFMPEG)
endif()
if (${HAS_XRANDR})
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_XRANDR)
endif()
if (${HAS_XINERAMA} AND WITH_XINERAMA)
sm_add_compile_definition("${SM_EXE_NAME}" HAVE_XINERAMA)
endif()
if (BSD)
sm_add_compile_definition("${SM_EXE_NAME}" BSD)
endif()
@@ -316,6 +326,12 @@ else() # Linux
if("${CMAKE_SYSTEM}" MATCHES "Linux")
sm_add_compile_definition("${SM_EXE_NAME}" LINUX)
endif()
sm_add_compile_flag("${SM_EXE_NAME}" "-std=${SM_CPP_STANDARD}")
if (CMAKE_CXX_COMPILER MATCHES "clang")
sm_add_compile_flag("${SM_EXE_NAME}" "-stdlib=libc++")
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS "-stdlib=libc++")
endif()
endif()
set_property(TARGET "${SM_EXE_NAME}" PROPERTY FOLDER "Internal Libraries")
@@ -346,7 +362,7 @@ if (NOT SYSTEM_PCRE_FOUND)
endif()
if (WIN32)
list(APPEND SMDATA_LINK_LIB
# The misc libraries are here.
"${LIB_SWSCALE}"
@@ -354,7 +370,7 @@ if (WIN32)
"${LIB_AVFORMAT}"
"${LIB_AVUTIL}"
)
if (WITH_OGG)
list(APPEND SMDATA_LINK_LIB
"ogg"
@@ -362,15 +378,15 @@ if (WIN32)
"vorbisfile"
)
endif()
list(APPEND SMDATA_LINK_LIB
"dbghelp.lib"
"setupapi.lib"
"hid.lib"
)
get_filename_component(DIRECTX_LIBRARY_DIR "${DIRECTX_LIBRARIES}" DIRECTORY)
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${DIRECTX_LIBRARY_DIR}\"")
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${SM_EXTERN_DIR}/ffmpeg/lib\"")
sm_add_link_flag("${SM_EXE_NAME}" "/LIBPATH:\"${SM_SRC_DIR}/archutils/Win32/ddk\"")
@@ -385,7 +401,7 @@ if (WIN32)
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_DEBUG "/NODEFAULTLIB:msvcrt.lib")
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:WINDOWS")
set_target_properties("${SM_EXE_NAME}" PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:WINDOWS")
elseif(APPLE)
# The following were removed from SMDATA_LINK_LIB to "match" StepMania's pbxproj.
# ${MAC_FRAME_APPKIT}
@@ -508,6 +524,7 @@ else() # Unix / Linux
list(APPEND SMDATA_LINK_LIB
${XRANDR_LIBRARIES}
${XINERAMA_LIBRARIES}
)
list(REMOVE_ITEM SMDATA_LINK_LIB "zlib")
+149
View File
@@ -0,0 +1,149 @@
#include "global.h"
#include "DisplaySpec.h"
#include "LuaBinding.h"
#include "RageLog.h"
class LunaDisplayMode: public Luna<DisplayMode>
{
public:
DEFINE_METHOD( GetWidth, width );
DEFINE_METHOD( GetHeight, height );
DEFINE_METHOD( GetRefreshRate, refreshRate );
LunaDisplayMode()
{
ADD_METHOD( GetWidth );
ADD_METHOD( GetHeight );
ADD_METHOD( GetRefreshRate );
}
};
LUA_REGISTER_CLASS( DisplayMode )
class LunaDisplaySpec: public Luna<DisplaySpec>
{
public:
DEFINE_METHOD( GetId, id() );
DEFINE_METHOD( GetName, name() );
DEFINE_METHOD( IsVirtual, isVirtual() );
static int GetSupportedModes( T* p, lua_State *L)
{
std::vector<DisplayMode*> v;
for (auto const &m: p->supportedModes())
{
v.push_back( const_cast<DisplayMode*>(&m));
}
LuaHelpers::CreateTableFromArray( v, L );
return 1;
}
static int GetCurrentMode( T *p, lua_State *L )
{
if (p->currentMode() != NULL) {
DisplayMode *m = const_cast<DisplayMode *>( p->currentMode() );
m->PushSelf( L );
} else {
lua_pushnil( L );
}
return 1;
}
LunaDisplaySpec()
{
ADD_METHOD( GetId );
ADD_METHOD( GetName );
ADD_METHOD( GetSupportedModes );
ADD_METHOD( IsVirtual );
ADD_METHOD( GetCurrentMode );
}
};
LUA_REGISTER_CLASS( DisplaySpec )
namespace
{
const char *DISPLAYSPECS = "DisplaySpecs";
DisplaySpecs *check_DisplaySpecs(lua_State *L)
{
void *ud = luaL_checkudata( L, 1, DISPLAYSPECS );
luaL_argcheck( L, ud != NULL, 1, "`DisplaySpecs` expected" );
return static_cast<DisplaySpecs *>(ud);
}
int DisplaySpecs_gc(lua_State *L)
{
DisplaySpecs *specs = static_cast<DisplaySpecs *> (lua_touserdata( L, 1 ));
if (specs)
{
specs->~DisplaySpecs();
}
return 0;
}
int DisplaySpecs_len(lua_State *L)
{
DisplaySpecs *specs = check_DisplaySpecs( L );
if (specs)
{
lua_pushinteger( L, specs->size() );
} else
{
lua_pushinteger( L, 0 );
}
return 1;
}
int DisplaySpecs_tostring(lua_State *L)
{
DisplaySpecs *specs = check_DisplaySpecs( L );
lua_pushfstring( L, "DisplaySpecs: %p", specs );
return 1;
}
int DisplaySpecs_get(lua_State *L)
{
DisplaySpecs *specs = check_DisplaySpecs( L );
if (specs)
{
int index = luaL_checkint( L, 2 );
luaL_argcheck( L, 1 <= index && static_cast<unsigned int> (index) <= specs->size(), 2,
"index out of range" );
DisplaySpecs::iterator it = specs->begin();
std::advance( it, index - 1 );
DisplaySpec *s = const_cast<DisplaySpec *>(&(*it));
s->PushSelf( L );
}
else
{
lua_pushnil( L );
}
return 1;
}
const luaL_Reg DisplaySpecs_meta[] =
{
{"__gc", DisplaySpecs_gc},
{"__index", DisplaySpecs_get},
{"__len", DisplaySpecs_len},
{"__tostring", DisplaySpecs_tostring},
{NULL, NULL}
};
void register_DisplaySpecs(lua_State *L)
{
luaL_newmetatable( L, DISPLAYSPECS );
luaL_openlib( L, 0, DisplaySpecs_meta, 0 );
lua_pop( L, 1 );
}
}
REGISTER_WITH_LUA_FUNCTION(register_DisplaySpecs);
DisplaySpecs *pushDisplaySpecs(lua_State *L, const DisplaySpecs &specs)
{
void *vpSpecs = lua_newuserdata( L, sizeof( DisplaySpecs ));
DisplaySpecs *pspecs = new( vpSpecs ) DisplaySpecs( specs );
luaL_getmetatable( L, DISPLAYSPECS );
lua_setmetatable( L, -2 );
return pspecs;
}
+203
View File
@@ -0,0 +1,203 @@
#ifndef DisplaySpec_H
#define DisplaySpec_H
#include <set>
#include "RageTypes.h"
struct DisplayMode {
// Width (in pixels) of the display in this mode
unsigned int width;
// Height (in pixels) of the display in this mode
unsigned int height;
/** Refresh rate, in hz, of the display for the given mode
* MacOS Quartz Display Services provides rate as double,
* winapi DEVMODE uses 32bit unsigned int (still gives rate as hz),
* RandR gives 32 bit pixel clock, which is then divided by width*height.
*/
double refreshRate;
/*
* Bits-per-pixel is *not* a property of the DisplayMode for our purposes:
* bit-depth is going to be a property of the OpenGL/D3D context, not a display
* configuration
*/
bool operator<( const DisplayMode &other ) const
{
/** @brief A quick way to compare the two DisplayResolutions. */
#define COMPARE(x) if( x != other.x ) return x < other.x;
COMPARE( width );
COMPARE( height );
COMPARE( refreshRate );
#undef COMPARE
return false;
}
// Lua
void PushSelf( lua_State *L );
};
/** @brief The dimensions of the program. */
class DisplaySpec
{
public:
/*
* Construct a specification for the display with the given ID, which supports the given modes,
* and is currently using the specified mode with the specified logical screen bounds
*/
DisplaySpec(const std::string &id,
const std::string &name,
const std::set<DisplayMode> &modes,
const DisplayMode &curMode,
const RectI &curBounds,
const bool isVirtual=false):
m_sId( id ), m_sName( name ),
m_sModes( modes ), m_bCurModeActive( true ), m_CurMode( curMode ),
m_rectBounds( curBounds ), m_bIsVirtual( isVirtual )
{
if ( m_sModes.find( curMode ) == m_sModes.end() )
{
// This is an error, make a failing assertion with a descriptive error message
std::stringstream msgStream;
msgStream << "DisplaySpec current mode (" << curMode.width << "x" <<
curMode.height << "@" << curMode.refreshRate << ") not in given list of supported modes: ";
for ( auto &m : modes )
{
msgStream << m.width << "x" << m.height << "@" << m.refreshRate << ", ";
}
auto msg = msgStream.str();
// Drop the trailing ", "
msg.resize( msg.size() - 2 );
ASSERT_M( false, msg.c_str() );
}
}
/*
* Construct a specification for the display with the given ID, which supports the given modes,
* and is currently disabled (has no active mode)
*/
DisplaySpec(const std::string id,
const std::string name,
const std::set<DisplayMode> modes,
const bool isVirtual=false):
m_sId( id ), m_sName( name ),
m_sModes( modes ), m_bCurModeActive( false ), m_CurMode( { } ),
m_bIsVirtual( isVirtual )
{
}
// Create a specification for a display supporting a single (and currently active) mode
DisplaySpec(std::string id, std::string name, DisplayMode mode) : m_sId( id ), m_sName( name ), m_bIsVirtual( false ),
m_bCurModeActive( true ), m_CurMode( mode )
{
m_sModes.insert( mode );
m_rectBounds = RectI( 0, 0, mode.width, mode.height );
}
DisplaySpec( const DisplaySpec &other ) = default;
std::string name() const
{
return m_sName;
}
std::string id() const
{
return m_sId;
}
const std::set<DisplayMode> &supportedModes() const
{
return m_sModes;
}
/*
* Return a pointer to the currently active display mode, or NULL if
* display is inactive
*
* Note that inactive *does not* necessarily mean unusable. E.g., in X11,
* an output can be enabled/disabled by an application by connecting/disconnecting
* a crtc
*/
const DisplayMode *currentMode() const
{
return m_bCurModeActive ? &m_CurMode : nullptr;
}
const RectI &currentBounds() const
{
return m_rectBounds;
}
bool isVirtual() const
{
return m_bIsVirtual;
}
/**
* @brief Determine if one DisplaySpec compares less than the other.
*
* Used to enforce a consistent ordering of displays, e.g. for consistent option
* presentation. Also allows DisplaySpec to be placed in a std::set
*
* @param other the other DisplaySpec to check.
* @return true if this DisplaySpec is less than the other, or false otherwise. */
bool operator<( const DisplaySpec &other ) const
{
return m_sId < other.id();
}
// Lua
void PushSelf( lua_State *L );
private:
// Unique identifier of the display
std::string m_sId;
// "Human-readable" display name
std::string m_sName;
// Modes supported by this display
std::set<DisplayMode> m_sModes;
// currently configured mode, if available
bool m_bCurModeActive;
DisplayMode m_CurMode;
// The current bounds of this display in global display coordinate space
RectI m_rectBounds;
// Flag is "true" when display represents a logical display like an X screen
// or the Win32 "Virtual screen"
bool m_bIsVirtual;
};
/** @brief The collection of DisplaySpec available within the program. */
typedef std::set<DisplaySpec> DisplaySpecs;
//Lua
DisplaySpecs *pushDisplaySpecs(lua_State *L, const DisplaySpecs &specs);
#endif
/**
* @file
* @author Chris Danford (c) 2001-2005
* @section LICENSE
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, and/or sell copies of the Software, and to permit persons to
* whom the Software is furnished to do so, provided that the above
* copyright notice(s) and this permission notice appear in all copies of
* the Software and that both the above copyright notice(s) and this
* permission notice appear in supporting documentation.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF
* THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS
* INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT
* OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
* OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
+2
View File
@@ -82,9 +82,11 @@ namespace LuaHelpers
{
template<> void Push<bool>( lua_State *L, const bool &Object ) { lua_pushboolean( L, Object ); }
template<> void Push<float>( lua_State *L, const float &Object ) { lua_pushnumber( L, Object ); }
template<> void Push<double>( lua_State *L, const double &Object ) { lua_pushnumber( L, Object ); }
template<> void Push<int>( lua_State *L, const int &Object ) { lua_pushinteger( L, Object ); }
template<> void Push<unsigned int>( lua_State *L, const unsigned int &Object ) { lua_pushnumber( L, double(Object) ); }
template<> void Push<RString>( lua_State *L, const RString &Object ) { lua_pushlstring( L, Object.data(), Object.size() ); }
template<> void Push<std::string>( lua_State *L, std::string const& object ) { lua_pushlstring( L, object.data(), object.size() ); }
template<> bool FromStack<bool>( Lua *L, bool &Object, int iOffset ) { Object = !!lua_toboolean( L, iOffset ); return true; }
template<> bool FromStack<float>( Lua *L, float &Object, int iOffset ) { Object = (float)lua_tonumber( L, iOffset ); return true; }
+1 -1
View File
@@ -145,7 +145,7 @@ CreateZip.cpp CreateZip.h \
CryptHelpers.cpp CryptHelpers.h \
DateTime.cpp DateTime.h \
Difficulty.cpp Difficulty.h \
DisplayResolutions.h \
DisplaySpec.h \
EnumHelper.cpp EnumHelper.h \
FileDownload.cpp FileDownload.h \
Font.cpp Font.h \
+3 -3
View File
@@ -845,10 +845,10 @@ void OptionRow::Reload()
switch( m_pHand->Reload() )
{
case OptionRowHandler::RELOAD_CHANGED_NONE:
case RELOAD_CHANGED_NONE:
break;
case OptionRowHandler::RELOAD_CHANGED_ALL:
case RELOAD_CHANGED_ALL:
{
ChoicesChanged( m_RowType );
@@ -861,7 +861,7 @@ void OptionRow::Reload()
// fall through
}
case OptionRowHandler::RELOAD_CHANGED_ENABLED:
case RELOAD_CHANGED_ENABLED:
UpdateEnabledDisabled();
FOREACH_HumanPlayer( pn )
PositionUnderlines( pn );
+93 -17
View File
@@ -834,6 +834,7 @@ class OptionRowHandlerLua : public OptionRowHandler
public:
LuaReference *m_pLuaTable;
LuaReference m_EnabledForPlayersFunc;
LuaReference m_ReloadFunc;
bool m_TableIsSane;
bool m_GoToFirstOnStart;
@@ -941,6 +942,17 @@ public:
}
lua_pop(L, 1);
lua_getfield(L, -1, "Reload");
if(!lua_isnil(L, -1))
{
if(!lua_isfunction(L, -1))
{
LuaHelpers::ReportScriptErrorFmt("LUA_ERROR: \"%s\" \"Reload\" entry is not a function.", RowName.c_str());
return false;
}
}
lua_pop(L, 1);
lua_getfield(L, -1, "LoadSelections");
if(!lua_isfunction(L, -1))
{
@@ -1007,6 +1019,22 @@ public:
LUA->Release(L);
}
void LoadChoices( Lua *L )
{
// Iterate over the "Choices" table.
lua_getfield(L, -1, "Choices");
lua_pushnil( L );
while( lua_next(L, -2) != 0 )
{
// `key' is at index -2 and `value' at index -1
const char *pValue = lua_tostring( L, -1 );
//LOG->Trace( "choice: '%s'", pValue);
m_Def.m_vsChoices.push_back( pValue );
lua_pop( L, 1 ); // removes `value'; keeps `key' for next iteration
}
lua_pop( L, 1 ); // pop choices table
}
virtual bool LoadInternal( const Commands &cmds )
{
const Command &command = cmds.v[0];
@@ -1059,18 +1087,7 @@ public:
m_Def.m_selectType = StringToSelectType( pStr );
lua_pop( L, 1 );
// Iterate over the "Choices" table.
lua_getfield(L, -1, "Choices");
lua_pushnil( L );
while( lua_next(L, -2) != 0 )
{
// `key' is at index -2 and `value' at index -1
const char *pValue = lua_tostring( L, -1 );
//LOG->Trace( "choice: '%s'", pValue);
m_Def.m_vsChoices.push_back( pValue );
lua_pop( L, 1 ); // removes `value'; keeps `key' for next iteration
}
lua_pop( L, 1 ); // pop choices table
LoadChoices( L );
// Set the EnabledForPlayers function.
lua_getfield(L, -1, "EnabledForPlayers");
@@ -1093,6 +1110,10 @@ public:
}
lua_pop( L, 1 ); // pop ReloadRowMessages table
// Set the Reload function
lua_getfield(L, -1, "Reload");
m_ReloadFunc.SetFromStack( L );
lua_pop( L, 1 ); // pop main table
ASSERT( lua_gettop(L) == 0 );
@@ -1102,8 +1123,47 @@ public:
virtual ReloadChanged Reload()
{
if (!m_TableIsSane)
{
return RELOAD_CHANGED_NONE;
}
/* We'll always call SetEnabledForPlayers, and
* return at least RELOAD_CHANGED_ENABLED,
* to preserve original OptionRowHandlerLua behavior.
*
* Will also call the standard OptionRowHandler::Reload
* function to determine whether we should declare a full
* RELOAD_CHANGED_ALL
*/
ReloadChanged effect = RELOAD_CHANGED_ENABLED;
if (!m_ReloadFunc.IsNil())
{
Lua *L = LUA->Get();
m_ReloadFunc.PushSelf( L );
// Argument 1: (self)
m_pLuaTable->PushSelf( L );
RString error = "Reload: ";
LuaHelpers::RunScriptOnStack( L, error, 1, 1, true );
effect = std::max( effect, Enum::Check<ReloadChanged>( L, -1 ));
lua_pop( L, 1 );
if (effect == RELOAD_CHANGED_ALL)
{
m_Def.m_vsChoices.clear();
m_pLuaTable->PushSelf( L );
LoadChoices( L );
lua_pop( L, 1 );
ASSERT( lua_gettop(L) == 0 );
}
LUA->Release( L );
}
SetEnabledForPlayers();
return RELOAD_CHANGED_ENABLED;
return effect;
}
virtual void ImportOption( OptionRow *pRow, const vector<PlayerNumber> &vpns, vector<bool> vbSelectedOut[NUM_PLAYERS] ) const
@@ -1174,6 +1234,7 @@ public:
ASSERT( lua_gettop(L) == 0 );
int effects = 0;
FOREACH_CONST( PlayerNumber, vpns, pn )
{
PlayerNumber p = *pn;
@@ -1206,9 +1267,14 @@ public:
ASSERT( lua_gettop(L) == 6 ); // vbSelectedOut, m_iLuaTable, function, self, arg, arg
RString error= "SaveSelections: ";
LuaHelpers::RunScriptOnStack( L, error, 3, 0, true );
ASSERT( lua_gettop(L) == 2 );
LuaHelpers::RunScriptOnStack( L, error, 3, 1, true );
ASSERT( lua_gettop(L) == 3 ); // SaveSelections *may* return effects flags, otherwise nil
double ret = lua_tonumber( L, -1 );
ASSERT_M( (lua_isnumber( L, -1 ) && std::floor( ret ) == ret) || lua_isnil( L, -1 ),
"SaveSelections must return integer flags, or nill" );
effects |= static_cast<int>( ret );
lua_pop( L, 1 ); // pop effects
lua_pop( L, 1 ); // pop option table
lua_pop( L, 1 ); // pop vbSelected table
@@ -1217,8 +1283,7 @@ public:
LUA->Release(L);
// XXX: allow specifying the mask
return 0;
return effects;
}
virtual bool NotifyOfSelection(PlayerNumber pn, int choice)
{
@@ -1593,6 +1658,17 @@ OptionRowHandler* OptionRowHandlerUtil::MakeSimple( const MenuRowDef &mr )
return pHand;
}
// Expose ReloadChanged to Lua
static const char *ReloadChangedNames[] =
{
"None",
"Enabled",
"All"
};
XToString( ReloadChanged );
StringToX( ReloadChanged );
LuaXType( ReloadChanged );
/*
* (c) 2002-2004 Chris Danford
* All rights reserved.
+7 -1
View File
@@ -31,6 +31,13 @@ enum LayoutType
const RString& LayoutTypeToString( LayoutType pm );
LayoutType StringToLayoutType( const RString& s );
LuaDeclareType( LayoutType );
enum ReloadChanged
{
RELOAD_CHANGED_NONE, RELOAD_CHANGED_ENABLED, RELOAD_CHANGED_ALL, NUM_ReloadChanged, ReloadChanged_Invalid
};
const RString& ReloadChangedToString( ReloadChanged rc );
ReloadChanged StringToReloadChanged( const std::string& rc );
LuaDeclareType( ReloadChanged );
/** @brief Define the purpose of the OptionRow. */
struct OptionRowDefinition
@@ -169,7 +176,6 @@ public:
* graphic elements will also be reinitialized. If only m_vEnabledForPlayers
* has been changed, return RELOAD_CHANGED_ENABLED. If the row is static, and
* nothing has changed, return RELOAD_CHANGED_NONE. */
enum ReloadChanged { RELOAD_CHANGED_NONE, RELOAD_CHANGED_ENABLED, RELOAD_CHANGED_ALL };
virtual ReloadChanged Reload() { return RELOAD_CHANGED_NONE; }
virtual int GetDefaultOption() const { return -1; }
+3 -1
View File
@@ -166,6 +166,7 @@ PrefsManager::PrefsManager() :
m_sDefaultModifiers ( "DefaultModifiers", "" ),
m_bWindowed ( "Windowed", true ),
m_sDisplayId ( "DisplayId", "" ),
m_iDisplayWidth ( "DisplayWidth", 854 ),
m_iDisplayHeight ( "DisplayHeight", 480 ),
m_fDisplayAspectRatio ( "DisplayAspectRatio", 16/9.f, ValidateDisplayAspectRatio ),
@@ -178,6 +179,7 @@ PrefsManager::PrefsManager() :
m_iMaxTextureResolution ( "MaxTextureResolution", 2048 ),
m_iRefreshRate ( "RefreshRate", REFRESH_DEFAULT ),
m_bAllowMultitexture ( "AllowMultitexture", true ),
m_bFullscreenIsBorderlessWindow( "FullscreenIsBorderlessWindow", false ),
m_bShowStats ( "ShowStats", TRUE_IF_DEBUG),
m_bShowBanners ( "ShowBanners", true ),
m_bShowMouseCursor ( "ShowMouseCursor", true ),
@@ -379,7 +381,7 @@ void PrefsManager::StoreGamePrefs()
ASSERT( !m_sCurrentGame.Get().empty() );
// save off old values
GamePrefs &gp = m_mapGameNameToGamePrefs[m_sCurrentGame];
GamePrefs &gp = m_mapGameNameToGamePrefs[m_sCurrentGame.Get()];
gp.m_sAnnouncer = m_sAnnouncer;
gp.m_sTheme = m_sTheme;
gp.m_sDefaultModifiers = m_sDefaultModifiers;
+2
View File
@@ -158,6 +158,7 @@ protected:
public:
Preference<bool> m_bWindowed;
Preference<RString> m_sDisplayId;
Preference<int> m_iDisplayWidth;
Preference<int> m_iDisplayHeight;
Preference<float> m_fDisplayAspectRatio;
@@ -170,6 +171,7 @@ public:
Preference<int> m_iMaxTextureResolution;
Preference<int> m_iRefreshRate;
Preference<bool> m_bAllowMultitexture;
Preference<bool> m_bFullscreenIsBorderlessWindow;
Preference<bool> m_bShowStats;
Preference<bool> m_bShowBanners;
Preference<bool> m_bShowMouseCursor;
+1 -1
View File
@@ -230,7 +230,7 @@ bool ProfileManager::LoadLocalProfileFromMachine( PlayerNumber pn )
void ProfileManager::GetMemoryCardProfileDirectoriesToTry( vector<RString> &asDirsToTry )
{
/* Try to load the preferred profile. */
asDirsToTry.push_back( PREFSMAN->m_sMemoryCardProfileSubdir );
asDirsToTry.push_back( PREFSMAN->m_sMemoryCardProfileSubdir.Get() );
/* If that failed, try loading from all fallback directories. */
split( g_sMemoryCardProfileImportSubdirs, ";", asDirsToTry, true );
+57 -8
View File
@@ -12,7 +12,7 @@
#include "RageSurface.h"
#include "Preference.h"
#include "LocalizedString.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "arch/ArchHooks/ArchHooks.h"
// Statistics stuff
@@ -90,17 +90,33 @@ RString RageDisplay::SetVideoMode( VideoModeParams p, bool &bNeedReloadTextures
vs.push_back( err );
// Fall back on a known resolution good rather than 640 x 480.
DisplayResolutions dr;
this->GetDisplayResolutions( dr );
DisplaySpecs dr;
this->GetDisplaySpecs(dr);
if( dr.empty() )
{
vs.push_back( "No display resolutions" );
return SETVIDEOMODE_FAILED.GetValue() + " " + join(";",vs);
}
const DisplayResolution &d = *dr.begin();
p.width = d.iWidth;
p.height = d.iHeight;
DisplaySpec d = *dr.begin();
// Try to find DisplaySpec corresponding to requested display
for (const auto &candidate: dr)
{
if (candidate.currentMode() != nullptr)
{
d = candidate;
if (candidate.id() == p.sDisplayId)
{
break;
}
}
}
p.sDisplayId = d.id();
const DisplayMode supported = d.currentMode() != nullptr ? *d.currentMode() : *d.supportedModes().begin();
p.width = supported.width;
p.height = supported.height;
p.rate = static_cast<int> (round(supported.refreshRate));
if( (err = this->TryVideoMode(p,bNeedReloadTextures)) == "" )
return RString();
vs.push_back( err );
@@ -714,8 +730,8 @@ void RageDisplay::ChangeCentering( int iTranslateX, int iTranslateY, int iAddWid
RageMatrix RageDisplay::GetCenteringMatrix( float fTranslateX, float fTranslateY, float fAddWidth, float fAddHeight ) const
{
// in screen space, left edge = -1, right edge = 1, bottom edge = -1. top edge = 1
float fWidth = (float) GetActualVideoModeParams().width;
float fHeight = (float) GetActualVideoModeParams().height;
float fWidth = (float) GetActualVideoModeParams().windowWidth;
float fHeight = (float) GetActualVideoModeParams().windowHeight;
float fPercentShiftX = SCALE( fTranslateX, 0, fWidth, 0, +2.0f );
float fPercentShiftY = SCALE( fTranslateY, 0, fHeight, 0, -2.0f );
float fPercentScaleX = SCALE( fAddWidth, 0, fWidth, 1.0f, 2.0f );
@@ -990,6 +1006,16 @@ void RageCompiledGeometry::Set( const vector<msMesh> &vMeshes, bool bNeedsNormal
// lua start
#include "LuaBinding.h"
// Register with Lua.
static void register_REFRESH_DEFAULT(lua_State *L)
{
lua_pushstring( L, "REFRESH_DEFAULT" );
lua_pushinteger( L, REFRESH_DEFAULT );
lua_settable( L, LUA_GLOBALSINDEX);
}
REGISTER_WITH_LUA_FUNCTION( register_REFRESH_DEFAULT );
/** @brief Allow Lua to have access to the RageDisplay. */
class LunaRageDisplay: public Luna<RageDisplay>
{
@@ -1026,6 +1052,26 @@ public:
return 1;
}
static int GetDisplaySpecs( T* p, lua_State *L )
{
DisplaySpecs s;
p->GetDisplaySpecs(s);
pushDisplaySpecs(L, s);
return 1;
}
static int SupportsRenderToTexture( T* p, lua_State *L )
{
lua_pushboolean(L, p->SupportsRenderToTexture());
return 1;
}
static int SupportsFullscreenBorderlessWindow( T* p, lua_State *L )
{
lua_pushboolean(L, p->SupportsFullscreenBorderlessWindow());
return 1;
}
LunaRageDisplay()
{
ADD_METHOD( GetDisplayWidth );
@@ -1033,6 +1079,9 @@ public:
ADD_METHOD( GetFPS );
ADD_METHOD( GetVPF );
ADD_METHOD( GetCumFPS );
ADD_METHOD( GetDisplaySpecs );
ADD_METHOD( SupportsRenderToTexture );
ADD_METHOD( SupportsFullscreenBorderlessWindow);
}
};
+60 -9
View File
@@ -7,8 +7,8 @@
#include "ModelTypes.h"
#include <set>
class DisplayResolution;
typedef set<DisplayResolution> DisplayResolutions;
class DisplaySpec;
typedef std::set<DisplaySpec> DisplaySpecs;
const int REFRESH_DEFAULT = 0;
struct RageSurface;
@@ -79,6 +79,7 @@ public:
// are filled (in case new params are added).
VideoModeParams(
bool windowed_,
RString sDisplayId_,
int width_,
int height_,
int bpp_,
@@ -88,12 +89,14 @@ public:
bool bSmoothLines_,
bool bTrilinearFiltering_,
bool bAnisotropicFiltering_,
bool bWindowIsFullscreenBorderless_,
RString sWindowTitle_,
RString sIconFile_,
bool PAL_,
float fDisplayAspectRatio_
):
windowed(windowed_),
sDisplayId(sDisplayId_),
width(width_),
height(height_),
bpp(bpp_),
@@ -103,18 +106,36 @@ public:
bSmoothLines(bSmoothLines_),
bTrilinearFiltering(bTrilinearFiltering_),
bAnisotropicFiltering(bAnisotropicFiltering_),
bWindowIsFullscreenBorderless(bWindowIsFullscreenBorderless_),
sWindowTitle(sWindowTitle_),
sIconFile(sIconFile_),
PAL(PAL_),
fDisplayAspectRatio(fDisplayAspectRatio_) {}
VideoModeParams(const VideoModeParams &other):
windowed(other.windowed), sDisplayId(other.sDisplayId),
width(other.width), height(other.height),
bpp(other.bpp), rate(other.rate),
vsync(other.vsync), interlaced(other.interlaced),
bSmoothLines(other.bSmoothLines), bTrilinearFiltering(other.bTrilinearFiltering),
bAnisotropicFiltering(other.bAnisotropicFiltering), bWindowIsFullscreenBorderless(other.bWindowIsFullscreenBorderless),
sWindowTitle(other.sWindowTitle), sIconFile(other.sIconFile),
PAL(other.PAL), fDisplayAspectRatio(other.fDisplayAspectRatio)
{}
VideoModeParams(): windowed(false), width(0), height(0),
bpp(0), rate(0), vsync(false), interlaced(false),
bSmoothLines(false), bTrilinearFiltering(false),
bAnisotropicFiltering(false), sWindowTitle(RString()),
sIconFile(RString()), PAL(false), fDisplayAspectRatio(0.0f) {}
bpp(0), rate(0), vsync(false), interlaced(false),
bSmoothLines(false), bTrilinearFiltering(false),
bAnisotropicFiltering(false), bWindowIsFullscreenBorderless(false),
sWindowTitle(RString()), sIconFile(RString()),
PAL(false), fDisplayAspectRatio(0.0f) {}
// Subclassing VideoModeParams in ActualVideoModeParams. Make destructor virtual just in case
// someone tries to delete one of those through a pointer to base...
virtual ~VideoModeParams() {}
bool windowed;
RString sDisplayId;
int width;
int height;
int bpp;
@@ -124,12 +145,41 @@ public:
bool bSmoothLines;
bool bTrilinearFiltering;
bool bAnisotropicFiltering;
bool bWindowIsFullscreenBorderless;
RString sWindowTitle;
RString sIconFile;
bool PAL;
float fDisplayAspectRatio;
};
/**
* @brief The _actual_ VideoModeParams determined by the LowLevelWindow implementation.
* Contains all the attributes of VideoModeParams, plus the actual window width/height determined by
* LLW
*/
class ActualVideoModeParams: public VideoModeParams
{
public:
ActualVideoModeParams(): VideoModeParams(), windowWidth(0), windowHeight(0), renderOffscreen(false) {}
ActualVideoModeParams( const VideoModeParams &params ) : VideoModeParams( params ),
windowWidth( params.width ),
windowHeight( params.height ),
renderOffscreen( false )
{ }
ActualVideoModeParams( const VideoModeParams &params, int windowWidth, int windowHeight, bool renderOffscreen ) :
VideoModeParams( params ), windowWidth( windowWidth ), windowHeight( windowHeight ),
renderOffscreen( renderOffscreen )
{ }
ActualVideoModeParams (const ActualVideoModeParams &other) = default;
// If bWindowIsFullscreenBorderless is true,
// then these properties will differ from width/height (which describe the
// render size)
int windowWidth;
int windowHeight;
bool renderOffscreen;
};
struct RenderTargetParam
{
RenderTargetParam():
@@ -181,7 +231,7 @@ public:
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer ) = 0;
virtual RString GetApiDescription() const = 0;
virtual void GetDisplayResolutions( DisplayResolutions &out ) const = 0;
virtual void GetDisplaySpecs(DisplaySpecs &out) const = 0;
// Don't override this. Override TryVideoMode() instead.
// This will set the video mode to be as close as possible to params.
@@ -193,7 +243,7 @@ public:
virtual bool BeginFrame();
virtual void EndFrame();
virtual VideoModeParams GetActualVideoModeParams() const = 0;
virtual ActualVideoModeParams GetActualVideoModeParams() const = 0;
bool IsWindowed() const { return this->GetActualVideoModeParams().windowed; }
virtual void SetBlendMode( BlendMode mode ) = 0;
@@ -235,7 +285,8 @@ public:
virtual void SetEffectMode( EffectMode ) { }
virtual bool IsEffectModeSupported( EffectMode effect ) { return effect == EffectMode_Normal; }
bool SupportsRenderToTexture() const { return false; }
virtual bool SupportsRenderToTexture() const { return false; }
virtual bool SupportsFullscreenBorderlessWindow() const { return false; }
/* Create a render target, returning a texture handle. In addition to normal
* texture functions, this can be passed to SetRenderTarget. Delete with
+29 -10
View File
@@ -10,7 +10,7 @@
#include "RageSurface.h"
#include "RageSurfaceUtils.h"
#include "EnumHelper.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "LocalizedString.h"
#include <D3dx9tex.h>
@@ -271,19 +271,39 @@ RageDisplay_D3D::~RageDisplay_D3D()
}
}
void RageDisplay_D3D::GetDisplayResolutions( DisplayResolutions &out ) const
void RageDisplay_D3D::GetDisplaySpecs( DisplaySpecs &out ) const
{
out.clear();
int iCnt = g_pd3d->GetAdapterModeCount( D3DADAPTER_DEFAULT, g_DefaultAdapterFormat );
for( int i = 0; i < iCnt; ++i )
std::set<DisplayMode> modes;
D3DDISPLAYMODE mode;
for ( int i = 0; i < iCnt; ++i )
{
D3DDISPLAYMODE mode;
g_pd3d->EnumAdapterModes( D3DADAPTER_DEFAULT, g_DefaultAdapterFormat, i, &mode );
DisplayResolution res = { mode.Width, mode.Height };
out.insert( res );
modes.insert( { mode.Width, mode.Height, static_cast<double> (mode.RefreshRate) } );
}
// Get the current display mode
if ( g_pd3d->GetAdapterDisplayMode( D3DADAPTER_DEFAULT, &mode ) == D3D_OK )
{
D3DADAPTER_IDENTIFIER9 ID;
g_pd3d->GetAdapterIdentifier( D3DADAPTER_DEFAULT, 0, &ID );
DisplayMode active = { mode.Width, mode.Height, static_cast<double> (mode.RefreshRate) };
RectI bounds( 0, 0, active.width, active.height );
out.insert( DisplaySpec( "", "Fullscreen", modes, active, bounds ) );
}
else
{
LOG->Warn( "Could not find active mode for default D3D adapter" );
if ( !modes.empty() )
{
const DisplayMode &m = *modes.begin();
RectI bounds( 0, 0, m.width, m.height );
out.insert( DisplaySpec( "", "Fullscreen", modes, m, bounds ) );
}
}
}
D3DFORMAT FindBackBufferType(bool bWindowed, int iBPP)
@@ -677,10 +697,9 @@ RageSurface* RageDisplay_D3D::CreateScreenshot()
return result;
}
VideoModeParams RageDisplay_D3D::GetActualVideoModeParams() const
ActualVideoModeParams RageDisplay_D3D::GetActualVideoModeParams() const
{
VideoModeParams p = GraphicsWindow::GetParams();
return p;
return GraphicsWindow::GetParams();
}
void RageDisplay_D3D::SendCurrentMatrices()
+2 -2
View File
@@ -11,13 +11,13 @@ public:
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
virtual RString GetApiDescription() const { return "D3D"; }
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
virtual void GetDisplaySpecs( DisplaySpecs &out ) const;
void ResolutionChanged();
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
bool BeginFrame();
void EndFrame();
VideoModeParams GetActualVideoModeParams() const;
ActualVideoModeParams GetActualVideoModeParams() const;
void SetBlendMode( BlendMode mode );
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
bool SupportsThreadedRendering();
+4 -4
View File
@@ -11,7 +11,7 @@
#include "RageSurface.h"
#include "RageTextureManager.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "arch/LowLevelWindow/LowLevelWindow.h"
@@ -444,10 +444,10 @@ RageDisplay_GLES2::~RageDisplay_GLES2()
}
void
RageDisplay_GLES2::GetDisplayResolutions( DisplayResolutions &out ) const
RageDisplay_GLES2::GetDisplaySpecs(DisplaySpecs &out) const
{
out.clear();
g_pWind->GetDisplayResolutions( out );
g_pWind->GetDisplaySpecs(out);
}
RageSurface*
@@ -517,7 +517,7 @@ RageDisplay_GLES2::GetApiDescription() const
return "OpenGL ES 2.0";
}
VideoModeParams
ActualVideoModeParams
RageDisplay_GLES2::GetActualVideoModeParams() const
{
return g_pWind->GetActualVideoModeParams();
+7 -7
View File
@@ -9,21 +9,21 @@ public:
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
virtual RString GetApiDescription() const;
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
bool BeginFrame();
void EndFrame();
VideoModeParams GetActualVideoModeParams() const;
ActualVideoModeParams GetActualVideoModeParams() const;
void SetBlendMode( BlendMode mode );
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
bool SupportsPerVertexMatrixScale();
unsigned CreateTexture(
RagePixelFormat pixfmt,
unsigned CreateTexture(
RagePixelFormat pixfmt,
RageSurface* img,
bool bGenerateMipMaps );
void UpdateTexture(
unsigned iTexHandle,
void UpdateTexture(
unsigned iTexHandle,
RageSurface* img,
int xoffset, int yoffset, int width, int height );
void DeleteTexture( unsigned iTexHandle );
@@ -42,7 +42,7 @@ public:
void ClearZBuffer();
void SetCullMode( CullMode mode );
void SetAlphaTest( bool b );
void SetMaterial(
void SetMaterial(
const RageColor &emissive,
const RageColor &ambient,
const RageColor &diffuse,
+5 -4
View File
@@ -9,7 +9,7 @@
#include "RageTypes.h"
#include "RageUtil.h"
#include "RageSurface.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
static RageDisplay::RagePixelFormatDesc PIXEL_FORMAT_DESC[NUM_RagePixelFormat] = {
{
@@ -81,11 +81,12 @@ RString RageDisplay_Null::Init( const VideoModeParams &p, bool /* bAllowUnaccele
return RString();
}
void RageDisplay_Null::GetDisplayResolutions( DisplayResolutions &out ) const
void RageDisplay_Null::GetDisplaySpecs(DisplaySpecs &out) const
{
out.clear();
DisplayResolution res = { 640, 480, true };
out.insert( res );
DisplayMode nullMode = {640U, 480U, 30.0};
DisplaySpec nullSpec("NullDisplay", "NullDisplay", nullMode);
out.insert( nullSpec );
}
RageSurface* RageDisplay_Null::CreateScreenshot()
+8 -8
View File
@@ -10,23 +10,23 @@ public:
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
virtual RString GetApiDescription() const { return "Null"; }
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
bool BeginFrame() { return true; }
void EndFrame();
VideoModeParams GetActualVideoModeParams() const { return m_Params; }
ActualVideoModeParams GetActualVideoModeParams() const { return m_Params; }
void SetBlendMode( BlendMode ) { }
bool SupportsTextureFormat( RagePixelFormat, bool /* realtime */ =false ) { return true; }
bool SupportsPerVertexMatrixScale() { return false; }
unsigned CreateTexture(
RagePixelFormat,
unsigned CreateTexture(
RagePixelFormat,
RageSurface* /* img */,
bool /* bGenerateMipMaps */ ) { return 1; }
void UpdateTexture(
unsigned /* iTexHandle */,
void UpdateTexture(
unsigned /* iTexHandle */,
RageSurface* /* img */,
int /* xoffset */, int /* yoffset */, int /* width */, int /* height */
int /* xoffset */, int /* yoffset */, int /* width */, int /* height */
) { }
void DeleteTexture( unsigned /* iTexHandle */ ) { }
void ClearAllTextures() { }
@@ -44,7 +44,7 @@ public:
void ClearZBuffer() { }
void SetCullMode( CullMode ) { }
void SetAlphaTest( bool ) { }
void SetMaterial(
void SetMaterial(
const RageColor & /* unreferenced: emissive */,
const RageColor & /* unreferenced: ambient */,
const RageColor & /* unreferenced: diffuse */,
+106 -20
View File
@@ -15,7 +15,7 @@ using namespace RageDisplay_Legacy_Helpers;
#include "RageUtil.h"
#include "EnumHelper.h"
#include "Foreach.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "LocalizedString.h"
#include "arch/LowLevelWindow/LowLevelWindow.h"
@@ -63,7 +63,7 @@ static const GLenum RageSpriteVertexFormat = GL_T2F_C4F_N3F_V3F;
/* If we support texture matrix scaling, a handle to the vertex program: */
static GLhandleARB g_bTextureMatrixShader = 0;
static map<unsigned, RenderTarget *> g_mapRenderTargets;
static std::map<unsigned, RenderTarget *> g_mapRenderTargets;
static RenderTarget *g_pCurrentRenderTarget = NULL;
static LowLevelWindow *g_pWind;
@@ -264,6 +264,7 @@ RageDisplay_Legacy::RageDisplay_Legacy()
g_pWind = NULL;
g_bTextureMatrixShader = 0;
offscreenRenderTarget = nullptr;
}
RString GetInfoLog( GLhandleARB h )
@@ -561,10 +562,10 @@ RageDisplay_Legacy::~RageDisplay_Legacy()
delete g_pWind;
}
void RageDisplay_Legacy::GetDisplayResolutions( DisplayResolutions &out ) const
void RageDisplay_Legacy::GetDisplaySpecs(DisplaySpecs &out) const
{
out.clear();
g_pWind->GetDisplayResolutions( out );
g_pWind->GetDisplaySpecs(out);
}
static void CheckPalettedTextures()
@@ -685,7 +686,9 @@ void SetupExtensions()
const float fGLUVersion = StringToFloat( (const char *) gluGetString(GLU_VERSION) );
g_gluVersion = lrintf( fGLUVersion * 10 );
#ifndef HAVE_X11 // LLW_X11 needs to init GLEW early for GLX exts
glewInit();
#endif
g_iMaxTextureUnits = 1;
if (GLEW_ARB_multitexture)
@@ -712,6 +715,39 @@ void SetupExtensions()
}
}
bool RageDisplay_Legacy::UseOffscreenRenderTarget()
{
if ( !GetActualVideoModeParams().renderOffscreen || !TEXTUREMAN )
{
return false;
}
if ( !offscreenRenderTarget )
{
RenderTargetParam param;
param.bWithDepthBuffer = true;
param.bWithAlpha = true;
param.bFloat = false;
param.iWidth = GetActualVideoModeParams().width;
param.iHeight = GetActualVideoModeParams().height;
RageTextureID id( ssprintf( "FullscreenTexture%dx%d", param.iWidth,
param.iHeight ) );
// See if we have this texture loaded already
// (not GC'd yet). If it exists and we try to recreate
// it, we'll get an error
if ( TEXTUREMAN->IsTextureRegistered( id ) )
{
offscreenRenderTarget = static_cast<RageTextureRenderTarget*>( TEXTUREMAN->LoadTexture( id ) );
}
else
{
offscreenRenderTarget = new RageTextureRenderTarget( id, param );
TEXTUREMAN->RegisterTexture( id, offscreenRenderTarget );
}
}
return true;
}
void RageDisplay_Legacy::ResolutionChanged()
{
//LOG->Warn( "RageDisplay_Legacy::ResolutionChanged" );
@@ -721,6 +757,13 @@ void RageDisplay_Legacy::ResolutionChanged()
EndFrame();
RageDisplay::ResolutionChanged();
if (offscreenRenderTarget && TEXTUREMAN)
{
TEXTUREMAN->UnloadTexture( offscreenRenderTarget );
offscreenRenderTarget = NULL;
}
}
// Return true if mode change was successful.
@@ -746,6 +789,7 @@ RString RageDisplay_Legacy::TryVideoMode( const VideoModeParams &p, bool &bNewDe
if (TEXTUREMAN)
TEXTUREMAN->InvalidateTextures();
/* Delete all render targets. They may have associated resources other than
* the texture itself. */
FOREACHM( unsigned, RenderTarget *, g_mapRenderTargets, rt )
@@ -784,8 +828,8 @@ bool RageDisplay_Legacy::BeginFrame()
{
/* We do this in here, rather than ResolutionChanged, or we won't update the
* viewport for the concurrent rendering context. */
int fWidth = g_pWind->GetActualVideoModeParams().width;
int fHeight = g_pWind->GetActualVideoModeParams().height;
int fWidth = g_pWind->GetActualVideoModeParams().windowWidth;
int fHeight = g_pWind->GetActualVideoModeParams().windowHeight;
glViewport( 0, 0, fWidth, fHeight );
@@ -793,11 +837,34 @@ bool RageDisplay_Legacy::BeginFrame()
SetZWrite( true );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
return RageDisplay::BeginFrame();
bool beginFrame = RageDisplay::BeginFrame();
if (beginFrame && UseOffscreenRenderTarget()) {
offscreenRenderTarget->BeginRenderingTo( false );
}
return beginFrame;
}
void RageDisplay_Legacy::EndFrame()
{
if (UseOffscreenRenderTarget())
{
offscreenRenderTarget->FinishRenderingTo();
Sprite fullscreenSprite;
// We've got a hold of this, don't want sprite deleting it when
// it's deleted
offscreenRenderTarget->m_iRefCount++;
fullscreenSprite.SetTexture(offscreenRenderTarget);
fullscreenSprite.SetHorizAlign(align_left);
fullscreenSprite.SetVertAlign(align_top);
CameraPushMatrix();
LoadMenuPerspective( 0, GetActualVideoModeParams().width, GetActualVideoModeParams().height,
static_cast<float> (GetActualVideoModeParams().width) / 2.f,
static_cast<float> (GetActualVideoModeParams().height) / 2.f );
fullscreenSprite.Draw();
CameraPopMatrix();
}
FrameLimitBeforeVsync( g_pWind->GetActualVideoModeParams().rate );
g_pWind->SwapBuffers();
FrameLimitAfterVsync();
@@ -823,20 +890,31 @@ RageSurface* RageDisplay_Legacy::CreateScreenshot()
int width = g_pWind->GetActualVideoModeParams().width;
int height = g_pWind->GetActualVideoModeParams().height;
const RagePixelFormatDesc &desc = PIXEL_FORMAT_DESC[RagePixelFormat_RGBA8];
RageSurface *image = CreateSurface( width, height, desc.bpp,
desc.masks[0], desc.masks[1], desc.masks[2], 0 );
RageSurface *image = NULL;
if (offscreenRenderTarget) {
RageSurface *raw = GetTexture(offscreenRenderTarget->GetTexHandle());
image = CreateSurface( offscreenRenderTarget->GetImageWidth(), offscreenRenderTarget->GetImageHeight(),
raw->fmt.BitsPerPixel, raw->fmt.Rmask, raw->fmt.Gmask, raw->fmt.Bmask,
raw->fmt.Amask );
RageSurfaceUtils::Blit(raw, image);
delete raw;
} else {
const RagePixelFormatDesc &desc = PIXEL_FORMAT_DESC[RagePixelFormat_RGBA8];
image = CreateSurface( width, height, desc.bpp,
desc.masks[0], desc.masks[1], desc.masks[2], 0 );
DebugFlushGLErrors();
DebugFlushGLErrors();
glReadBuffer( GL_FRONT );
DebugAssertNoGLError();
//TODO: revisit for MacOS, where backbuffer size can be less than window size
glReadBuffer( GL_FRONT );
DebugAssertNoGLError();
glReadPixels( 0, 0, g_pWind->GetActualVideoModeParams().width, g_pWind->GetActualVideoModeParams().height, GL_RGBA,
GL_UNSIGNED_BYTE, image->pixels );
DebugAssertNoGLError();
glReadPixels( 0, 0, g_pWind->GetActualVideoModeParams().width, g_pWind->GetActualVideoModeParams().height, GL_RGBA,
GL_UNSIGNED_BYTE, image->pixels );
DebugAssertNoGLError();
RageSurfaceUtils::FlipVertically( image );
RageSurfaceUtils::FlipVertically( image );
}
return image;
}
@@ -865,7 +943,7 @@ RageSurface *RageDisplay_Legacy::GetTexture( unsigned iTexture )
return pImage;
}
VideoModeParams RageDisplay_Legacy::GetActualVideoModeParams() const
ActualVideoModeParams RageDisplay_Legacy::GetActualVideoModeParams() const
{
return g_pWind->GetActualVideoModeParams();
}
@@ -2483,6 +2561,14 @@ bool RageDisplay_Legacy::SupportsRenderToTexture() const
return GLEW_EXT_framebuffer_object || g_pWind->SupportsRenderToTexture();
}
bool RageDisplay_Legacy::SupportsFullscreenBorderlessWindow() const
{
// In order to support FSBW, we're going to need the LowLevelWindow implementation
// to support creating a fullscreen borderless window, and we're going to need
// RenderToTexture support in order to render in alternative resolutions
return g_pWind->SupportsFullscreenBorderlessWindow() && SupportsRenderToTexture();
}
/*
* Render-to-texture can be implemented in several ways: the generic GL_ARB_pixel_buffer_object,
* or platform-specifically. PBO is not available on all hardware that supports RTT,
@@ -2525,8 +2611,8 @@ void RageDisplay_Legacy::SetRenderTarget( unsigned iTexture, bool bPreserveTextu
DISPLAY->CameraPopMatrix();
/* Reset the viewport. */
int fWidth = g_pWind->GetActualVideoModeParams().width;
int fHeight = g_pWind->GetActualVideoModeParams().height;
int fWidth = g_pWind->GetActualVideoModeParams().windowWidth;
int fHeight = g_pWind->GetActualVideoModeParams().windowHeight;
glViewport( 0, 0, fWidth, fHeight );
if (g_pCurrentRenderTarget)
+17 -10
View File
@@ -4,9 +4,11 @@
#define RAGE_DISPLAY_OGL_H
#include "RageDisplay.h"
#include "RageTextureRenderTarget.h"
#include "Sprite.h"
/* Making an OpenGL call doesn't also flush the error state; if we happen
* to have an error from a previous call, then the assert below will fail.
* to have an error from a previous call, then the assert below will fail.
* Flush it. */
#define FlushGLErrors() do { } while( glGetError() != GL_NO_ERROR )
#define AssertNoGLError() \
@@ -31,7 +33,7 @@ public:
virtual RString Init( const VideoModeParams &p, bool bAllowUnacceleratedRenderer );
virtual RString GetApiDescription() const { return "OpenGL"; }
virtual void GetDisplayResolutions( DisplayResolutions &out ) const;
virtual void GetDisplaySpecs(DisplaySpecs &out) const;
void ResolutionChanged();
const RagePixelFormatDesc *GetPixelFormatDesc(RagePixelFormat pf) const;
@@ -41,22 +43,23 @@ public:
void BeginConcurrentRendering();
void EndConcurrentRendering();
bool BeginFrame();
bool BeginFrame();
void EndFrame();
VideoModeParams GetActualVideoModeParams() const;
ActualVideoModeParams GetActualVideoModeParams() const;
void SetBlendMode( BlendMode mode );
bool SupportsTextureFormat( RagePixelFormat pixfmt, bool realtime=false );
bool SupportsPerVertexMatrixScale();
unsigned CreateTexture(
RagePixelFormat pixfmt,
unsigned CreateTexture(
RagePixelFormat pixfmt,
RageSurface* img,
bool bGenerateMipMaps );
void UpdateTexture(
unsigned iTexHandle,
void UpdateTexture(
unsigned iTexHandle,
RageSurface* img,
int xoffset, int yoffset, int width, int height
int xoffset, int yoffset, int width, int height
);
void DeleteTexture( unsigned iTexHandle );
bool UseOffscreenRenderTarget();
RageSurface *GetTexture( unsigned iTexture );
RageTextureLock *CreateTextureLock();
@@ -70,6 +73,7 @@ public:
void SetEffectMode( EffectMode effect );
bool IsEffectModeSupported( EffectMode effect );
bool SupportsRenderToTexture() const;
bool SupportsFullscreenBorderlessWindow() const;
unsigned CreateRenderTarget( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut );
unsigned GetRenderTarget();
void SetRenderTarget( unsigned iHandle, bool bPreserveTexture );
@@ -81,7 +85,7 @@ public:
void ClearZBuffer();
void SetCullMode( CullMode mode );
void SetAlphaTest( bool b );
void SetMaterial(
void SetMaterial(
const RageColor &emissive,
const RageColor &ambient,
const RageColor &diffuse,
@@ -125,6 +129,9 @@ protected:
bool SupportsSurfaceFormat( RagePixelFormat pixfmt );
void SendCurrentMatrices();
private:
RageTextureRenderTarget *offscreenRenderTarget;
};
#endif
+1
View File
@@ -247,6 +247,7 @@ ScreenManager::ScreenManager()
m_bZeroNextUpdate = false;
m_PopTopScreen = SM_Invalid;
m_OnDonePreparingScreen = SM_Invalid;
}
+35 -15
View File
@@ -14,7 +14,7 @@
#include "Game.h"
#include "Foreach.h"
#include "GameConstantsAndTypes.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "LocalizedString.h"
#include "SpecialFiles.h"
#include "RageLog.h"
@@ -248,22 +248,25 @@ static void ThemeChoices( vector<RString> &out )
*s = THEME->GetThemeDisplayName( *s );
}
static DisplayResolutions display_resolution_list;
static void cache_display_resolution_list()
static DisplaySpecs display_specs;
static void cache_display_specs()
{
if(display_resolution_list.empty())
if(display_specs.empty())
{
DISPLAY->GetDisplayResolutions(display_resolution_list);
DISPLAY->GetDisplaySpecs(display_specs);
}
}
static void DisplayResolutionChoices( vector<RString> &out )
{
cache_display_resolution_list();
FOREACHS_CONST( DisplayResolution, display_resolution_list, iter )
cache_display_specs();
FOREACHS_CONST( DisplaySpec, display_specs, iter )
{
RString s = ssprintf("%dx%d", iter->iWidth, iter->iHeight);
out.push_back( s );
if (iter->currentMode() != NULL)
{
RString s = ssprintf("%dx%d", iter->currentMode()->width, iter->currentMode()->height);
out.push_back(s);
}
}
}
@@ -516,6 +519,8 @@ static void MaxHighScoresPerListForPlayer(int& sel, bool to_sel, ConfOption cons
#include "LuaManager.h"
#include "LuaBinding.h"
static int GetTimingDifficulty()
{
int iTimingDifficulty = 0;
@@ -583,12 +588,14 @@ static void DisplayResolutionM( int &sel, bool ToSel, const ConfOption *pConfOpt
{
static vector<res_t> res_choices;
if(res_choices.empty())
if( res_choices.empty() )
{
cache_display_resolution_list();
FOREACHS_CONST(DisplayResolution, display_resolution_list, iter)
FOREACHS_CONST( DisplaySpec, display_specs, iter )
{
res_choices.push_back(res_t(iter->iWidth, iter->iHeight));
if ( iter->currentMode() != NULL )
{
res_choices.push_back( res_t( iter->currentMode()->width, iter->currentMode()->height ) );
}
}
}
@@ -733,10 +740,10 @@ static void InitializeConfOptions()
if( !g_ConfOptions.empty() )
return;
// Clear the display_resolution_list so that we don't get problems from
// Clear the display_specs so that we don't get problems from
// caching it. If the DisplayResolution option row is on the screen, it'll
// recache the list. -Kyz
display_resolution_list.clear();
display_specs.clear();
// There are a couple ways of getting the current preference column or turning
// a new choice in the interface into a new preference. The easiest is when
@@ -958,6 +965,19 @@ void ConfOption::MakeOptionsList( vector<RString> &out ) const
out = names;
}
static const char *OptEffectNames[] = {
"SavePreferences",
"ApplyGraphics",
"ApplyTheme",
"ChangeGame",
"ApplySound",
"ApplySong",
"ApplyAspectRatio"
};
XToString( OptEffect );
StringToX( OptEffect );
LuaXType( OptEffect );
/**
* @file
* @author Glenn Maynard (c) 2003-2004
+17 -7
View File
@@ -1,14 +1,24 @@
#ifndef SCREEN_OPTIONS_MASTER_PREFS_H
#define SCREEN_OPTIONS_MASTER_PREFS_H
#include "EnumHelper.h"
static const int MAX_OPTIONS=16;
#define OPT_SAVE_PREFERENCES (1<<0)
#define OPT_APPLY_GRAPHICS (1<<1)
#define OPT_APPLY_THEME (1<<2)
#define OPT_CHANGE_GAME (1<<3)
#define OPT_APPLY_SOUND (1<<4)
#define OPT_APPLY_SONG (1<<5)
#define OPT_APPLY_ASPECT_RATIO (1<<6)
enum OptEffect
{
OPT_SAVE_PREFERENCES = (1<<0),
OPT_APPLY_GRAPHICS = (1<<1),
OPT_APPLY_THEME = (1<<2),
OPT_CHANGE_GAME = (1<<3),
OPT_APPLY_SOUND = (1<<4),
OPT_APPLY_SONG = (1<<5),
OPT_APPLY_ASPECT_RATIO = (1<<6),
NUM_OptEffect = 7,
OptEffect_Invalid = MAX_OPTIONS+1
};
const RString& OptEffectToString( OptEffect e );
OptEffect StringToOptEffect( const std::string &e );
LuaDeclareType( OptEffect );
struct ConfOption
{
+37 -12
View File
@@ -84,6 +84,31 @@ Sprite::Sprite( const Sprite &cpy ):
m_pTexture = NULL;
}
Sprite &Sprite::operator=( Sprite other )
{
using std::swap;
#define SWAP(a) swap(a, other.a)
SWAP( m_States );
SWAP(m_animation_length_seconds);
SWAP( m_iCurState );
SWAP( m_fSecsIntoState );
SWAP( m_bUsingCustomTexCoords );
SWAP( m_bUsingCustomPosCoords );
SWAP( m_bSkipNextUpdate );
SWAP( m_DecodeMovie );
SWAP( m_EffectMode );
memcpy( m_CustomTexCoords, other.m_CustomTexCoords, sizeof(m_CustomTexCoords) );
memcpy( m_CustomPosCoords, other.m_CustomPosCoords, sizeof(m_CustomPosCoords) );
SWAP( m_fRememberedClipWidth );
SWAP( m_fRememberedClipHeight );
SWAP( m_fTexCoordVelocityX );
SWAP( m_fTexCoordVelocityY );
SWAP(m_use_effect_clock_for_texcoords);
SWAP(m_pTexture);
#undef SWAP
return *this;
}
void Sprite::InitState()
{
Actor::InitState();
@@ -934,7 +959,7 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
Sprite::ScaleToCover( RectF(0, 0, fWidth, fHeight) );
// find which dimension is larger
bool bXDimNeedsToBeCropped = GetZoomedWidth() > fWidth+0.01;
if( bXDimNeedsToBeCropped ) // crop X
{
float fPercentageToCutOff = (this->GetZoomedWidth() - fWidth) / this->GetZoomedWidth();
@@ -943,9 +968,9 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
// generate a rectangle with new texture coordinates
RectF fCustomImageRect(
fPercentageToCutOffEachSide,
0,
1 - fPercentageToCutOffEachSide,
fPercentageToCutOffEachSide,
0,
1 - fPercentageToCutOffEachSide,
1 );
SetCustomImageRect( fCustomImageRect );
}
@@ -957,9 +982,9 @@ void Sprite::ScaleToClipped( float fWidth, float fHeight )
// generate a rectangle with new texture coordinates
RectF fCustomImageRect(
0,
0,
fPercentageToCutOffEachSide,
1,
1,
1 - fPercentageToCutOffEachSide );
SetCustomImageRect( fCustomImageRect );
}
@@ -995,7 +1020,7 @@ void Sprite::CropTo( float fWidth, float fHeight )
Sprite::ScaleToCover( RectF(0, 0, fWidth, fHeight) );
// find which dimension is larger
bool bXDimNeedsToBeCropped = GetZoomedWidth() > fWidth+0.01;
if( bXDimNeedsToBeCropped ) // crop X
{
float fPercentageToCutOff = (this->GetZoomedWidth() - fWidth) / this->GetZoomedWidth();
@@ -1003,9 +1028,9 @@ void Sprite::CropTo( float fWidth, float fHeight )
// generate a rectangle with new texture coordinates
RectF fCustomImageRect(
fPercentageToCutOffEachSide,
0,
1 - fPercentageToCutOffEachSide,
fPercentageToCutOffEachSide,
0,
1 - fPercentageToCutOffEachSide,
1 );
SetCustomImageRect( fCustomImageRect );
}
@@ -1016,9 +1041,9 @@ void Sprite::CropTo( float fWidth, float fHeight )
// generate a rectangle with new texture coordinates
RectF fCustomImageRect(
0,
0,
fPercentageToCutOffEachSide,
1,
1,
1 - fPercentageToCutOffEachSide );
SetCustomImageRect( fCustomImageRect );
}
+1
View File
@@ -21,6 +21,7 @@ public:
Sprite();
Sprite( const Sprite &cpy );
Sprite &operator=( Sprite other );
virtual ~Sprite();
// See explanation in source.
+10 -2
View File
@@ -96,7 +96,8 @@ void StepMania::GetPreferredVideoModeParams( VideoModeParams &paramsOut )
}
paramsOut = VideoModeParams(
PREFSMAN->m_bWindowed,
PREFSMAN->m_bWindowed || PREFSMAN->m_bFullscreenIsBorderlessWindow,
PREFSMAN->m_sDisplayId,
iWidth,
PREFSMAN->m_iDisplayHeight,
PREFSMAN->m_iDisplayColorDepth,
@@ -106,6 +107,7 @@ void StepMania::GetPreferredVideoModeParams( VideoModeParams &paramsOut )
PREFSMAN->m_bSmoothLines,
PREFSMAN->m_bTrilinearFiltering,
PREFSMAN->m_bAnisotropicFiltering,
!PREFSMAN->m_bWindowed && PREFSMAN->m_bFullscreenIsBorderlessWindow,
CommonMetrics::WINDOW_TITLE,
THEME->GetPathG("Common","window icon"),
PREFSMAN->m_bPAL,
@@ -146,7 +148,13 @@ static void StoreActualGraphicOptions()
* we don't go through the process of auto-detecting a usable video mode
* every time. */
const VideoModeParams &params = DISPLAY->GetActualVideoModeParams();
PREFSMAN->m_bWindowed.Set( params.windowed );
PREFSMAN->m_bWindowed.Set( params.windowed && !params.bWindowIsFullscreenBorderless );
if (!params.windowed && !params.bWindowIsFullscreenBorderless) {
// In all other cases, want to preserve the value of this preference,
// but if DISPLAY decides to go fullscreen exclusive, we'll persist that decision
PREFSMAN->m_bFullscreenIsBorderlessWindow.Set( false );
}
/* If we're windowed, we may have tweaked the width based on the aspect ratio.
* Don't save this new value over the preferred value. */
+7 -4
View File
@@ -3,9 +3,10 @@
#include <set>
class DisplayResolution;
typedef set<DisplayResolution> DisplayResolutions;
class DisplaySpec;
typedef std::set<DisplaySpec> DisplaySpecs;
class VideoModeParams;
class ActualVideoModeParams;
class RenderTarget;
struct RenderTargetParam;
/** @brief Handle low-level operations that OGL 1.x doesn't give us. */
@@ -22,7 +23,7 @@ public:
// bNewDeviceOut is set true if a new device was created and textures
// need to be reloaded.
virtual RString TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut ) = 0;
virtual void GetDisplayResolutions( DisplayResolutions &out ) const = 0;
virtual void GetDisplaySpecs(DisplaySpecs &out) const = 0;
virtual void LogDebugInformation() const { }
virtual bool IsSoftwareRenderer( RString & /* sError */ ) { return false; }
@@ -30,11 +31,13 @@ public:
virtual void SwapBuffers() = 0;
virtual void Update() { }
virtual const VideoModeParams &GetActualVideoModeParams() const = 0;
virtual const ActualVideoModeParams GetActualVideoModeParams() const = 0;
virtual bool SupportsRenderToTexture() const { return false; }
virtual RenderTarget *CreateRenderTarget() { return NULL; }
virtual bool SupportsFullscreenBorderlessWindow() const { return false; };
virtual bool SupportsThreadedRendering() { return false; }
virtual void BeginConcurrentRenderingMainThread() { }
virtual void EndConcurrentRenderingMainThread() { }
@@ -22,12 +22,12 @@ public:
~LowLevelWindow_MacOSX();
void *GetProcAddress( RString s );
RString TryVideoMode( const VideoModeParams& p, bool& newDeviceOut );
void GetDisplayResolutions( DisplayResolutions &dr ) const;
void GetDisplaySpecs( DisplaySpecs &specs ) const;
void SwapBuffers();
void Update();
const VideoModeParams &GetActualVideoModeParams() const { return m_CurrentParams; }
const ActualVideoModeParams GetActualVideoModeParams() const { return m_CurrentParams; }
bool SupportsRenderToTexture() const { return true; }
RenderTarget *CreateRenderTarget();
@@ -1,6 +1,6 @@
#import "global.h"
#import "LowLevelWindow_MacOSX.h"
#import "DisplayResolutions.h"
#import "DisplaySpec.h"
#import "RageUtil.h"
#import "RageThreads.h"
#import "RageDisplay_OGL_Helpers.h"
@@ -109,7 +109,7 @@ public:
- (void) setParams:(NSValue *)params
{
const VideoModeParams &p = *(const VideoModeParams *)[params pointerValue];
NSRect contentRect = { { 0, 0 }, { p.width, p.height } };
NSRect contentRect = { { 0, 0 }, { static_cast<CGFloat>(p.width), static_cast<CGFloat>(p.height) } };
[m_Window setContentSize:contentRect.size];
[m_Window setTitle:[NSString stringWithUTF8String:p.sWindowTitle.c_str()]];
@@ -564,28 +564,50 @@ static bool GetBoolValue( CFTypeRef r )
return r && CFGetTypeID( r ) == CFBooleanGetTypeID() && CFBooleanGetValue( CFBooleanRef(r) );
}
void LowLevelWindow_MacOSX::GetDisplayResolutions( DisplayResolutions &dr ) const
static double GetDoubleValue( CFTypeRef r )
{
double ret;
if( !r || CFGetTypeID(r) != CFNumberGetTypeID() || !CFNumberGetValue(CFNumberRef(r), kCFNumberDoubleType, &ret) )
return 0;
return ret;
}
static DisplayMode ConvertDisplayMode( CFDictionaryRef dict )
{
int width = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayWidth) );
int height = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayHeight) );
double rate = GetDoubleValue( CFDictionaryGetValue(dict, kCGDisplayRefreshRate) );
return { static_cast<unsigned int> (width), static_cast<unsigned int> (height), rate};
}
void LowLevelWindow_MacOSX::GetDisplaySpecs( DisplaySpecs &specs ) const
{
CFArrayRef modes = CGDisplayAvailableModes( kCGDirectMainDisplay );
ASSERT( modes );
const CFIndex count = CFArrayGetCount( modes );
std::set<DisplayMode> available;
CFDictionaryRef currentModeDict = CGDisplayCurrentMode( kCGDirectMainDisplay );
DisplayMode current = ConvertDisplayMode( currentModeDict );
for( CFIndex i = 0; i < count; ++i )
{
CFDictionaryRef dict = (CFDictionaryRef)CFArrayGetValueAtIndex( modes, i );
int width = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayWidth) );
int height = GetIntValue( CFDictionaryGetValue(dict, kCGDisplayHeight) );
CFTypeRef safe = CFDictionaryGetValue( dict, kCGDisplayModeIsSafeForHardware );
bool stretched = GetBoolValue( CFDictionaryGetValue(dict, kCGDisplayModeIsStretched) );
if( !width || !height )
DisplayMode mode = ConvertDisplayMode( dict );
if( !mode.width || !mode.height )
continue;
if( safe && !GetBoolValue( safe ) )
continue;
DisplayResolution res = { width, height, stretched };
dr.insert( res );
available.insert( mode );
}
// Do not release modes! We don't own them here.
RectI bounds( 0, 0, current.width, current.height );
DisplaySpec s( "", "Fullscreen", available, current, bounds );
specs.insert( s );
}
void LowLevelWindow_MacOSX::SwapBuffers()
@@ -59,9 +59,9 @@ LowLevelWindow_Win32::~LowLevelWindow_Win32()
GraphicsWindow::Shutdown();
}
void LowLevelWindow_Win32::GetDisplayResolutions( DisplayResolutions &out ) const
void LowLevelWindow_Win32::GetDisplaySpecs( DisplaySpecs &out ) const
{
GraphicsWindow::GetDisplayResolutions( out );
GraphicsWindow::GetDisplaySpecs( out );
}
int ChooseWindowPixelFormat( const VideoModeParams &p, PIXELFORMATDESCRIPTOR *pixfmt )
@@ -292,7 +292,7 @@ void LowLevelWindow_Win32::Update()
GraphicsWindow::Update();
}
const VideoModeParams &LowLevelWindow_Win32::GetActualVideoModeParams() const
const ActualVideoModeParams LowLevelWindow_Win32::GetActualVideoModeParams() const
{
return GraphicsWindow::GetParams();
}
@@ -10,7 +10,7 @@ public:
~LowLevelWindow_Win32();
void *GetProcAddress( RString s );
RString TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut );
void GetDisplayResolutions( DisplayResolutions &out ) const;
void GetDisplaySpecs( DisplaySpecs &out ) const;
bool IsSoftwareRenderer( RString &sError );
void SwapBuffers();
void Update();
@@ -20,7 +20,7 @@ public:
virtual bool SupportsRenderToTexture() const { return true; }
virtual RenderTarget *CreateRenderTarget();
const VideoModeParams &GetActualVideoModeParams() const;
const ActualVideoModeParams GetActualVideoModeParams() const;
};
#ifdef ARCH_LOW_LEVEL_WINDOW
+545 -116
View File
@@ -5,31 +5,54 @@
#include "archutils/Unix/X11Helper.h"
#include "PrefsManager.h" // XXX
#include "RageDisplay.h" // VideoModeParams
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "LocalizedString.h"
#include "RageDisplay_OGL_Helpers.h"
using namespace RageDisplay_Legacy_Helpers;
using namespace X11Helper;
#include <stack>
#include <set>
#include <math.h> // ceil()
#include <GL/glxew.h>
#define GLX_GLXEXT_PROTOTYPES
#include <GL/glx.h> // All sorts of stuff...
#include <X11/Xlib.h>
#include <X11/Xatom.h>
#include <X11/extensions/Xrandr.h>
#if defined(HAVE_XINERAMA)
#include <X11/extensions/Xinerama.h>
#endif
#if defined(HAVE_LIBXTST)
#include <X11/extensions/XTest.h>
#endif
// Display ID for treating the entire X screen as the display
const std::string ID_XSCREEN = "XSCREEN_RANDR";
static GLXContext g_pContext = NULL;
static GLXContext g_pBackgroundContext = NULL;
static Window g_AltWindow = None;
static Rotation g_OldRotation;
static int g_iOldSize;
XRRScreenConfiguration *g_pScreenConfig = NULL;
static bool g_bChangedScreenSize = false;
static SizeID g_iOldSize = None;
static Rotation g_OldRotation = RR_Rotate_0;
static XRRScreenConfiguration *g_pScreenConfig = nullptr;
static RRMode g_originalRandRMode = None;
static RROutput g_usedCrtc = None;
static int g_iRandRVerMinor = 0;
static int g_iRandRVerMajor = 0;
static bool g_bUseXRandR12 = false;
static bool g_bUseXinerama = false;
inline float calcRandRRefresh( unsigned long iPixelClock, int iHTotal, int iVTotal )
{
// Pixel Clock divided by total pixels in mode,
// not just those onscreen!
return ( iPixelClock ) / ( iHTotal * iVTotal );
}
bool NetWMSupported(Display *Dpy, Atom feature);
static LocalizedString FAILED_CONNECTION_XSERVER( "LowLevelWindow_X11", "Failed to establish a connection with the X server" );
LowLevelWindow_X11::LowLevelWindow_X11()
@@ -37,6 +60,18 @@ LowLevelWindow_X11::LowLevelWindow_X11()
if( !OpenXConnection() )
RageException::Throw( "%s", FAILED_CONNECTION_XSERVER.GetValue().c_str() );
if( XRRQueryVersion( Dpy, &g_iRandRVerMajor, &g_iRandRVerMinor ) && g_iRandRVerMajor >= 1 && g_iRandRVerMinor >= 2) g_bUseXRandR12 = true;
#ifdef HAVE_XINERAMA
int xinerama_event_base = 0;
int xinerama_error_base = 0;
Atom fullscreen_monitors = XInternAtom( Dpy, "_NET_WM_FULLSCREEN_MONITORS", False );
if (XineramaQueryExtension( Dpy, &xinerama_event_base, &xinerama_error_base ) &&
NetWMSupported( Dpy, fullscreen_monitors ))
{
g_bUseXinerama = true;
}
#endif
const int iScreen = DefaultScreen( Dpy );
int iXServerVersion = XVendorRelease( Dpy ); /* eg. 40201001 */
int iMajor = iXServerVersion / 10000000; iXServerVersion %= 10000000;
@@ -50,7 +85,6 @@ LowLevelWindow_X11::LowLevelWindow_X11()
LOG->Info( "Client GLX vendor: %s [%s]", glXGetClientString( Dpy, GLX_VENDOR ), glXGetClientString( Dpy, GLX_VERSION ) );
m_bWasWindowed = true;
g_pScreenConfig = XRRGetScreenInfo( Dpy, RootWindow(Dpy, DefaultScreen(Dpy)) );
g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation );
}
LowLevelWindow_X11::~LowLevelWindow_X11()
@@ -58,8 +92,7 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
// Reset the display
if( !m_bWasWindowed )
{
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime );
RestoreOutputConfig();
XUngrabKeyboard( Dpy, CurrentTime );
}
if( g_pContext )
@@ -72,9 +105,6 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
glXDestroyContext( Dpy, g_pBackgroundContext );
g_pBackgroundContext = NULL;
}
XRRFreeScreenConfigInfo( g_pScreenConfig );
g_pScreenConfig = NULL;
XDestroyWindow( Dpy, Win );
Win = None;
XDestroyWindow( Dpy, g_AltWindow );
@@ -82,6 +112,29 @@ LowLevelWindow_X11::~LowLevelWindow_X11()
CloseXConnection();
}
/*
* Restore saved X screen/CRTC configuration
*/
void LowLevelWindow_X11::RestoreOutputConfig() {
if (g_bChangedScreenSize) {
XRRSetScreenConfig(Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation,
CurrentTime);
}
if (g_usedCrtc != None) {
ASSERT(g_bUseXRandR12);
XRRScreenResources *res = XRRGetScreenResources(Dpy, Win);
XRRCrtcInfo *conf = XRRGetCrtcInfo(Dpy, res, g_usedCrtc);
XRRSetCrtcConfig(Dpy, res, g_usedCrtc, conf->timestamp, conf->x, conf->y, g_originalRandRMode, conf->rotation,
conf->outputs, conf->noutput);
XRRFreeScreenResources(res);
XRRFreeCrtcInfo(conf);
}
g_iOldSize = None;
g_bChangedScreenSize = false;
g_usedCrtc = None;
g_OldRotation = RR_Rotate_0;
}
void *LowLevelWindow_X11::GetProcAddress( RString s )
{
// XXX: We should check whether glXGetProcAddress or
@@ -92,19 +145,20 @@ void *LowLevelWindow_X11::GetProcAddress( RString s )
RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDeviceOut )
{
#if defined(UNIX)
/* nVidia cards:
* This only works the first time we set up a window; after that, the
* drivers appear to cache the value, so you have to actually restart
* the program to change it again. */
static char buf[128];
strcpy( buf, "__GL_SYNC_TO_VBLANK=" );
strcat( buf, p.vsync?"1":"0" );
putenv( buf );
#endif
// We're going to be interested in MapNotify/ConfigureNotify events in this routine,
// so ensure our event mask includes these, restore it on exit
XWindowAttributes winAttrib;
auto restore = [&](XWindowAttributes *attr) { XSelectInput( Dpy, Win, attr->your_event_mask );};
auto restoreAttrib = std::unique_ptr<XWindowAttributes, decltype(restore)>(&winAttrib, restore);
// These might change if we're rendering at different resolution than window
int windowWidth = p.width;
int windowHeight = p.height;
bool renderOffscreen = false;
if( g_pContext == NULL || p.bpp != CurrentParams.bpp || m_bWasWindowed != p.windowed )
{
bool bFirstRun = g_pContext == NULL;
// Different depth, or we didn't make a window before. New context.
bNewDeviceOut = true;
@@ -156,128 +210,377 @@ RString LowLevelWindow_X11::TryVideoMode( const VideoModeParams &p, bool &bNewDe
glXMakeCurrent( Dpy, Win, g_pContext );
// Map the window, ensuring we get the MapNotify event
XWindowAttributes winAttrib;
XGetWindowAttributes( Dpy, Win, &winAttrib );
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask );
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask | PropertyChangeMask );
XMapWindow( Dpy, Win );
// Wait until we actually have a mapped window before trying to
// use it!
XEvent event;
do
{
XNextEvent( Dpy, &event );
} while (event.type != MapNotify);
XEvent ev;
do {XWindowEvent( Dpy, Win, StructureNotifyMask, &ev );}
while ( ev.type != MapNotify);
// Set the event mask back to what it was
XSelectInput( Dpy, Win, winAttrib.your_event_mask );
// I can't find official docs saying what happens if you re-init GLEW.
// I'll just assume the behavior is undefined.
if(bFirstRun)
{
GLenum err = glewInit();
ASSERT( err == GLEW_OK );
}
}
else
{
// We're remodeling the existing window, and not touching the context.
bNewDeviceOut = false;
XGetWindowAttributes( Dpy, Win, &winAttrib );
XSelectInput( Dpy, Win, winAttrib.your_event_mask | StructureNotifyMask | PropertyChangeMask );
if( !p.windowed )
{
// X11 is an asynchronous beast. If we're resizing an existing
// window directly (i.e. override-redirect as opposed to asking the
// WM to do it) and don't wait for the window to actually be
// resized, we'll get unexpected results from glViewport() etc. I
// don't know why, or why it *doesn't* break in the slower process
// of waiting for the WM to resize the window.
// So, set the event mask so we're notified when the window is resized...
// Send the resize command...
XResizeWindow( Dpy, Win, static_cast<unsigned int> (p.width), static_cast<unsigned int> (p.height) );
// We'll wait for the notification once we've done everything else,
// to save time.
}
}
float rate = 60; // Will be unchanged if windowed. Not sure I care.
if( !p.windowed )
{
if( m_bWasWindowed )
{
RestoreOutputConfig();
if (p.sDisplayId == ID_XSCREEN || p.sDisplayId.empty()) {
// If the user changed the resolution while StepMania was windowed we overwrite the resolution to restore with it at exit.
g_iOldSize = XRRConfigCurrentConfiguration( g_pScreenConfig, &g_OldRotation );
m_bWasWindowed = false;
}
// Find a matching mode.
int iSizesXct;
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct );
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
// Find a matching mode.
int iSizesXct;
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen(Dpy), &iSizesXct );
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
int iSizeMatch = -1;
int iSizeMatch = -1;
for( int i = 0; i < iSizesXct; ++i )
{
if( pSizesX[i].width == p.width && pSizesX[i].height == p.height )
{
iSizeMatch = i;
break;
for (int i = 0; i < iSizesXct; ++i) {
if (pSizesX[i].width == p.width && pSizesX[i].height == p.height) {
iSizeMatch = i;
break;
}
}
if (iSizeMatch != g_iOldSize) {
g_bChangedScreenSize = true;
}
}
// Set this mode.
// XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr)
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime );
// Set this mode.
// XXX: This doesn't handle if the config has changed since we queried it (see man Xrandr)
Status s = XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), iSizeMatch, 1, CurrentTime );
if (s)
{
return "Failed to set screen config";
}
XMoveWindow( Dpy, Win, 0, 0 );
XRaiseWindow( Dpy, Win );
// We want to prevent the WM from catching anything that comes from the keyboard.
// We should do this every time on fullscreen and not only we entering from windowed mode because we could lose focus at resolution change and that will leave the user input locked.
while (XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ));
} else {
ASSERT(g_bUseXRandR12);
/* === Configuring a specific CRTC === */
// Arcane and undocumented but PROPER XRandR 1.2 method.
// What we do is directly reconfigure the CRTC of the primary display,
// Which prevents the (RandR) screen itself from resizing, and therefore
// leaving user's desktop unmolested.
LOG->Info("LowLevelWindow_X11: Using XRandR");
XRRScreenResources *scrRes = XRRGetScreenResources(Dpy, Win);
ASSERT(scrRes != NULL);
ASSERT(scrRes->ncrtc > 0);
ASSERT(scrRes->noutput > 0);
ASSERT(scrRes->nmode > 0);
// If an output name has been specified, search for it
RROutput targetOut = None;
if (p.sDisplayId.length() > 0) {
for (unsigned int i = 0; i < scrRes->noutput && targetOut == None; ++i) {
XRROutputInfo *outInfo = XRRGetOutputInfo(Dpy, scrRes, scrRes->outputs[i]);
std::string outName = std::string(outInfo->name, static_cast<unsigned int> (outInfo->nameLen));
if (p.sDisplayId == outName) {
targetOut = scrRes->outputs[i];
}
XRRFreeOutputInfo(outInfo);
}
}
if (targetOut == None) {
LOG->Info("Did not find display output %s, trying another", p.sDisplayId.c_str());
// didn't find named output, pick primary/or at least one that works
if (g_iRandRVerMajor >= 1 && g_iRandRVerMinor >= 3) {
// RandR 1.3 can tell us what the primary display is.
targetOut = XRRGetOutputPrimary(Dpy, Win);
} else {
// Only RandR 1.2. We'll look for a "Connected" output, or if we can't find that,
// (it is possible the connection state could be unknown), we'll at least
// look for an output with a CRTC driving it
RROutput connected = None, hasCrtc = None;
for (unsigned int i = 0; i < scrRes->noutput; ++i) {
XRROutputInfo *outInfo = XRRGetOutputInfo(Dpy, scrRes, scrRes->outputs[i]);
if (outInfo->connection == RR_Connected) { // Check for CONNECTED state: Connected == 0
connected = scrRes->outputs[i];
}
if (outInfo->crtc != None) {
hasCrtc = outInfo->crtc;
}
XRRFreeOutputInfo(outInfo);
}
targetOut = connected != None ? connected : hasCrtc;
ASSERT(targetOut != None);
}
}
// if the target output is not currently being driven by a crtc,
// find an unused crtc that can be connected to it
XRROutputInfo *tgtOutInfo = XRRGetOutputInfo( Dpy, scrRes, targetOut );
if (tgtOutInfo == NULL)
{
XRRFreeScreenResources(scrRes);
return "Failed to find XRROutput";
}
RRCrtc tgtOutCrtc = tgtOutInfo->crtc;
if (tgtOutCrtc == None)
{
for (unsigned int i = 0; i < tgtOutInfo->ncrtc; ++i)
{
XRRCrtcInfo *crtcInfo = XRRGetCrtcInfo( Dpy, scrRes, tgtOutInfo->crtcs[i] );
if (crtcInfo->mode == None)
{
tgtOutCrtc = tgtOutInfo->crtcs[i];
}
XRRFreeCrtcInfo( crtcInfo );
}
}
ASSERT(tgtOutCrtc != None);
XRRCrtcInfo *oldConf = XRRGetCrtcInfo( Dpy, scrRes, tgtOutCrtc );
float fRefreshDiff = 99999;
float fRefreshRate = 0;
RRMode mode = None;
// A quirk of XRandR is that the width and height are as the display
// controller ("CRTC") sees it, which means height and width are
// flipped if there's rotation going on.
const bool bPortrait = (oldConf->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0;
// Find a mode that matches our exact wanted resolution,
// with as close to our desired refresh rate as possible.
for (int i = 0; i < scrRes->nmode; i++) {
const XRRModeInfo &thisMI = scrRes->modes[i];
const unsigned int modeWidth = bPortrait ? thisMI.height : thisMI.width;
const unsigned int modeHeight = bPortrait ? thisMI.width : thisMI.height;
if (modeWidth == p.width && modeHeight == p.height) {
float fTempRefresh = calcRandRRefresh(thisMI.dotClock, thisMI.hTotal, thisMI.vTotal);
float fTempDiff = std::abs(p.rate - fTempRefresh);
if ((p.rate != REFRESH_DEFAULT && fTempDiff < fRefreshDiff) ||
(p.rate == REFRESH_DEFAULT && fTempRefresh > fRefreshRate)) {
int j;
// Ensure that the output supports the mode
for (j = 0; j < tgtOutInfo->nmode; j++)
if (tgtOutInfo->modes[j] == scrRes->modes[i].id) {
mode = tgtOutInfo->modes[j];
break;
}
if (j < tgtOutInfo->nmode) {
fRefreshRate = fTempRefresh;
fRefreshDiff = fTempDiff;
}
}
}
}
rate = roundf(fRefreshRate);
g_usedCrtc = tgtOutCrtc;
g_originalRandRMode = oldConf->mode;
const std::string tgtOutName = std::string(tgtOutInfo->name, static_cast<unsigned int> (tgtOutInfo->nameLen));
LOG->Info("XRandR output config using CRTC %lu in mode %lu, driving output %s",
g_usedCrtc, mode, tgtOutName.c_str());
// and FIRE!
Status s = XRRSetCrtcConfig(Dpy, scrRes, g_usedCrtc, oldConf->timestamp, oldConf->x, oldConf->y, mode,
oldConf->rotation, oldConf->outputs, oldConf->noutput);
if (s) {
XRRFreeCrtcInfo(oldConf);
XRRFreeOutputInfo(tgtOutInfo);
XRRFreeScreenResources(scrRes);
return "Failed to set CRTC config";
}
// We don't move to absolute 0,0 because that may be in the area of a different output.
// Instead we preserved the corner of our CRTC; go to that.
XMoveWindow(Dpy, Win, oldConf->x, oldConf->y);
// Final cleanup
XRRFreeCrtcInfo(oldConf);
XRRFreeOutputInfo(tgtOutInfo);
XRRFreeScreenResources(scrRes);
}
m_bWasWindowed = false;
XRaiseWindow( Dpy, Win );
// We want to prevent the WM from catching anything that comes from the keyboard.
// We should do this every time on fullscreen and not only we entering from windowed mode because we could lose focus at resolution change and that will leave the user input locked.
XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime );
while (XGrabKeyboard( Dpy, Win, True, GrabModeAsync, GrabModeAsync, CurrentTime ));
}
else
else // if(p.windowed)
{
if( !m_bWasWindowed )
{
XRRSetScreenConfig( Dpy, g_pScreenConfig, RootWindow(Dpy, DefaultScreen(Dpy)), g_iOldSize, g_OldRotation, CurrentTime );
// In windowed mode, we actually want the WM to function normally.
// Release any previous grab.
// Return the display to the mode it was in before we fullscreened.
RestoreOutputConfig();
XUngrabKeyboard( Dpy, CurrentTime );
m_bWasWindowed = true;
}
Atom net_wm_state = XInternAtom( Dpy, "_NET_WM_STATE", False );
Atom fullscreen_state = XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False );
Atom maximized_vert = XInternAtom( Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False );
Atom maximized_horz = XInternAtom( Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False );
// if FSBW, find matching monitor, move window to its origin,
// then set fullscreen hint, and set the CurrentParams.outWidth, CurrentParams.outHeight to the values of that display
// otherwise set the size hints and disable MAXIMIZED_*
if (p.bWindowIsFullscreenBorderless)
{
auto specs = DisplaySpecs{};
GetDisplaySpecs( specs );
auto target = std::find_if( specs.begin(), specs.end(), [&]( const DisplaySpec &spec ) {
return p.sDisplayId == spec.id() && spec.currentMode() != nullptr;
} );
// If we didn't find a matching DisplaySpec for the requested ID, pick the first one with a current mode
if (target == specs.end())
{
target = std::find_if( specs.begin(), specs.end(), [&]( const DisplaySpec &spec ) {
return spec.currentMode() != nullptr;
} );
}
// If we _still_ haven't found anything (unlikely), then just give up
if (target == specs.end())
{
return "Unable to find destination monitor for fullscreen borderless";
}
windowWidth = target->currentMode()->width;
windowHeight = target->currentMode()->height;
if (windowWidth != p.width || windowHeight != p.height)
{
renderOffscreen = true;
}
// Reset anything that might've been set previously:
// (1) Undo Min/Max size bounds
// (2) Remove FULLSCREEN/MAXIMIZED_{HORIZ,VERT} hints
// Without doing this, WM may not let us move/resize window to new display
// Give Window manager the chance to react to changes (otherwise, Mutter had problems
// properly reacting to moving a _NET_WM_STATE_FULLSCREEN window to a different output
// and fullscreen resetting FULLSCREEN hint.
XSizeHints hints;
hints.flags = 0;
XSetWMNormalHints( Dpy, Win, &hints );
#if defined(HAVE_XINERAMA)
if (!g_bUseXinerama || !SetWMFullscreenMonitors( *target ))
#endif
{
SetWMState( winAttrib.root, Win, 0, maximized_horz );
SetWMState( winAttrib.root, Win, 0, maximized_vert );
SetWMState( winAttrib.root, Win, 0, fullscreen_state );
XFlush( Dpy );
XResizeWindow( Dpy, Win, static_cast<unsigned int> (windowWidth), static_cast<unsigned int> (windowHeight) );
XMoveWindow( Dpy, Win, target->currentBounds().left, target->currentBounds().top );
XRaiseWindow( Dpy, Win );
SetWMState( winAttrib.root, Win, 1, fullscreen_state );
SetWMState( winAttrib.root, Win, 1, maximized_horz );
SetWMState( winAttrib.root, Win, 1, maximized_vert );
}
} else
{
windowWidth = p.width;
windowHeight = p.height;
SetWMState( winAttrib.root, Win, 0, fullscreen_state );
// Make a window fixed size, don't let resize it or maximize it.
// Do this before resizing the window so that pane-style WMs (Ion,
// ratpoison) don't resize us back inappropriately.
{
XSizeHints hints;
hints.flags = PMinSize|PMaxSize|PWinGravity;
hints.min_width = hints.max_width = windowWidth;
hints.min_height = hints.max_height = windowHeight;
hints.win_gravity = CenterGravity;
XSetWMNormalHints( Dpy, Win, &hints );
}
/* Workaround for metacity and compiz: if the window have the same
* resolution or higher than the screen, it gets automaximized even
* when the window is set to not let it happen. This happens when
* changing from fullscreen to window mode and our screen resolution
* is bigger. */
{
SetWMState( winAttrib.root, Win, 1, maximized_vert );
SetWMState( winAttrib.root, Win, 1, maximized_horz );
// This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running.
// Commented out per the patch at http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=398
//XMoveWindow( Dpy, Win, 0, 0 );
}
}
}
// NOTE: nVidia's implementation of this is broken by default.
// The only ways around this are mucking with xorg.conf or querying
// nvidia-settings with "$ nvidia-settings -t -q RefreshRate".
int rate = XRRConfigCurrentRate( g_pScreenConfig );
// Make a window fixed size, don't let resize it or maximize it.
// Do this before resizing the window so that pane-style WMs (Ion,
// ratpoison) don't resize us back inappropriately.
{
XSizeHints hints;
hints.flags = PMinSize|PMaxSize|PWinGravity;
hints.min_width = hints.max_width = p.width;
hints.min_height = hints.max_height = p.height;
hints.win_gravity = CenterGravity;
XSetWMNormalHints( Dpy, Win, &hints );
}
/* Workaround for metacity and compiz: if the window have the same
* resolution or higher than the screen, it gets automaximized even
* when the window is set to not let it happen. This happens when
* changing from fullscreen to window mode and our screen resolution
* is bigger. */
{
XEvent xev;
Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False);
Atom maximized_vert = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_VERT", False);
Atom maximized_horz = XInternAtom(Dpy, "_NET_WM_STATE_MAXIMIZED_HORZ", False);
memset(&xev, 0, sizeof(xev));
xev.type = ClientMessage;
xev.xclient.window = Win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = 1;
xev.xclient.data.l[1] = maximized_vert;
xev.xclient.data.l[2] = 0;
XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev);
xev.xclient.data.l[1] = maximized_horz;
XSendEvent(Dpy, DefaultRootWindow(Dpy), False, SubstructureNotifyMask, &xev);
// This one is needed for compiz, if the window reaches out of bounds of the screen it becames destroyed, only the window, the program is left running.
// Commented out per the patch at http://ssc.ajworld.net/sm-ssc/bugtracker/view.php?id=398
//XMoveWindow( Dpy, Win, 0, 0 );
}
// Resize the window.
XResizeWindow( Dpy, Win, p.width, p.height );
CurrentParams = p;
CurrentParams.rate = rate;
CurrentParams.windowWidth = windowWidth;
CurrentParams.windowHeight = windowHeight;
CurrentParams.renderOffscreen = renderOffscreen;
ASSERT( rate > 0 );
CurrentParams.rate = static_cast<int> (roundf(rate));
if (!p.windowed)
{
// Set our V-sync hint.
if (GLXEW_EXT_swap_control) // I haven't seen this actually implemented yet, but why not.
glXSwapIntervalEXT( Dpy, Win, CurrentParams.vsync ? 1 : 0 );
// XXX: These two might be server-global. I should look into whether
// to try to preserve the original value on exit.
#ifdef GLXEW_MESA_swap_control // Added in 1.7. 1.6 is still common out there apparently.
else if(GLXEW_MESA_swap_control) // Haven't seen this NOT implemented yet
glXSwapIntervalMESA( CurrentParams.vsync ? 1 : 0 );
#endif
else if (GLXEW_SGI_swap_control) // But old GLEW.
glXSwapIntervalSGI( CurrentParams.vsync ? 1 : 0 );
else
CurrentParams.vsync = false; // Assuming it's not on
}
return ""; // Success
}
@@ -332,16 +635,114 @@ void LowLevelWindow_X11::SwapBuffers()
}
}
void LowLevelWindow_X11::GetDisplayResolutions( DisplayResolutions &out ) const
{
int iSizesXct;
XRRScreenSize *pSizesX = XRRSizes( Dpy, DefaultScreen( Dpy ), &iSizesXct );
ASSERT_M( iSizesXct != 0, "Couldn't get resolution list from X server" );
void LowLevelWindow_X11::GetDisplaySpecs(DisplaySpecs &out) const {
int screenNum = DefaultScreen(Dpy);
Screen *screen = ScreenOfDisplay(Dpy, screenNum);
for( int i = 0; i < iSizesXct; ++i )
{
DisplayResolution res = { pSizesX[i].width, pSizesX[i].height, true };
out.insert( res );
XWindowAttributes winAttr = XWindowAttributes();
if (XGetWindowAttributes(Dpy, Win, &winAttr)) {
screen = winAttr.screen;
screenNum = XScreenNumberOfScreen(screen);
}
// Create a display spec for the entire X screen itself
// First get current config
Rotation curRotation;
XRRScreenConfiguration *screenConf = XRRGetScreenInfo(Dpy, Win);
const short curRate = XRRConfigCurrentRate(screenConf);
SizeID curSizeId = XRRConfigCurrentConfiguration(screenConf, &curRotation);
// curRotation does not factor into how we report supported XScreen sizes:
// XRR reports the supported *screen* sizes with height/width swapped appropriately
// for currently configured rotation. Supported sizes for *output* modes (below)
// DO NOT account for screen rotation
std::set<DisplayMode> screenModes;
int nsizes = 0;
XRRScreenSize *screenSizes = XRRSizes( Dpy, screenNum, &nsizes);
DisplayMode screenCurMode = {0};
for (unsigned int szIdx = 0, mode_idx = 0; szIdx < nsizes; ++szIdx) {
XRRScreenSize &size = screenSizes[szIdx];
int nrates = 0;
short *rates = XRRRates(Dpy, screenNum, szIdx, &nrates);
for (unsigned int rIdx = 0; rIdx < nrates; ++rIdx, ++mode_idx) {
DisplayMode m = {static_cast<unsigned int> (size.width), static_cast<unsigned int> (size.height), static_cast<double> (rates[rIdx])};
screenModes.insert(m);
if (rates[rIdx] == curRate && szIdx == curSizeId) {
screenCurMode = m;
}
}
}
const RectI screenBounds( 0, 0, screenSizes[curSizeId].width, screenSizes[curSizeId].height);
const DisplaySpec screenSpec( ID_XSCREEN, "X Screen", screenModes, screenCurMode, screenBounds, true);
out.insert(screenSpec);
// XRRScreenSize array from XRRSizes does *not* have to be returned (valgrind said XFree was an invalid
// free in a small test program, there is no XRRFreeScreenSize, etc)
XRRFreeScreenConfigInfo(screenConf);
if (g_bUseXRandR12) {
// Build per-output DisplaySpecs
// First, get the list of resolutions that'll be referenced (by RRMode) in each
// OutputInfo
XRRScreenResources *scrRes = XRRGetScreenResources(Dpy, Win);
std::map<RRMode, DisplayMode> outputModes;
for (unsigned int i = 0; i < scrRes->nmode; ++i) {
const XRRModeInfo &mode = scrRes->modes[i];
DisplayMode m = {mode.width, mode.height,
calcRandRRefresh(mode.dotClock, mode.hTotal, mode.vTotal)};
outputModes[mode.id] = m;
}
// Now, for each output, build a corresponding DisplaySpec
for (unsigned int outIdx = 0; outIdx < scrRes->noutput; ++outIdx)
{
XRROutputInfo *outInfo = XRRGetOutputInfo( Dpy, scrRes, scrRes->outputs[outIdx] );
if (outInfo->nmode > 0)
{
// Get the current configuration of the Output, if it's being driven by
// a crtc
RRMode curRRMode = None;
bool bPortrait = false;
int crtcX = 0, crtcY = 0;
if (outInfo->crtc != None)
{
XRRCrtcInfo *conf = XRRGetCrtcInfo( Dpy, scrRes, outInfo->crtc );
curRRMode = conf->mode;
bPortrait = (conf->rotation & (RR_Rotate_90 | RR_Rotate_270)) != 0;
crtcX = conf->x;
crtcY = conf->y;
XRRFreeCrtcInfo( conf );
}
// Get all supported modes, noting which one, if any, is currently active
std::set<DisplayMode> outputSupported;
DisplayMode outputCurMode = {0};
RectI outBounds;
for (unsigned int modeIdx = 0; modeIdx < outInfo->nmode; ++modeIdx)
{
DisplayMode mode = outputModes[outInfo->modes[modeIdx]];
unsigned int modeWidth = bPortrait ? mode.height : mode.width;
unsigned int modeHeight = bPortrait ? mode.width : mode.height;
DisplayMode m = {modeWidth, modeHeight, mode.refreshRate};
outputSupported.insert( m );
if (curRRMode != None && outInfo->modes[modeIdx] == curRRMode)
{
outputCurMode = m;
outBounds = RectI( crtcX, crtcY, crtcX + modeWidth, crtcY + modeHeight);
}
}
const std::string outId( outInfo->name, static_cast<unsigned int> (outInfo->nameLen) );
const std::string outName( outId );
if (curRRMode != None)
{
out.insert( DisplaySpec( outId, outName, outputSupported, outputCurMode, outBounds ));
} else
{
out.insert( DisplaySpec( outId, outName, outputSupported ));
}
}
XRRFreeOutputInfo( outInfo );
}
XRRFreeScreenResources( scrRes );
}
}
@@ -512,6 +913,34 @@ bool LowLevelWindow_X11::SupportsRenderToTexture() const
return true;
}
bool NetWMSupported(Display *Dpy, Atom feature)
{
Atom net_supported = XInternAtom( Dpy, "_NET_SUPPORTED", False );
Atom actual_type_return = BadAtom;
int actual_format_return = 0;
unsigned long nitems_return = 0;
unsigned long bytes_after_return = 0;
Atom *prop_return;
Status status = XGetWindowProperty( Dpy, RootWindow( Dpy, DefaultScreen( Dpy )), net_supported, 0, 8192, False,
XA_ATOM, &actual_type_return,
&actual_format_return, &nitems_return, &bytes_after_return,
reinterpret_cast<unsigned char **> (&prop_return));
if (status != Success)
{
return false;
}
auto supported = std::find( prop_return, prop_return + nitems_return, feature ) != prop_return + nitems_return;
XFree( prop_return );
return supported;
}
bool LowLevelWindow_X11::SupportsFullscreenBorderlessWindow() const
{
Atom fullscreen = XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False );
return NetWMSupported( Dpy, fullscreen );
}
RenderTarget *LowLevelWindow_X11::CreateRenderTarget()
{
return new RenderTarget_X11( this );
+7 -3
View File
@@ -18,13 +18,15 @@ public:
bool IsSoftwareRenderer( RString &sError );
void SwapBuffers();
const VideoModeParams &GetActualVideoModeParams() const { return CurrentParams; }
const ActualVideoModeParams GetActualVideoModeParams() const { return CurrentParams; }
void GetDisplayResolutions( DisplayResolutions &out ) const;
void GetDisplaySpecs(DisplaySpecs &out) const;
bool SupportsRenderToTexture() const;
RenderTarget *CreateRenderTarget();
bool SupportsFullscreenBorderlessWindow() const;
bool SupportsThreadedRendering();
void BeginConcurrentRenderingMainThread();
void EndConcurrentRenderingMainThread();
@@ -32,8 +34,10 @@ public:
void EndConcurrentRendering();
private:
void RestoreOutputConfig();
bool m_bWasWindowed;
VideoModeParams CurrentParams;
ActualVideoModeParams CurrentParams;
};
#ifdef ARCH_LOW_LEVEL_WINDOW
-1
View File
@@ -5,7 +5,6 @@
extern "C" int sm_main( int argc, char *argv[] );
#define HAVE_CXA_DEMANGLE
#define HAVE_PTHREAD_COND_TIMEDWAIT
/* This must be defined to 1 because autoconf's AC_CHECK_DECLS macro decides to define
* this in all cases. If only they could be consistent... */
#define HAVE_DECL_SIGUSR1 1
+96
View File
@@ -129,6 +129,23 @@ bool X11Helper::MakeWindow( Window &win, int screenNum, int depth, Visual *visua
return true;
}
void X11Helper::SetWMState( const Window &root, const Window &win, const long action, const Atom atom )
{
if ( !Dpy )
return;
Atom wm_state = XInternAtom(Dpy, "_NET_WM_STATE", False);
XEvent xev;
memset( &xev, 0, sizeof( xev ));
xev.type = ClientMessage;
xev.xclient.window = Win;
xev.xclient.message_type = wm_state;
xev.xclient.format = 32;
xev.xclient.data.l[0] = action; // 0 = Remove, 1 = Add, 2 = Toggle
xev.xclient.data.l[1] = atom;
xev.xclient.data.l[2] = 0; // end list of Atoms
XSendEvent( Dpy, root, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev );
}
int ErrorCallback( Display *d, XErrorEvent *err )
{
char errText[512];
@@ -144,6 +161,85 @@ int FatalCallback( Display *d )
RageException::Throw( "Fatal I/O error communicating with X server." );
}
#ifdef HAVE_XINERAMA
#include <X11/extensions/Xinerama.h>
bool X11Helper::SetWMFullscreenMonitors( const DisplaySpec &target )
{
int num_screens = 0;
XineramaScreenInfo *screens = XineramaQueryScreens( Dpy, &num_screens );
if (screens == nullptr)
{
return false;
}
XineramaScreenInfo *end = screens + num_screens;
RectI monitors{};
bool found_bounds = false;
if (target.isVirtual())
{
auto topmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
return a.y_org < b.y_org;
} );
monitors.top = topmost->screen_number;
auto bottommost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
return a.y_org < b.y_org;
} );
monitors.bottom = bottommost->screen_number;
auto leftmost = std::min_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
return a.x_org < b.x_org;
} );
monitors.left = leftmost->screen_number;
auto rightmost = std::max_element( screens, end, []( XineramaScreenInfo &a, XineramaScreenInfo &b ) {
return a.x_org < b.x_org;
} );
monitors.right = rightmost->screen_number;
found_bounds = true;
}
else if (target.currentMode() != nullptr)
{
auto mon = std::find_if( screens, end, [&]( XineramaScreenInfo &screen ) {
return screen.x_org == target.currentBounds().left && screen.y_org == target.currentBounds().top
&& screen.width == target.currentMode()->width && screen.height == target.currentMode()->height;
} );
if (mon != end)
{
monitors.left = monitors.right = monitors.top = monitors.bottom = mon->screen_number;
found_bounds = true;
}
}
XFree( screens );
XWindowAttributes attr = {0};
if (!found_bounds || !XGetWindowAttributes( Dpy, Win, &attr ))
{
return false;
}
SetWMState( attr.root, Win, 1, XInternAtom( Dpy, "_NET_WM_STATE_FULLSCREEN", False ));
XClientMessageEvent xclient = {0};
xclient.type = ClientMessage;
xclient.window = Win;
xclient.message_type = XInternAtom( Dpy, "_NET_WM_FULLSCREEN_MONITORS", False );
xclient.format = 32;
xclient.data.l[0] = monitors.top;
xclient.data.l[1] = monitors.bottom;
xclient.data.l[2] = monitors.left;
xclient.data.l[3] = monitors.right;
xclient.data.l[4] = 1;
XSendEvent( Dpy, attr.root, False, SubstructureRedirectMask | SubstructureNotifyMask,
reinterpret_cast<XEvent *> (&xclient));
XFlush( Dpy );
return true;
}
#endif
/*
* (c) 2005, 2006 Ben Anderson, Steve Checkoway
* All rights reserved.
+8
View File
@@ -4,6 +4,8 @@
#include <X11/Xlib.h> // Window
#include <X11/Xutil.h>
#include <DisplaySpec.h>
namespace X11Helper
{
// All functions in here that return a bool return true on success, and
@@ -25,6 +27,12 @@ namespace X11Helper
// (Re)create the Window win.
bool MakeWindow( Window &win, int screenNum, int depth, Visual *visual,
int width, int height, bool overrideRedirect );
void SetWMState( const Window &root, const Window &win, const long action, const Atom atom );
#ifdef HAVE_XINERAMA
bool SetWMFullscreenMonitors( const DisplaySpec &target );
#endif
};
#endif
+44 -20
View File
@@ -4,7 +4,7 @@
#include "RageLog.h"
#include "RageUtil.h"
#include "RageDisplay.h"
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
#include "arch/ArchHooks/ArchHooks.h"
#include "archutils/Win32/AppInstance.h"
#include "archutils/Win32/Crash.h"
@@ -539,29 +539,53 @@ HWND GraphicsWindow::GetHwnd()
return g_hWndMain;
}
void GraphicsWindow::GetDisplayResolutions( DisplayResolutions &out )
void GraphicsWindow::GetDisplaySpecs( DisplaySpecs &out )
{
DEVMODE dm;
ZERO( dm );
dm.dmSize = sizeof(dm);
int i=0;
while(EnumDisplaySettings(NULL, i++, &dm))
{
const size_t DM_DRIVER_EXTRA_BYTES = 4096;
const size_t DMSIZE = sizeof( DEVMODE ) + DM_DRIVER_EXTRA_BYTES;
auto reset = [=]( std::unique_ptr<DEVMODE> &p ) {
::memset( p.get(), 0, DMSIZE );
p->dmSize = sizeof( DEVMODE );
p->dmDriverExtra = static_cast<WORD> (DM_DRIVER_EXTRA_BYTES);
};
auto isvalid = []( std::unique_ptr<DEVMODE> &dm ) {
// Windows 8 and later don't support less than 32bpp, so don't even test
// for them. GetDisplayResolutions is only for resolutions anyway. -Kyz
if(dm.dmBitsPerPel < 32)
// for them. GetDisplaySpecs only tracks resolution/refresh rate anyway. -Kyz, drewbarbs
return (dm->dmFields & DM_PELSWIDTH) && (dm->dmFields & DM_PELSHEIGHT) && (dm->dmFields & DM_DISPLAYFREQUENCY)
&& (dm->dmBitsPerPel >= 32 || !(dm->dmFields & DM_BITSPERPEL));
};
std::unique_ptr<DEVMODE> dm( static_cast<DEVMODE*> (operator new(DMSIZE)) );
reset( dm );
int i = 0;
std::set<DisplayMode> modes;
while ( EnumDisplaySettingsEx( nullptr, i++, dm.get(), 0 ) )
{
if ( isvalid( dm ) && ChangeDisplaySettingsEx( nullptr, dm.get(), nullptr, CDS_TEST, nullptr ) == DISP_CHANGE_SUCCESSFUL )
{
continue;
}
DisplayResolution res = { dm.dmPelsWidth, dm.dmPelsHeight };
std::set<DisplayResolution>::iterator entry= out.find(res);
if(entry == out.end())
{
if(ChangeDisplaySettings(&dm, CDS_TEST)==DISP_CHANGE_SUCCESSFUL)
{
out.insert(res);
}
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
modes.insert(m);
}
reset( dm );
}
reset( dm );
// Get the current display mode
if ( EnumDisplaySettingsEx( nullptr, ENUM_CURRENT_SETTINGS, dm.get(), 0 ) && isvalid( dm ) )
{
DisplayMode m = { dm->dmPelsWidth, dm->dmPelsHeight, static_cast<double> (dm->dmDisplayFrequency) };
RectI bounds = { 0, 0, static_cast<int> (m.width), static_cast<int> (m.height) };
out.insert( DisplaySpec( "", "Fullscreen", modes, m, bounds ) );
}
else if ( !modes.empty() )
{
LOG->Warn( "Could not retrieve valid current display mode" );
out.insert( DisplaySpec( "", "Fullscreen", *modes.begin() ) );
}
else
{
LOG->Warn( "Could not retrieve *any* DisplaySpec's!" );
}
}
+2 -2
View File
@@ -2,7 +2,7 @@
#define GRAPHICS_WINDOW_H
#include <windows.h>
#include "DisplayResolutions.h"
#include "DisplaySpec.h"
class VideoModeParams;
class DisplayResolution;
@@ -28,7 +28,7 @@ namespace GraphicsWindow
void CreateGraphicsWindow( const VideoModeParams &p, bool bForceRecreateWindow = false );
void DestroyGraphicsWindow();
void GetDisplayResolutions( DisplayResolutions &out );
void GetDisplaySpecs( DisplaySpecs &out );
const VideoModeParams &GetParams();
HDC GetHDC();