OpenTTD Source 20260129-master-g2bb01bd0e4
cocoa_ogl.mm
Go to the documentation of this file.
1/*
2 * This file is part of OpenTTD.
3 * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
4 * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
5 * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see <https://www.gnu.org/licenses/old-licenses/gpl-2.0>.
6 */
7
18#if defined(WITH_COCOA) || defined(DOXYGEN_API)
19
20#include "../../stdafx.h"
21#include "../../os/macosx/macos.h"
22
24#define GL_SILENCE_DEPRECATION
25
26#include "../../os/macosx/macos_objective_c.h"
27#include "../../openttd.h"
28#include "../../debug.h"
29#include "../../core/geometry_func.hpp"
30#include "../../core/math_func.hpp"
31#include "cocoa_ogl.h"
32#include "cocoa_wnd.h"
33#include "../../blitter/factory.hpp"
34#include "../../gfx_func.h"
35#include "../../framerate_type.h"
36#include "../opengl.h"
37
38#import <dlfcn.h>
39#import <OpenGL/OpenGL.h>
40#import <OpenGL/gl3.h>
41
43
45static OGLProc GetOGLProcAddressCallback(const char *proc)
46{
47 static void *dl = nullptr;
48
49 if (dl == nullptr) {
50 dl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
51 }
52
53 return reinterpret_cast<OGLProc>(dlsym(dl, proc));
54}
55
56@interface OTTD_CGLLayer : CAOpenGLLayer {
57@private
58 CGLContextObj _context;
59}
60
61@property (class) bool allowSoftware;
62+ (CGLPixelFormatObj)defaultPixelFormat;
63
64- (instancetype)initWithContext:(CGLContextObj)context;
65@end
66
67@implementation OTTD_CGLLayer
68
69static bool _allowSoftware;
70+ (bool)allowSoftware
71{
72 return _allowSoftware;
73}
74+ (void)setAllowSoftware:(bool)newVal
75{
76 _allowSoftware = newVal;
77}
78
79- (instancetype)initWithContext:(CGLContextObj)context
80{
81 if (self = [ super init ]) {
82 self->_context = context;
83
84 self.opaque = YES;
85 self.magnificationFilter = kCAFilterNearest;
86 }
87 return self;
88}
89
90+ (CGLPixelFormatObj)defaultPixelFormat
91{
92 CGLPixelFormatAttribute attribs[] = {
93 kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
94 kCGLPFAColorSize, (CGLPixelFormatAttribute)24,
95 kCGLPFAAlphaSize, (CGLPixelFormatAttribute)0,
96 kCGLPFADepthSize, (CGLPixelFormatAttribute)0,
97 kCGLPFADoubleBuffer,
98 kCGLPFAAllowOfflineRenderers,
99 kCGLPFASupportsAutomaticGraphicsSwitching,
100 kCGLPFANoRecovery,
101 _allowSoftware ? (CGLPixelFormatAttribute)0 : kCGLPFAAccelerated,
102 (CGLPixelFormatAttribute)0
103 };
104
105 CGLPixelFormatObj pxfmt = nullptr;
106 GLint numPixelFormats;
107 CGLChoosePixelFormat(attribs, &pxfmt, &numPixelFormats);
108
109 return pxfmt;
110}
111
112- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
113{
114 return [ OTTD_CGLLayer defaultPixelFormat ];
115}
116
117- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pf
118{
119 CGLContextObj ctx;
120 CGLCreateContext(pf, self->_context, &ctx);
121
122 /* Set context state that is not shared. */
123 CGLSetCurrentContext(ctx);
124 OpenGLBackend::Get()->PrepareContext();
125
126 return ctx;
127}
128
129- (void)drawInCGLContext:(CGLContextObj)ctx pixelFormat:(CGLPixelFormatObj)pf forLayerTime:(CFTimeInterval)t displayTime:(nullable const CVTimeStamp *)ts
130{
131 CGLSetCurrentContext(ctx);
132
135
136 [ super drawInCGLContext:ctx pixelFormat:pf forLayerTime:t displayTime:ts ];
137}
138@end
139
140@interface OTTD_CGLLayerView : NSView
141- (instancetype)initWithFrame:(NSRect)frameRect context:(CGLContextObj)context;
142@end
143
144@implementation OTTD_CGLLayerView
145
146- (instancetype)initWithFrame:(NSRect)frameRect context:(CGLContextObj)context
147{
148 if (self = [ super initWithFrame:frameRect ]) {
149 /* We manage our content updates ourselves. */
150 self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
151
152 /* Create backing layer. */
153 CALayer *l = [ [ OTTD_CGLLayer alloc ] initWithContext:context ];
154 self.layer = l;
155 self.wantsLayer = YES;
156 [ l release ];
157 }
158 return self;
159}
160
161- (BOOL)acceptsFirstResponder
162{
163 return NO;
164}
165
166- (BOOL)isOpaque
167{
168 return YES;
169}
170
171- (void)viewDidChangeBackingProperties
172{
173 self.layer.contentsScale = _allow_hidpi_window && [ self.window respondsToSelector:@selector(backingScaleFactor) ] ? [ self.window backingScaleFactor ] : 1.0f;
174}
175@end
176
177
180
181
182std::optional<std::string_view> VideoDriver_CocoaOpenGL::Start(const StringList &param)
183{
184 auto err = this->Initialize();
185 if (err) return err;
186
188 if (bpp != 8 && bpp != 32) {
189 this->Stop();
190 return "The cocoa OpenGL subdriver only supports 8 and 32 bpp.";
191 }
192
193 /* Try to allocate GL context. */
194 err = this->AllocateContext(GetDriverParamBool(param, "software"));
195 if (err) {
196 this->Stop();
197 return err;
198 }
199
200 this->driver_info = GetName();
201 this->driver_info += " (";
202 this->driver_info += OpenGLBackend::Get()->GetDriverName();
203 this->driver_info += ")";
204
205 bool fullscreen = _fullscreen;
206 if (!this->MakeWindow(_cur_resolution.width, _cur_resolution.height)) {
207 this->Stop();
208 return "Could not create window";
209 }
210
211 this->AllocateBackingStore(true);
212
213 if (fullscreen) this->ToggleFullscreen(fullscreen);
214
215 this->GameSizeChanged();
216 this->UpdateVideoModes();
218
219 this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
220
221 return std::nullopt;
222
223}
224
226{
228
229 CGLSetCurrentContext(this->gl_context);
231 CGLReleaseContext(this->gl_context);
232}
233
240
242{
244
245 CGLSetCurrentContext(this->gl_context);
247}
248
249std::optional<std::string_view> VideoDriver_CocoaOpenGL::AllocateContext(bool allow_software)
250{
251 [ OTTD_CGLLayer setAllowSoftware:allow_software ];
252
253 CGLPixelFormatObj pxfmt = [ OTTD_CGLLayer defaultPixelFormat ];
254 if (pxfmt == nullptr) return "No suitable pixel format found";
255
256 CGLCreateContext(pxfmt, nullptr, &this->gl_context);
257 CGLDestroyPixelFormat(pxfmt);
258
259 if (this->gl_context == nullptr) return "Can't create a rendering context";
260
261 CGLSetCurrentContext(this->gl_context);
262
263 return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
264}
265
266NSView *VideoDriver_CocoaOpenGL::AllocateDrawView()
267{
268 return [ [ OTTD_CGLLayerView alloc ] initWithFrame:this->cocoaview.bounds context:this->gl_context ];
269}
270
273{
274 if (this->window == nil || this->setup) return;
275
276 if (_screen.dst_ptr != nullptr) this->ReleaseVideoPointer();
277
278 CGLSetCurrentContext(this->gl_context);
279 NSRect frame = [ this->cocoaview getRealRect:[ this->cocoaview frame ] ];
280 OpenGLBackend::Get()->Resize(frame.size.width, frame.size.height, force);
281 if (this->buffer_locked) _screen.dst_ptr = this->GetVideoPointer();
282 this->dirty_rect = {};
283
284 /* Redraw screen */
285 this->GameSizeChanged();
286}
287
289{
290 CGLSetCurrentContext(this->gl_context);
291 if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
292 this->anim_buffer = OpenGLBackend::Get()->GetAnimBuffer();
293 }
295}
296
298{
299 CGLSetCurrentContext(this->gl_context);
300
301 if (this->anim_buffer != nullptr) OpenGLBackend::Get()->ReleaseAnimBuffer(this->dirty_rect);
302 OpenGLBackend::Get()->ReleaseVideoBuffer(this->dirty_rect);
303 this->dirty_rect = {};
304 _screen.dst_ptr = nullptr;
305 this->anim_buffer = nullptr;
306}
307
309{
311
314
315 /* Always push a changed palette to OpenGL. */
316 CGLSetCurrentContext(this->gl_context);
320 }
321 }
322
323 [ CATransaction begin ];
324 [ this->cocoaview.subviews[0].layer setNeedsDisplay ];
325 [ CATransaction commit ];
326}
327
328#endif /* WITH_COCOA or DOXYGEN_API */
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:136
How all blitters should look like.
Definition base.hpp:29
virtual uint8_t GetScreenDepth()=0
Get the screen depth this blitter works for.
virtual Blitter::PaletteAnimation UsePaletteAnimation()=0
Check if the blitter uses palette animation at all.
virtual void PaletteAnimate(const Palette &palette)=0
Called when the 8bpp palette is changed; you should redraw all pixels on the screen that are equal to...
@ Blitter
The blitter takes care of the palette animation.
void Paint()
Render video buffer to the screen.
Definition opengl.cpp:1039
uint8_t * GetAnimBuffer()
Get a pointer to the memory for the separate animation buffer.
Definition opengl.cpp:1170
void * GetVideoBuffer()
Get a pointer to the memory for the video driver to draw to.
Definition opengl.cpp:1148
bool Resize(int w, int h, bool force=false)
Change the size of the drawing window and allocate matching resources.
Definition opengl.cpp:913
static std::optional< std::string_view > Create(GetOGLProcAddressProc get_proc, const Dimension &screen_res)
Create and initialize the singleton back-end class.
Definition opengl.cpp:464
void UpdatePalette(const Colour *pal, uint first, uint length)
Update the stored palette.
Definition opengl.cpp:1025
void ReleaseAnimBuffer(const Rect &update_rect)
Update animation buffer texture after the animation buffer was filled.
Definition opengl.cpp:1231
void ClearCursorCache()
Queue a request for cursor cache clear.
Definition opengl.cpp:1135
static OpenGLBackend * Get()
Get singleton instance of this class.
Definition opengl.h:83
void DrawMouseCursor()
Draw mouse cursor on screen.
Definition opengl.cpp:1071
void ReleaseVideoBuffer(const Rect &update_rect)
Update video buffer texture after the video buffer was filled.
Definition opengl.cpp:1193
static void Destroy()
Free resources and destroy singleton back-end class.
Definition opengl.cpp:477
RAII class for measuring simple elements of performance.
void * GetVideoPointer() override
Get a pointer to the video buffer.
Definition cocoa_ogl.mm:288
void PopulateSystemSprites() override
Populate all sprites in cache.
Definition cocoa_ogl.mm:234
void ReleaseVideoPointer() override
Hand video buffer back to the drawing backend.
Definition cocoa_ogl.mm:297
std::optional< std::string_view > Start(const StringList &param) override
Start this driver.
Definition cocoa_ogl.mm:182
void Paint() override
Paint the window.
Definition cocoa_ogl.mm:308
void ClearSystemSprites() override
Clear all cached sprites.
Definition cocoa_ogl.mm:241
void Stop() override
Stop Cocoa video driver.
Definition cocoa_ogl.mm:225
void AllocateBackingStore(bool force=false) override
Resize the window.
Definition cocoa_ogl.mm:272
void PopulateSystemSprites() override
Populate all sprites in cache.
Definition cocoa_v.mm:202
void ClearSystemSprites() override
Clear all cached sprites.
Definition cocoa_v.mm:197
void Stop() override
Stop Cocoa video driver.
Definition cocoa_v.mm:84
The Cocoa OpenGL video driver.
static FVideoDriver_CocoaOpenGL iFVideoDriver_CocoaOpenGL
Storage for instance of the FVideoDriver_CocoaOpenGL class.
Definition cocoa_ogl.mm:179
static Palette _local_palette
Current palette to use for drawing.
Definition cocoa_ogl.mm:42
static OGLProc GetOGLProcAddressCallback(const char *proc)
Platform-specific callback to get an OpenGL function pointer.
Definition cocoa_ogl.mm:45
OS interface for the cocoa video driver.
bool _allow_hidpi_window
Storage for allow_hidpi setting. If true renders OTTD in native resolution.
Definition cocoa_wnd.mm:69
bool GetDriverParamBool(const StringList &parm, std::string_view name)
Get a boolean parameter the list of parameters.
Definition driver.cpp:67
Dimension _cur_resolution
The current resolution.
Definition driver.cpp:29
@ PFE_VIDEO
Speed of painting drawn video buffer.
void GameSizeChanged()
Size of the application screen changed.
Definition main_gui.cpp:596
void MarkWholeScreenDirty()
This function mark the whole screen as dirty.
Definition gfx.cpp:1549
@ Stop
Go to the depot and stop there.
bool CopyPalette(Palette &local_palette, bool force_copy)
Copy the current palette if the palette was updated.
Definition palette.cpp:225
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60
Information about the currently used palette.
Definition gfx_type.h:373
int first_dirty
The first dirty element.
Definition gfx_type.h:375
int count_dirty
The number of dirty elements.
Definition gfx_type.h:376
Colour palette[256]
Current palette. Entry 0 has to be always fully transparent!
Definition gfx_type.h:374