35 #include <SDL2/SDL_render.h>  
   42     SDL_Surface* Android_AP_getFrameBuffer();
 
   47 #define LOG_DP LOG_STREAM(info, log_display) 
   48 #define ERR_DP LOG_STREAM(err, log_display) 
   49 #define WRN_DP LOG_STREAM(warn, log_display) 
   50 #define DBG_DP LOG_STREAM(debug, log_display) 
   55 std::unique_ptr<sdl::window> window;
 
   61 texture current_render_target_ = {};
 
   63 bool headless_ = 
false; 
 
   64 bool testing_ = 
false; 
 
   65 point test_resolution_ = {1024, 768}; 
 
   66 int refresh_rate_ = 0;
 
   67 point game_canvas_size_ = {0, 0};
 
   70 rect input_area_ = {};
 
   92     LOG_DP << 
"initializing video";
 
   93     if(SDL_WasInit(SDL_INIT_VIDEO)) {
 
   94         throw error(
"video subsystem already initialized");
 
   96     if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
 
   97         ERR_DP << 
"Could not initialize SDL_video: " << SDL_GetError();
 
   98         throw error(
"Video initialization failed");
 
  115         throw error(
"unrecognized fake type passed to video::init");
 
  121     LOG_DP << 
"deinitializing video";
 
  125     assert(SDL_WasInit(SDL_INIT_TIMER));
 
  130     render_texture_.reset();
 
  131     current_render_target_.reset();
 
  137     if(SDL_WasInit(SDL_INIT_VIDEO)) {
 
  138         LOG_DP << 
"quitting SDL video subsystem";
 
  139         SDL_QuitSubSystem(SDL_INIT_VIDEO);
 
  141     if(SDL_WasInit(SDL_INIT_VIDEO)) {
 
  143         throw error(
"video subsystem still initialized after deinit");
 
  159     LOG_DP << 
"running headless";
 
  162     game_canvas_size_ = {800,600};
 
  176         throw(
"trying to update test framebuffer with no window");
 
  179     bool changed = 
false;
 
  183     if (render_texture_) {
 
  185         SDL_QueryTexture(render_texture_, 
nullptr, 
nullptr, &
w, &
h);
 
  186         if (
w != test_resolution_.x || 
h != test_resolution_.y) {
 
  188             LOG_DP << 
"destroying old render texture";
 
  189             render_texture_.reset();
 
  192     if (!render_texture_) {
 
  193         LOG_DP << 
"creating offscreen render texture";
 
  194         render_texture_.assign(SDL_CreateTexture(
 
  196             window->pixel_format(),
 
  197             SDL_TEXTUREACCESS_TARGET,
 
  198             test_resolution_.x, test_resolution_.y
 
  200         LOG_DP << 
"updated render target to " << test_resolution_.x
 
  201             << 
"x" << test_resolution_.y;
 
  206     game_canvas_size_ = test_resolution_;
 
  207     input_area_ = {{}, test_resolution_};
 
  218         throw error(
"trying to update framebuffer with no window");
 
  225     bool changed = 
false;
 
  228     SDL_SetRenderTarget(*window, 
nullptr);
 
  233     SDL_RenderSetIntegerScale(*window, SDL_TRUE);
 
  236     point osize(window->get_output_size());
 
  237     max_scale_ = std::min(
 
  246         int def_scale = std::min(
 
  249         scale = std::min(max_scale_, def_scale);
 
  251         int min_scale = std::min(
 
  259     if (pixel_scale_ != 
scale) {
 
  260         pixel_scale_ = 
scale;
 
  265     point lsize(window->get_logical_size());
 
  266     point wsize(window->get_size());
 
  267     if (lsize.x != osize.x / 
scale || lsize.y != osize.y / 
scale) {
 
  269             LOG_DP << 
"reducing pixel scale from desired " 
  274         LOG_DP << 
"overriding logical size";
 
  275         LOG_DP << 
"  old lsize: " << lsize;
 
  276         LOG_DP << 
"  old wsize: " << wsize;
 
  277         LOG_DP << 
"  old osize: " << osize;
 
  278         window->set_logical_size(osize.x / 
scale, osize.y / 
scale);
 
  279         lsize = window->get_logical_size();
 
  280         wsize = window->get_size();
 
  281         osize = window->get_output_size();
 
  282         LOG_DP << 
"  new lsize: " << lsize;
 
  283         LOG_DP << 
"  new wsize: " << wsize;
 
  284         LOG_DP << 
"  new osize: " << osize;
 
  286         SDL_RenderGetScale(*window, &sx, &sy);
 
  287         LOG_DP << 
"  render scale: " << sx << 
", " << sy;
 
  290     game_canvas_size_ = lsize;
 
  293     if (render_texture_) {
 
  295         SDL_QueryTexture(render_texture_, 
nullptr, 
nullptr, &
w, &
h);
 
  296         if (
w != osize.x || 
h != osize.y) {
 
  298             LOG_DP << 
"destroying old render texture";
 
  299             render_texture_.reset();
 
  302             render_texture_.set_draw_size(lsize);
 
  305     if (!render_texture_) {
 
  306         LOG_DP << 
"creating offscreen render texture";
 
  307         render_texture_.assign(SDL_CreateTexture(
 
  309             window->pixel_format(),
 
  310             SDL_TEXTUREACCESS_TARGET,
 
  314         render_texture_.set_draw_size(lsize);
 
  322     input_area_ = {{}, wsize};
 
  325     if (active_area.
size() != osize) {
 
  326         LOG_DP << 
"render target offset: LT " << active_area.
origin() << 
" RB " 
  327                << osize - active_area.
size() - active_area.
origin();
 
  330             (active_area.
origin() * wsize) / osize,
 
  331             (active_area.
size() * wsize) / osize
 
  333         LOG_DP << 
"input area: " << input_area_;
 
  341     LOG_DP << 
"creating test window " << test_resolution_.x
 
  342         << 
"x" << test_resolution_.y;
 
  344     uint32_t window_flags = 0;
 
  345     window_flags |= SDL_WINDOW_HIDDEN;
 
  348     uint32_t renderer_flags = 0;
 
  349     renderer_flags |= SDL_RENDERER_TARGETTEXTURE;
 
  353         "", 0, 0, test_resolution_.x, test_resolution_.y,
 
  354         window_flags, renderer_flags
 
  364     SDL_SetHint(SDL_HINT_RENDER_DRIVER, 
"opengles");
 
  368     const int x = 
prefs::get().fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
 
  369     const int y = 
prefs::get().fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
 
  376     uint32_t window_flags = 0;
 
  379     window_flags |= SDL_WINDOW_RESIZABLE;
 
  380     window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
 
  383         window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
 
  385         window_flags |= SDL_WINDOW_MAXIMIZED;
 
  389         LOG_DP << 
"hiding main window";
 
  390         window_flags |= SDL_WINDOW_HIDDEN;
 
  393     uint32_t renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
 
  397         renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
 
  401     window.reset(
new sdl::window(
"", x, y, 
w, 
h, window_flags, renderer_flags));
 
  405     assert(!render_texture_);
 
  411     SDL_DisplayMode currentDisplayMode;
 
  412     SDL_GetCurrentDisplayMode(window->get_display_index(), ¤tDisplayMode);
 
  413     refresh_rate_ = currentDisplayMode.refresh_rate != 0 ? currentDisplayMode.refresh_rate : 60;
 
  416     window->set_size(
w, 
h);
 
  430         return test_resolution_;
 
  433     return window->get_output_size();
 
  439         return test_resolution_;
 
  441     return window->get_size();
 
  446     return {0, 0, game_canvas_size_.x, game_canvas_size_.y};
 
  451     return game_canvas_size_;
 
  456     return current_render_target_.draw_size();
 
  461     return {0, 0, current_render_target_.w(), current_render_target_.h()};
 
  474     return (osize - (
scale * dsize)) / 2;
 
  480     return {0, 0, 
p.x, 
p.y};
 
  486     point dsize = current_render_target_.draw_size();
 
  487     point osize = current_render_target_.get_raw_size();
 
  510     return refresh_rate_;
 
  516     if(
auto preferred = 
prefs::get().refresh_rate(); preferred > 0) {
 
  517         return std::min(preferred, refresh_rate_);
 
  519         return refresh_rate_;
 
  526         ERR_DP << 
"failed to set render target to " 
  527             << 
static_cast<void*
>(
t.get()) << 
' ' 
  528             << 
t.draw_size() << 
" / " << 
t.get_raw_size();
 
  529         ERR_DP << 
"last SDL error: " << SDL_GetError();
 
  530         throw error(
"failed to set render target");
 
  532     current_render_target_ = 
t;
 
  541         DBG_DP << 
"rendering to window / screen";
 
  542         window->set_logical_size(game_canvas_size_);
 
  543     } 
else if (
t == render_texture_) {
 
  544         DBG_DP << 
"rendering to primary buffer";
 
  545         window->set_logical_size(game_canvas_size_);
 
  547         DBG_DP << 
"rendering to custom target " 
  548             << 
static_cast<void*
>(
t.get()) << 
' ' 
  549             << 
t.draw_size() << 
" / " << 
t.get_raw_size();
 
  550         window->set_logical_size(
t.w(), 
t.h());
 
  568     assert(current_render_target_ == SDL_GetRenderTarget(
get_renderer()));
 
  570     return current_render_target_;
 
  578     if(headless_ || testing_) {
 
  584         WRN_DP << 
"trying to render with no window";
 
  590     if(SDL_GetRenderTarget(*window) != render_texture_) {
 
  591         ERR_DP << 
"trying to render screen, but current render texture is " 
  592             << 
static_cast<void*
>(SDL_GetRenderTarget(*window))
 
  593             << 
" | " << 
static_cast<void*
>(current_render_target_.get())
 
  594             << 
". It should be " << 
static_cast<void*
>(render_texture_.get());
 
  595         throw error(
"tried to render screen from wrong render target");
 
  602     SDL_SetRenderDrawColor(*window, 0u, 0u, 0u, 0u);
 
  605     SDL_RenderClear(*window);
 
  608     SDL_RenderCopy(*window, render_texture_, 
nullptr, 
nullptr);
 
  611     SDL_RenderPresent(*window);
 
  620         WRN_DP << 
"trying to read pixels with no window";
 
  625     texture& target = current_render_target_;
 
  628     if (target != SDL_GetRenderTarget(*window)) {
 
  629         SDL_Texture* 
t = SDL_GetRenderTarget(*window);
 
  630         ERR_DP << 
"render target " << 
static_cast<void*
>(target.
get())
 
  632             << 
" doesn't match window render target " 
  633             << 
static_cast<void*
>(
t);
 
  634         throw error(
"unexpected render target while reading pixels");
 
  641         if (r_clipped != *r) {
 
  642             DBG_DP << 
"modifying pixel read area from " << *r
 
  643                    << 
" to " << r_clipped;
 
  653     SDL_RenderReadPixels(*window, &o, 
s->format->format, 
s->pixels, 
s->pitch);
 
  660         WRN_DP << 
"trying to read pixels with no window";
 
  674     window->set_title(title);
 
  680     window->set_icon(icon);
 
  699     const char* 
const drvname = SDL_GetCurrentVideoDriver();
 
  700     return drvname ? drvname : 
"<not initialized>";
 
  705     std::vector<std::string> res;
 
  706     int num_drivers = SDL_GetNumVideoDrivers();
 
  708     for(
int n = 0; 
n < num_drivers; ++
n) {
 
  709         const char* drvname = SDL_GetVideoDriver(
n);
 
  710         res.emplace_back(drvname ? drvname : 
"<invalid driver>");
 
  723     return window && (window->get_flags() & flags) != 0;
 
  743     std::vector<point> result;
 
  749     const int display_index = window->get_display_index();
 
  751     const int modes = SDL_GetNumDisplayModes(display_index);
 
  762     SDL_GetDisplayBounds(display_index, &bounds);
 
  764     SDL_DisplayMode mode;
 
  766     for(
int i = 0; 
i < modes; ++
i) {
 
  767         if(SDL_GetDisplayMode(display_index, 
i, &mode) == 0) {
 
  769             if(mode.w > bounds.w && mode.h > bounds.h) {
 
  773             if(mode.w >= min_res.x && mode.h >= min_res.y) {
 
  774                 result.emplace_back(mode.w, mode.h);
 
  780         result.push_back(min_res);
 
  783     if(include_current) {
 
  787     std::sort(result.begin(), result.end());
 
  788     result.erase(std::unique(result.begin(), result.end()), result.end());
 
  796         return test_resolution_;
 
  798     return window->get_size();
 
  806     return (window->get_flags() & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
 
  811     if (headless_ || testing_) {
 
  818             window->full_screen();
 
  845         throw error(
"tried to set resolution with no window");
 
  849         LOG_DP << 
"resizing test resolution to " << resolution;
 
  850         test_resolution_ = resolution;
 
  855     window->set_size(resolution.x, resolution.y);
 
  861     LOG_DP << 
"updating resolution to " << resolution;
 
  874     LOG_DP << 
"updating video buffers";
 
  882     float hdpi = 0.0f, vdpi = 0.0f;
 
  883     if(window && SDL_GetDisplayDPI(window->get_display_index(), 
nullptr, &hdpi, &vdpi) == 0) {
 
  892             hdpi /= scale_factor;
 
  893             vdpi /= scale_factor;
 
  897     return { hdpi, vdpi };
 
  902     std::vector<std::pair<std::string, std::string>> res;
 
  906     if(window && (rnd = *window) && SDL_GetRendererInfo(rnd, &ri) == 0) {
 
  907         std::string renderer_name = ri.name ? ri.name : 
"<unknown>";
 
  909         if(ri.flags & SDL_RENDERER_SOFTWARE) {
 
  910             renderer_name += 
" (sw)";
 
  913         if(ri.flags & SDL_RENDERER_ACCELERATED) {
 
  914             renderer_name += 
" (hw)";
 
  917         std::string renderer_max = std::to_string(ri.max_texture_width) +
 
  919                                    std::to_string(ri.max_texture_height);
 
  921         res.emplace_back(
"Renderer", renderer_name);
 
  922         res.emplace_back(
"Maximum texture size", renderer_max);
 
  923         res.emplace_back(
"VSync", ri.flags & SDL_RENDERER_PRESENTVSYNC ? 
"on" : 
"off");
 
void set_resolution(const point &res)
 
The wrapper class for the SDL_Window class.
 
Wrapper class to encapsulate creation and management of an SDL_Texture.
 
point draw_size() const
The size of the texture in draw-space.
 
point get_raw_size() const
The raw internal texture size.
 
SDL_Texture * get() const
 
Represents version numbers.
 
Interfaces for manipulating version numbers of engine, add-ons, etc.
 
Standard logging facilities (interface).
 
CGFloat get_scale_factor(int display_index)
 
void invalidate_all()
Mark the entire screen as requiring redraw.
 
void flush_cache()
Purges all image caches.
 
const int min_window_height
 
const int max_pixel_scale
 
const int def_window_width
 
const int min_window_width
 
const int max_window_height
 
const int max_window_width
 
const int def_window_height
 
version_info get_version()
Returns the runtime SDL version.
 
std::size_t size(std::string_view str)
Length in characters of a UTF-8 string.
 
bool contains(const Container &container, const Value &value)
Returns true iff value is found in container.
 
bool window_has_mouse_focus()
True iff the window has mouse focus.
 
bool headless()
The game is running headless.
 
rect draw_area()
The current drawable area.
 
rect output_area()
{0, 0, output_size().x, output_size().y}
 
void set_window_title(const std::string &title)
Sets the title of the main window.
 
void clear_render_target()
Reset the render target to the main window / screen.
 
rect to_output(const rect &r)
Convert coordinates in draw space to coordinates in render space.
 
std::vector< std::pair< std::string, std::string > > renderer_report()
Provides diagnostic information about the current renderer for the build_info API.
 
static bool window_has_flags(uint32_t flags)
Tests whether the given flags are currently set on the SDL window.
 
static bool update_framebuffer()
 
void reset_render_target()
Reset the render target to the primary render buffer.
 
point output_size()
Returns the size of the final render target.
 
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
 
static bool update_test_framebuffer()
Returns true if the buffer was changed.
 
void set_window_icon(surface &icon)
Sets the icon of the main window.
 
int get_max_pixel_scale()
 
bool window_is_visible()
True iff the window is not hidden.
 
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
 
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
 
SDL_Window * get_window()
 
bool window_has_focus()
True iff the window has mouse or input focus.
 
point window_size()
Returns the size of the window in display units / screen coordinates.
 
bool has_window()
Whether the game has set up a window to render into.
 
bool testing()
The game is running unit tests.
 
bool is_fullscreen()
Whether we are currently in fullscreen mode.
 
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
 
rect game_canvas()
The game canvas area, in drawing coordinates.
 
std::pair< float, float > get_dpi()
Retrieves the current game screen DPI for the build_info API.
 
static point draw_offset()
 
int get_pixel_scale()
Get the current active pixel scale multiplier.
 
static void init_window(bool hidden=false)
 
point current_resolution()
The current window size in desktop coordinates.
 
int native_refresh_rate()
The native refresh rate of display, not taking any user preferences into account.
 
void init(fake type)
Initialize the video subsystem.
 
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
 
void deinit()
Deinitialize the video subsystem.
 
bool set_resolution(const point &resolution)
Set the window resolution.
 
int current_refresh_rate()
The refresh rate of the screen.
 
surface read_pixels_low_res(rect *r)
The same as read_pixels, but returns a low-resolution surface suitable for use with the old drawing s...
 
std::string current_driver()
The current video driver in use, or else "<not initialized>".
 
surface read_pixels(rect *r)
Copy back a portion of the render target that is already drawn.
 
void toggle_fullscreen()
Toggle fullscreen mode.
 
SDL_Renderer * get_renderer()
 
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
 
texture get_render_target()
Get the current render target.
 
fake
For describing the type of faked display, if any.
 
static void init_test_window()
 
point draw_size()
The size of the current render target in drawing coordinates.
 
rect input_area()
Returns the input area of the window, in display coordinates.
 
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, ColorFormat colFmt, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
 
Contains a wrapper class for the SDL_Window class.
 
An abstract description of a rectangle with integer coordinates.
 
void clip(const rect &r)
Clip this rectangle by the given rectangle.
 
constexpr point origin() const
 
constexpr point size() const
 
An error specifically indicating video subsystem problems.
 
static map_location::direction n
 
static map_location::direction s
 
surface scale_surface(const surface &surf, int w, int h)
Scale a surface using alpha-weighted modified bilinear filtering Note: causes artifacts with alpha gr...
 
static lg::log_domain log_display("display")