The Battle for Wesnoth  1.17.21+dev
video.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2003 - 2023
3  by David White <dave@whitevine.net>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #include "video.hpp"
17 
18 #include "display.hpp"
19 #include "draw_manager.hpp"
20 #include "font/sdl_ttf_compat.hpp"
21 #include "font/text.hpp"
22 #include "log.hpp"
23 #include "picture.hpp"
24 #include "preferences/general.hpp"
25 #include "sdl/input.hpp"
26 #include "sdl/point.hpp"
27 #include "sdl/texture.hpp"
28 #include "sdl/userevent.hpp"
29 #include "sdl/utils.hpp"
30 #include "sdl/window.hpp"
31 #include "widgets/menu.hpp" // for bluebg_style.unload_images
32 
33 #ifdef TARGET_OS_OSX
34 #include "desktop/apple_video.hpp"
35 #include "game_version.hpp"
36 #endif
37 
38 #include <SDL2/SDL_render.h> // SDL_Texture
39 
40 #include <cassert>
41 #include <vector>
42 
43 static lg::log_domain log_display("display");
44 #define LOG_DP LOG_STREAM(info, log_display)
45 #define ERR_DP LOG_STREAM(err, log_display)
46 #define WRN_DP LOG_STREAM(warn, log_display)
47 #define DBG_DP LOG_STREAM(debug, log_display)
48 
49 namespace
50 {
51 /** The SDL window object. Will be null only if headless_. */
52 std::unique_ptr<sdl::window> window;
53 
54 /** The main offscreen render target. */
55 texture render_texture_ = {};
56 
57 /** The current offscreen render target. */
58 texture current_render_target_ = {};
59 
60 bool headless_ = false; /**< running with no window at all */
61 bool testing_ = false; /**< running unit tests */
62 point test_resolution_ = {1024, 768}; /**< resolution for unit tests */
63 int refresh_rate_ = 0;
64 point game_canvas_size_ = {0, 0};
65 int pixel_scale_ = 1;
66 rect input_area_ = {};
67 
68 } // anon namespace
69 
70 namespace video
71 {
72 
73 // Non-public interface
74 void render_screen(); // exposed and used only in draw_manager.cpp
75 
76 // Internal functions
77 static void init_window();
78 static void init_test_window();
79 static void init_fake();
80 static void init_test();
81 static bool update_framebuffer();
82 static bool update_test_framebuffer();
83 static point draw_offset();
84 
85 
86 void init(fake type)
87 {
88  LOG_DP << "initializing video";
89  if(SDL_WasInit(SDL_INIT_VIDEO)) {
90  throw error("video subsystem already initialized");
91  }
92  if(SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
93  ERR_DP << "Could not initialize SDL_video: " << SDL_GetError();
94  throw error("Video initialization failed");
95  }
96 
97  switch(type) {
98  case fake::none:
99  init_window();
100  break;
101  case fake::window:
102  init_fake();
103  break;
104  case fake::draw:
105  init_test();
106  break;
107  default:
108  throw error("unrecognized fake type passed to video::init");
109  }
110 }
111 
112 void deinit()
113 {
114  LOG_DP << "deinitializing video";
115 
116  // SDL_INIT_TIMER is always initialized at program start.
117  // If it is not initialized here, there is a problem.
118  assert(SDL_WasInit(SDL_INIT_TIMER));
119 
120  // Clear any static texture caches,
121  // lest they try to delete textures after SDL_Quit.
124  render_texture_.reset();
125  current_render_target_.reset();
127 
128  // Destroy the window, and thus also the renderer.
129  window.reset();
130 
131  // Close the video subsystem.
132  if(SDL_WasInit(SDL_INIT_VIDEO)) {
133  LOG_DP << "quitting SDL video subsystem";
134  SDL_QuitSubSystem(SDL_INIT_VIDEO);
135  }
136  if(SDL_WasInit(SDL_INIT_VIDEO)) {
137  // This should not have been initialized multiple times
138  throw error("video subsystem still initialized after deinit");
139  }
140 }
141 
142 bool headless()
143 {
144  return headless_;
145 }
146 
147 bool testing()
148 {
149  return testing_;
150 }
151 
152 void init_fake()
153 {
154  headless_ = true;
155  refresh_rate_ = 1;
156  game_canvas_size_ = {800,600};
157 }
158 
159 void init_test()
160 {
161  testing_ = true;
162  refresh_rate_ = 1;
164 }
165 
166 /** Returns true if the buffer was changed */
168 {
169  if (!window) {
170  throw("trying to update test framebuffer with no window");
171  }
172 
173  bool changed = false;
174 
175  // TODO: code unduplication
176  // Build or update the current render texture.
177  if (render_texture_) {
178  int w, h;
179  SDL_QueryTexture(render_texture_, nullptr, nullptr, &w, &h);
180  if (w != test_resolution_.x || h != test_resolution_.y) {
181  // Delete it and let it be recreated.
182  LOG_DP << "destroying old render texture";
183  render_texture_.reset();
184  }
185  }
186  if (!render_texture_) {
187  LOG_DP << "creating offscreen render texture";
188  render_texture_.assign(SDL_CreateTexture(
189  *window,
190  window->pixel_format(),
191  SDL_TEXTUREACCESS_TARGET,
192  test_resolution_.x, test_resolution_.y
193  ));
194  LOG_DP << "updated render target to " << test_resolution_.x
195  << "x" << test_resolution_.y;
196  changed = true;
197  }
198 
199  pixel_scale_ = 1;
200  game_canvas_size_ = test_resolution_;
201  input_area_ = {{}, test_resolution_};
202 
203  // The render texture is always the render target in this case.
204  force_render_target(render_texture_);
205 
206  return changed;
207 }
208 
210 {
211  if (!window) {
212  throw error("trying to update framebuffer with no window");
213  }
214 
215  if (testing_) {
216  return update_test_framebuffer();
217  }
218 
219  bool changed = false;
220 
221  // Make sure we're getting values from the native window.
222  SDL_SetRenderTarget(*window, nullptr);
223 
224  // Non-integer scales are not currently supported.
225  // This option makes things neater when window size is not a perfect
226  // multiple of logical size, which can happen when manually resizing.
227  SDL_RenderSetIntegerScale(*window, SDL_TRUE);
228 
229  // Find max valid pixel scale at current output size.
230  point osize(window->get_output_size());
231  int max_scale = std::min(
234  max_scale = std::min(max_scale, preferences::max_pixel_scale);
235 
236  // Determine best pixel scale according to preference and window size
237  int scale = 1;
239  // Try to match the default size (1280x720) but do not reduce below
240  int def_scale = std::min(
243  scale = std::min(max_scale, def_scale);
244  // Otherwise reduce to keep below the max window size (1920x1080).
245  int min_scale = std::min(
246  osize.x / (preferences::max_window_width+1) + 1,
247  osize.y / (preferences::max_window_height+1) + 1);
248  scale = std::max(scale, min_scale);
249  } else {
250  scale = std::min(max_scale, preferences::pixel_scale());
251  }
252  // Cache it for easy access.
253  if (pixel_scale_ != scale) {
254  pixel_scale_ = scale;
255  changed = true;
256  }
257 
258  // Update logical size if it doesn't match the current resolution and scale.
259  point lsize(window->get_logical_size());
260  point wsize(window->get_size());
261  if (lsize.x != osize.x / scale || lsize.y != osize.y / scale) {
263  LOG_DP << "reducing pixel scale from desired "
264  << preferences::pixel_scale() << " to maximum allowable "
265  << scale;
266  }
267  LOG_DP << "pixel scale: " << scale;
268  LOG_DP << "overriding logical size";
269  LOG_DP << " old lsize: " << lsize;
270  LOG_DP << " old wsize: " << wsize;
271  LOG_DP << " old osize: " << osize;
272  window->set_logical_size(osize.x / scale, osize.y / scale);
273  lsize = window->get_logical_size();
274  wsize = window->get_size();
275  osize = window->get_output_size();
276  LOG_DP << " new lsize: " << lsize;
277  LOG_DP << " new wsize: " << wsize;
278  LOG_DP << " new osize: " << osize;
279  float sx, sy;
280  SDL_RenderGetScale(*window, &sx, &sy);
281  LOG_DP << " render scale: " << sx << ", " << sy;
282  }
283  // Cache it for easy access
284  game_canvas_size_ = lsize;
285 
286  // Build or update the current render texture.
287  if (render_texture_) {
288  int w, h;
289  SDL_QueryTexture(render_texture_, nullptr, nullptr, &w, &h);
290  if (w != osize.x || h != osize.y) {
291  // Delete it and let it be recreated.
292  LOG_DP << "destroying old render texture";
293  render_texture_.reset();
294  }
295  }
296  if (!render_texture_) {
297  LOG_DP << "creating offscreen render texture";
298  render_texture_.assign(SDL_CreateTexture(
299  *window,
300  window->pixel_format(),
301  SDL_TEXTUREACCESS_TARGET,
302  osize.x, osize.y
303  ));
304  // This isn't really necessary, but might be nice to have attached
305  render_texture_.set_draw_size(lsize);
306  changed = true;
307  }
308 
309  // Assign the render texture now. It will be used for all drawing.
310  force_render_target(render_texture_);
311 
312  // By default input area is the same as the window area.
313  input_area_ = {{}, wsize};
314 
315  rect active_area = to_output(draw_area());
316  if (active_area.size() != osize) {
317  LOG_DP << "render target offset: LT " << active_area.pos() << " RB "
318  << osize - active_area.size() - active_area.pos();
319  // Translate active_area into display coordinates as input_area_
320  input_area_ = {
321  (active_area.pos() * wsize) / osize,
322  (active_area.size() * wsize) / osize
323  };
324  LOG_DP << "input area: " << input_area_;
325  }
326 
327  return changed;
328 }
329 
331 {
332  LOG_DP << "creating test window " << test_resolution_.x
333  << "x" << test_resolution_.y;
334 
335  uint32_t window_flags = 0;
336  window_flags |= SDL_WINDOW_HIDDEN;
337  // The actual window won't be used, as we'll be rendering to texture.
338 
339  uint32_t renderer_flags = 0;
340  renderer_flags |= SDL_RENDERER_TARGETTEXTURE;
341  // All we need is to be able to render to texture.
342 
343  window.reset(new sdl::window(
344  "", 0, 0, test_resolution_.x, test_resolution_.y,
345  window_flags, renderer_flags
346  ));
347 
349 }
350 
352 {
353  // Position
354  const int x = preferences::fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
355  const int y = preferences::fullscreen() ? SDL_WINDOWPOS_UNDEFINED : SDL_WINDOWPOS_CENTERED;
356 
357  // Dimensions
358  const point res = preferences::resolution();
359  const int w = res.x;
360  const int h = res.y;
361 
362  uint32_t window_flags = 0;
363 
364  // Add any more default flags here
365  window_flags |= SDL_WINDOW_RESIZABLE;
366  window_flags |= SDL_WINDOW_ALLOW_HIGHDPI;
367 
369  window_flags |= SDL_WINDOW_FULLSCREEN_DESKTOP;
370  } else if(preferences::maximized()) {
371  window_flags |= SDL_WINDOW_MAXIMIZED;
372  }
373 
374  uint32_t renderer_flags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE;
375 
376  if(preferences::vsync()) {
377  LOG_DP << "VSYNC on";
378  renderer_flags |= SDL_RENDERER_PRESENTVSYNC;
379  }
380 
381  // Initialize window
382  window.reset(new sdl::window("", x, y, w, h, window_flags, renderer_flags));
383 
384  // It is assumed that this function is only ever called once.
385  // If that is no longer true, then you should clean things up.
386  assert(!render_texture_);
387 
388  PLAIN_LOG << "Setting mode to " << w << "x" << h;
389 
391 
392  SDL_DisplayMode currentDisplayMode;
393  SDL_GetCurrentDisplayMode(window->get_display_index(), &currentDisplayMode);
394  refresh_rate_ = currentDisplayMode.refresh_rate != 0 ? currentDisplayMode.refresh_rate : 60;
395 
397 }
398 
400 {
401  return bool(window);
402 }
403 
405 {
406  if (testing_) {
407  return test_resolution_;
408  }
409  // As we are rendering via an abstraction, we should never need this.
410  return window->get_output_size();
411 }
412 
414 {
415  if (testing_) {
416  return test_resolution_;
417  }
418  return window->get_size();
419 }
420 
422 {
423  return {0, 0, game_canvas_size_.x, game_canvas_size_.y};
424 }
425 
427 {
428  return game_canvas_size_;
429 }
430 
432 {
433  return current_render_target_.draw_size();
434 }
435 
437 {
438  return {0, 0, current_render_target_.w(), current_render_target_.h()};
439 }
440 
442 {
443  // As we are using SDL_RenderSetIntegerScale, there may be a slight
444  // offset of the drawable area on the render target if the target size
445  // is not perfectly divisble by the scale.
446  // SDL doesn't provide any way of retrieving this offset,
447  // so we just have to base our calculation on the known behaviour.
448  point osize = output_size();
449  point dsize = draw_size();
450  point scale = osize / dsize;
451  return (osize - (scale * dsize)) / 2;
452 }
453 
455 {
456  point p = output_size();
457  return {0, 0, p.x, p.y};
458 }
459 
460 rect to_output(const rect& r)
461 {
462  // Multiply r by integer scale, adding draw_offset to the position.
463  point dsize = current_render_target_.draw_size();
464  point osize = current_render_target_.get_raw_size();
465  point pos = (r.pos() * (osize / dsize)) + draw_offset();
466  point size = r.size() * (osize / dsize);
467  return {pos, size};
468 }
469 
471 {
472  return input_area_;
473 }
474 
476 {
477  return pixel_scale_;
478 }
479 
481 {
482  // TODO: this should be more clever, depending on usage
483  return refresh_rate_;
484 }
485 
487 {
488  if (SDL_SetRenderTarget(get_renderer(), t)) {
489  ERR_DP << "failed to set render target to "
490  << static_cast<void*>(t.get()) << ' '
491  << t.draw_size() << " / " << t.get_raw_size();
492  ERR_DP << "last SDL error: " << SDL_GetError();
493  throw error("failed to set render target");
494  }
495  current_render_target_ = t;
496 
497  if (testing_) {
498  return;
499  }
500 
501  // The scale factor gets reset when the render target changes,
502  // so make sure it gets set back appropriately.
503  if (!t) {
504  DBG_DP << "rendering to window / screen";
505  window->set_logical_size(game_canvas_size_);
506  } else if (t == render_texture_) {
507  DBG_DP << "rendering to primary buffer";
508  window->set_logical_size(game_canvas_size_);
509  } else {
510  DBG_DP << "rendering to custom target "
511  << static_cast<void*>(t.get()) << ' '
512  << t.draw_size() << " / " << t.get_raw_size();
513  window->set_logical_size(t.w(), t.h());
514  }
515 }
516 
518 {
520 }
521 
523 {
524  // This should always be up-to-date, but assert for sanity.
525  assert(current_render_target_ == SDL_GetRenderTarget(get_renderer()));
526  return current_render_target_;
527 }
528 
529 // Note: this is not thread-safe.
530 // Drawing functions should not be called while this is active.
531 // SDL renderer usage is not thread-safe anyway, so this is fine.
533 {
534  if(headless_ || testing_) {
535  // No need to present anything in this case
536  return;
537  }
538 
539  if(!window) {
540  WRN_DP << "trying to render with no window";
541  return;
542  }
543 
544  // This should only ever be called when the main render texture is the
545  // current render target. It could be adapted otherwise... but let's not.
546  if(SDL_GetRenderTarget(*window) != render_texture_) {
547  ERR_DP << "trying to render screen, but current render texture is "
548  << static_cast<void*>(SDL_GetRenderTarget(*window))
549  << " | " << static_cast<void*>(current_render_target_.get())
550  << ". It should be " << static_cast<void*>(render_texture_.get());
551  throw error("tried to render screen from wrong render target");
552  }
553 
554  // Clear the render target so we're drawing to the window.
556 
557  // Copy the render texture to the window.
558  SDL_RenderCopy(*window, render_texture_, nullptr, nullptr);
559 
560  // Finalize and display the frame.
561  SDL_RenderPresent(*window);
562 
563  // Reset the render target to the render texture.
564  force_render_target(render_texture_);
565 }
566 
567 surface read_pixels(SDL_Rect* r)
568 {
569  if (!window) {
570  WRN_DP << "trying to read pixels with no window";
571  return surface();
572  }
573 
574  // This should be what we want to read from.
575  texture& target = current_render_target_;
576 
577  // Make doubly sure.
578  if (target != SDL_GetRenderTarget(*window)) {
579  SDL_Texture* t = SDL_GetRenderTarget(*window);
580  ERR_DP << "render target " << static_cast<void*>(target.get())
581  << ' ' << target.draw_size() << " / " << target.get_raw_size()
582  << " doesn't match window render target "
583  << static_cast<void*>(t);
584  throw error("unexpected render target while reading pixels");
585  }
586 
587  // Intersect the draw area with the given rect.
588  rect r_clipped = draw_area();
589  if (r) {
590  r_clipped.clip(*r);
591  if (r_clipped != *r) {
592  DBG_DP << "modifying pixel read area from " << *r
593  << " to " << r_clipped;
594  *r = r_clipped;
595  }
596  }
597 
598  // Convert the rect to output coordinates, if necessary.
599  rect o = to_output(r_clipped);
600 
601  // Create surface and read pixels
602  surface s(o.w, o.h);
603  SDL_RenderReadPixels(*window, &o, s->format->format, s->pixels, s->pitch);
604  return s;
605 }
606 
608 {
609  if(!window) {
610  WRN_DP << "trying to read pixels with no window";
611  return surface();
612  }
613  surface s = read_pixels(r);
614  if(r) {
615  return scale_surface(s, r->w, r->h);
616  } else {
617  return scale_surface(s, draw_size().x, draw_size().y);
618  }
619 }
620 
621 void set_window_title(const std::string& title)
622 {
623  assert(window);
624  window->set_title(title);
625 }
626 
628 {
629  assert(window);
630  window->set_icon(icon);
631 }
632 
633 SDL_Renderer* get_renderer()
634 {
635  if(window) {
636  return *window;
637  } else {
638  return nullptr;
639  }
640 }
641 
642 SDL_Window* get_window()
643 {
644  return *window;
645 }
646 
647 std::string current_driver()
648 {
649  const char* const drvname = SDL_GetCurrentVideoDriver();
650  return drvname ? drvname : "<not initialized>";
651 }
652 
653 std::vector<std::string> enumerate_drivers()
654 {
655  std::vector<std::string> res;
656  int num_drivers = SDL_GetNumVideoDrivers();
657 
658  for(int n = 0; n < num_drivers; ++n) {
659  const char* drvname = SDL_GetVideoDriver(n);
660  res.emplace_back(drvname ? drvname : "<invalid driver>");
661  }
662 
663  return res;
664 }
665 
666 /**
667  * Tests whether the given flags are currently set on the SDL window.
668  *
669  * @param flags The flags to test, OR'd together.
670  */
671 static bool window_has_flags(uint32_t flags)
672 {
673  return window && (window->get_flags() & flags) != 0;
674 }
675 
677 {
678  return window_has_flags(SDL_WINDOW_SHOWN);
679 }
680 
682 {
683  return window_has_flags(SDL_WINDOW_MOUSE_FOCUS | SDL_WINDOW_INPUT_FOCUS);
684 }
685 
687 {
688  return window_has_flags(SDL_WINDOW_MOUSE_FOCUS);
689 }
690 
691 std::vector<point> get_available_resolutions(const bool include_current)
692 {
693  std::vector<point> result;
694 
695  if(!window) {
696  return result;
697  }
698 
699  const int display_index = window->get_display_index();
700 
701  const int modes = SDL_GetNumDisplayModes(display_index);
702  if(modes <= 0) {
703  PLAIN_LOG << "No modes supported";
704  return result;
705  }
706 
708 
709  // The maximum size to which this window can be set. For some reason this won't
710  // pop up as a display mode of its own.
711  SDL_Rect bounds;
712  SDL_GetDisplayBounds(display_index, &bounds);
713 
714  SDL_DisplayMode mode;
715 
716  for(int i = 0; i < modes; ++i) {
717  if(SDL_GetDisplayMode(display_index, i, &mode) == 0) {
718  // Exclude any results outside the range of the current DPI.
719  if(mode.w > bounds.w && mode.h > bounds.h) {
720  continue;
721  }
722 
723  if(mode.w >= min_res.x && mode.h >= min_res.y) {
724  result.emplace_back(mode.w, mode.h);
725  }
726  }
727  }
728 
729  if(std::find(result.begin(), result.end(), min_res) == result.end()) {
730  result.push_back(min_res);
731  }
732 
733  if(include_current) {
734  result.push_back(current_resolution());
735  }
736 
737  std::sort(result.begin(), result.end());
738  result.erase(std::unique(result.begin(), result.end()), result.end());
739 
740  return result;
741 }
742 
744 {
745  if (testing_) {
746  return test_resolution_;
747  }
748  return point(window->get_size()); // Convert from plain SDL_Point
749 }
750 
752 {
753  if (testing_) {
754  return true;
755  }
756  return (window->get_flags() & SDL_WINDOW_FULLSCREEN_DESKTOP) != 0;
757 }
758 
760 {
761  if (headless_ || testing_) {
762  return;
763  }
764 
765  // Only do anything if the current value differs from the desired value
766  if (window && is_fullscreen() != fullscreen) {
767  if (fullscreen) {
768  window->full_screen();
769  } else if (preferences::maximized()) {
770  window->to_window();
771  window->maximize();
772  } else {
773  window->to_window();
774  window->restore();
775  }
776  update_buffers();
777  }
778 
779  // Update the config value in any case.
781 }
782 
784 {
786 }
787 
789 {
790  if(resolution == current_resolution()) {
791  return false;
792  }
793 
794  if(!window) {
795  throw error("tried to set resolution with no window");
796  }
797 
798  if(testing_) {
799  LOG_DP << "resizing test resolution to " << resolution;
800  test_resolution_ = resolution;
801  return update_test_framebuffer();
802  }
803 
804  window->restore();
805  window->set_size(resolution.x, resolution.y);
806  window->center();
807 
808  update_buffers();
809 
810  // Change the saved values in preferences.
811  LOG_DP << "updating resolution to " << resolution;
814 
815  return true;
816 }
817 
818 void update_buffers(bool autoupdate)
819 {
820  if(headless_) {
821  return;
822  }
823 
824  LOG_DP << "updating video buffers";
825  if(update_framebuffer() && autoupdate) {
827  }
828 }
829 
830 std::pair<float, float> get_dpi()
831 {
832  float hdpi = 0.0f, vdpi = 0.0f;
833  if(window && SDL_GetDisplayDPI(window->get_display_index(), nullptr, &hdpi, &vdpi) == 0) {
834 #ifdef TARGET_OS_OSX
835  // SDL 2.0.12 changes SDL_GetDisplayDPI. Function now returns DPI
836  // multiplied by screen's scale factor. This part of code reverts
837  // this multiplication.
838  //
839  // For more info see issue: https://github.com/wesnoth/wesnoth/issues/5019
840  if(sdl::get_version() >= version_info{2, 0, 12}) {
841  float scale_factor = desktop::apple::get_scale_factor(window->get_display_index());
842  hdpi /= scale_factor;
843  vdpi /= scale_factor;
844  }
845 #endif
846  }
847  return { hdpi, vdpi };
848 }
849 
850 std::vector<std::pair<std::string, std::string>> renderer_report()
851 {
852  std::vector<std::pair<std::string, std::string>> res;
853  SDL_Renderer* rnd;
854  SDL_RendererInfo ri;
855 
856  if(window && (rnd = *window) && SDL_GetRendererInfo(rnd, &ri) == 0) {
857  std::string renderer_name = ri.name ? ri.name : "<unknown>";
858 
859  if(ri.flags & SDL_RENDERER_SOFTWARE) {
860  renderer_name += " (sw)";
861  }
862 
863  if(ri.flags & SDL_RENDERER_ACCELERATED) {
864  renderer_name += " (hw)";
865  }
866 
867  std::string renderer_max = std::to_string(ri.max_texture_width) +
868  'x' +
869  std::to_string(ri.max_texture_height);
870 
871  res.emplace_back("Renderer", renderer_name);
872  res.emplace_back("Maximum texture size", renderer_max);
873  res.emplace_back("VSync", ri.flags & SDL_RENDERER_PRESENTVSYNC ? "on" : "off");
874  }
875 
876  return res;
877 }
878 
879 } // namespace video
double t
Definition: astarsearch.cpp:65
static imgsel_style bluebg_style
Definition: menu.hpp:96
The wrapper class for the SDL_Window class.
Definition: window.hpp:48
Wrapper class to encapsulate creation and management of an SDL_Texture.
Definition: texture.hpp:33
point draw_size() const
The size of the texture in draw-space.
Definition: texture.hpp:122
point get_raw_size() const
The raw internal texture size.
Definition: texture.cpp:112
SDL_Texture * get() const
Definition: texture.hpp:196
Represents version numbers.
std::size_t i
Definition: function.cpp:968
int w
Interfaces for manipulating version numbers of engine, add-ons, etc.
Contains functions for cleanly handling SDL input.
Standard logging facilities (interface).
#define PLAIN_LOG
Definition: log.hpp:262
CGFloat get_scale_factor(int display_index)
void invalidate_all()
Mark the entire screen as requiring redraw.
void point(int x, int y)
Draw a single point.
Definition: draw.cpp:193
void flush_texture_cache()
Flush the rendered text cache.
Definition: text.cpp:65
void flush_cache()
Purges all image caches.
Definition: picture.cpp:225
const int max_window_height
Definition: general.cpp:73
const int def_window_width
Definition: general.cpp:69
bool vsync()
Definition: general.cpp:439
bool maximized()
Definition: general.cpp:429
bool auto_pixel_scale()
Definition: general.cpp:419
const int max_window_width
Definition: general.cpp:72
point resolution()
Definition: general.cpp:392
const int def_window_height
Definition: general.cpp:70
bool fullscreen()
Definition: general.cpp:434
void _set_fullscreen(bool ison)
Definition: general.cpp:455
void _set_maximized(bool ison)
Definition: general.cpp:450
int pixel_scale()
Definition: general.cpp:408
const int max_pixel_scale
Definition: general.cpp:79
const int min_window_height
Definition: general.cpp:67
const int min_window_width
Definition: general.cpp:66
void _set_resolution(const point &res)
Definition: general.cpp:444
version_info get_version()
Returns the runtime SDL version.
Definition: utils.cpp:34
std::size_t size(const std::string &str)
Length in characters of a UTF-8 string.
Definition: unicode.cpp:87
bool window_has_mouse_focus()
True iff the window has mouse focus.
Definition: video.cpp:686
bool headless()
The game is running headless.
Definition: video.cpp:142
rect draw_area()
The current drawable area.
Definition: video.cpp:436
rect output_area()
{0, 0, output_size().x, output_size().y}
Definition: video.cpp:454
void set_window_title(const std::string &title)
Sets the title of the main window.
Definition: video.cpp:621
static void init_fake()
Definition: video.cpp:152
void clear_render_target()
Reset the render target to the main window / screen.
Definition: video.cpp:517
rect to_output(const rect &r)
Convert coordinates in draw space to coordinates in render space.
Definition: video.cpp:460
void render_screen()
Definition: video.cpp:532
std::vector< std::pair< std::string, std::string > > renderer_report()
Provides diagnostic information about the current renderer for the build_info API.
Definition: video.cpp:850
static bool window_has_flags(uint32_t flags)
Tests whether the given flags are currently set on the SDL window.
Definition: video.cpp:671
static bool update_framebuffer()
Definition: video.cpp:209
point output_size()
Returns the size of the final render target.
Definition: video.cpp:404
std::vector< point > get_available_resolutions(const bool include_current)
Returns the list of available screen resolutions.
Definition: video.cpp:691
static bool update_test_framebuffer()
Returns true if the buffer was changed.
Definition: video.cpp:167
void set_window_icon(surface &icon)
Sets the icon of the main window.
Definition: video.cpp:627
bool window_is_visible()
True iff the window is not hidden.
Definition: video.cpp:676
surface read_pixels_low_res(SDL_Rect *r)
The same as read_pixels, but returns a low-resolution surface suitable for use with the old drawing s...
Definition: video.cpp:607
surface read_pixels(SDL_Rect *r)
Copy back a portion of the render target that is already drawn.
Definition: video.cpp:567
void force_render_target(const texture &t)
Set the render target, without any provided way of setting it back.
Definition: video.cpp:486
point game_canvas_size()
The size of the game canvas, in drawing coordinates / game pixels.
Definition: video.cpp:426
SDL_Window * get_window()
Definition: video.cpp:642
bool window_has_focus()
True iff the window has mouse or input focus.
Definition: video.cpp:681
point window_size()
Returns the size of the window in display units / screen coordinates.
Definition: video.cpp:413
bool has_window()
Whether the game has set up a window to render into.
Definition: video.cpp:399
bool testing()
The game is running unit tests.
Definition: video.cpp:147
bool is_fullscreen()
Whether we are currently in fullscreen mode.
Definition: video.cpp:751
std::vector< std::string > enumerate_drivers()
A list of available video drivers.
Definition: video.cpp:653
static void init_window()
Definition: video.cpp:351
rect game_canvas()
The game canvas area, in drawing coordinates.
Definition: video.cpp:421
std::pair< float, float > get_dpi()
Retrieves the current game screen DPI for the build_info API.
Definition: video.cpp:830
static point draw_offset()
Definition: video.cpp:441
int get_pixel_scale()
Get the current active pixel scale multiplier.
Definition: video.cpp:475
point current_resolution()
The current window size in desktop coordinates.
Definition: video.cpp:743
void init(fake type)
Initialize the video subsystem.
Definition: video.cpp:86
void set_fullscreen(bool fullscreen)
Set the fullscreen state.
Definition: video.cpp:759
void deinit()
Deinitialize the video subsystem.
Definition: video.cpp:112
bool set_resolution(const point &resolution)
Set the window resolution.
Definition: video.cpp:788
int current_refresh_rate()
The refresh rate of the screen.
Definition: video.cpp:480
std::string current_driver()
The current video driver in use, or else "<not initialized>".
Definition: video.cpp:647
void toggle_fullscreen()
Toggle fullscreen mode.
Definition: video.cpp:783
SDL_Renderer * get_renderer()
Definition: video.cpp:633
void update_buffers(bool autoupdate)
Update buffers to match current resolution and pixel scale settings.
Definition: video.cpp:818
texture get_render_target()
Get the current render target.
Definition: video.cpp:522
static void init_test()
Definition: video.cpp:159
fake
For describing the type of faked display, if any.
Definition: video.hpp:44
static void init_test_window()
Definition: video.cpp:330
point draw_size()
The size of the current render target in drawing coordinates.
Definition: video.cpp:431
rect input_area()
Returns the input area of the window, in display coordinates.
Definition: video.cpp:470
void scale(size_t factor, const uint32_t *src, uint32_t *trg, int srcWidth, int srcHeight, const ScalerCfg &cfg=ScalerCfg(), int yFirst=0, int yLast=std::numeric_limits< int >::max())
Definition: xbrz.cpp:1190
Contains a wrapper class for the SDL_Window class.
Transitional API for porting SDL_ttf-based code to Pango.
Holds a 2D point.
Definition: point.hpp:25
An abstract description of a rectangle with integer coordinates.
Definition: rect.hpp:47
void clip(const SDL_Rect &r)
Clip this rectangle by the given rectangle.
Definition: rect.cpp:101
constexpr point size() const
Definition: rect.hpp:65
constexpr point pos() const
Definition: rect.hpp:64
An error specifically indicating video subsystem problems.
Definition: video.hpp:307
mock_party p
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...
Definition: utils.cpp:129
#define LOG_DP
Definition: video.cpp:44
#define WRN_DP
Definition: video.cpp:46
static lg::log_domain log_display("display")
#define ERR_DP
Definition: video.cpp:45
#define DBG_DP
Definition: video.cpp:47
#define h