OpenTTD Source 20260311-master-g511d3794ce
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
17
18#if defined(WITH_COCOA) || defined(DOXYGEN_API)
19
20#include "../../stdafx.h"
22
24#define GL_SILENCE_DEPRECATION
25
27#include "../../openttd.h"
28#include "../../debug.h"
31#include "cocoa_ogl.h"
32#include "cocoa_wnd.h"
34#include "../../gfx_func.h"
36#include "../opengl.h"
37
38#import <dlfcn.h>
39#import <OpenGL/OpenGL.h>
40#import <OpenGL/gl3.h>
41
42static Palette _local_palette;
43
49static OGLProc GetOGLProcAddressCallback(const char *proc)
50{
51 static void *dl = nullptr;
52
53 if (dl == nullptr) {
54 dl = dlopen("/System/Library/Frameworks/OpenGL.framework/Versions/Current/OpenGL", RTLD_LAZY);
55 }
56
57 return reinterpret_cast<OGLProc>(dlsym(dl, proc));
58}
59
60@interface OTTD_CGLLayer : CAOpenGLLayer {
61@private
62 CGLContextObj _context;
63}
64
65@property (class) bool allowSoftware;
66+ (CGLPixelFormatObj)defaultPixelFormat;
67
68- (instancetype)initWithContext:(CGLContextObj)context;
69@end
70
71@implementation OTTD_CGLLayer
72
73static bool _allowSoftware;
74+ (bool)allowSoftware
75{
76 return _allowSoftware;
77}
78+ (void)setAllowSoftware:(bool)newVal
79{
80 _allowSoftware = newVal;
81}
82
83- (instancetype)initWithContext:(CGLContextObj)context
84{
85 if (self = [ super init ]) {
86 self->_context = context;
87
88 self.opaque = YES;
89 self.magnificationFilter = kCAFilterNearest;
90 }
91 return self;
92}
93
94+ (CGLPixelFormatObj)defaultPixelFormat
95{
96 CGLPixelFormatAttribute attribs[] = {
97 kCGLPFAOpenGLProfile, (CGLPixelFormatAttribute)kCGLOGLPVersion_3_2_Core,
98 kCGLPFAColorSize, (CGLPixelFormatAttribute)24,
99 kCGLPFAAlphaSize, (CGLPixelFormatAttribute)0,
100 kCGLPFADepthSize, (CGLPixelFormatAttribute)0,
101 kCGLPFADoubleBuffer,
102 kCGLPFAAllowOfflineRenderers,
103 kCGLPFASupportsAutomaticGraphicsSwitching,
104 kCGLPFANoRecovery,
105 _allowSoftware ? (CGLPixelFormatAttribute)0 : kCGLPFAAccelerated,
106 (CGLPixelFormatAttribute)0
107 };
108
109 CGLPixelFormatObj pxfmt = nullptr;
110 GLint numPixelFormats;
111 CGLChoosePixelFormat(attribs, &pxfmt, &numPixelFormats);
112
113 return pxfmt;
114}
115
116- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask
117{
118 return [ OTTD_CGLLayer defaultPixelFormat ];
119}
120
121- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pf
122{
123 CGLContextObj ctx;
124 CGLCreateContext(pf, self->_context, &ctx);
125
126 /* Set context state that is not shared. */
127 CGLSetCurrentContext(ctx);
128 OpenGLBackend::Get()->PrepareContext();
129
130 return ctx;
131}
132
133- (void)drawInCGLContext:(CGLContextObj)ctx pixelFormat:(CGLPixelFormatObj)pf forLayerTime:(CFTimeInterval)t displayTime:(nullable const CVTimeStamp *)ts
134{
135 CGLSetCurrentContext(ctx);
136
139
140 [ super drawInCGLContext:ctx pixelFormat:pf forLayerTime:t displayTime:ts ];
141}
142@end
143
144@interface OTTD_CGLLayerView : NSView
145- (instancetype)initWithFrame:(NSRect)frameRect context:(CGLContextObj)context;
146@end
147
148@implementation OTTD_CGLLayerView
149
150- (instancetype)initWithFrame:(NSRect)frameRect context:(CGLContextObj)context
151{
152 if (self = [ super initWithFrame:frameRect ]) {
153 /* We manage our content updates ourselves. */
154 self.layerContentsRedrawPolicy = NSViewLayerContentsRedrawOnSetNeedsDisplay;
155
156 /* Create backing layer. */
157 CALayer *l = [ [ OTTD_CGLLayer alloc ] initWithContext:context ];
158 self.layer = l;
159 self.wantsLayer = YES;
160 [ l release ];
161 }
162 return self;
163}
164
165- (BOOL)acceptsFirstResponder
166{
167 return NO;
168}
169
170- (BOOL)isOpaque
171{
172 return YES;
173}
174
175- (void)viewDidChangeBackingProperties
176{
177 self.layer.contentsScale = _allow_hidpi_window && [ self.window respondsToSelector:@selector(backingScaleFactor) ] ? [ self.window backingScaleFactor ] : 1.0f;
178}
179@end
180
181
184
185
186std::optional<std::string_view> VideoDriver_CocoaOpenGL::Start(const StringList &param)
187{
188 auto err = this->Initialize();
189 if (err) return err;
190
192 if (bpp != 8 && bpp != 32) {
193 this->Stop();
194 return "The cocoa OpenGL subdriver only supports 8 and 32 bpp.";
195 }
196
197 /* Try to allocate GL context. */
198 err = this->AllocateContext(GetDriverParamBool(param, "software"));
199 if (err) {
200 this->Stop();
201 return err;
202 }
203
204 this->driver_info = GetName();
205 this->driver_info += " (";
206 this->driver_info += OpenGLBackend::Get()->GetDriverName();
207 this->driver_info += ")";
208
209 bool fullscreen = _fullscreen;
210 if (!this->MakeWindow(_cur_resolution.width, _cur_resolution.height)) {
211 this->Stop();
212 return "Could not create window";
213 }
214
215 this->AllocateBackingStore(true);
216
217 if (fullscreen) this->ToggleFullscreen(fullscreen);
218
219 this->GameSizeChanged();
220 this->UpdateVideoModes();
222
223 this->is_game_threaded = !GetDriverParamBool(param, "no_threads") && !GetDriverParamBool(param, "no_thread");
224
225 return std::nullopt;
226
227}
228
230{
232
233 CGLSetCurrentContext(this->gl_context);
235 CGLReleaseContext(this->gl_context);
236}
237
244
246{
248
249 CGLSetCurrentContext(this->gl_context);
251}
252
253std::optional<std::string_view> VideoDriver_CocoaOpenGL::AllocateContext(bool allow_software)
254{
255 [ OTTD_CGLLayer setAllowSoftware:allow_software ];
256
257 CGLPixelFormatObj pxfmt = [ OTTD_CGLLayer defaultPixelFormat ];
258 if (pxfmt == nullptr) return "No suitable pixel format found";
259
260 CGLCreateContext(pxfmt, nullptr, &this->gl_context);
261 CGLDestroyPixelFormat(pxfmt);
262
263 if (this->gl_context == nullptr) return "Can't create a rendering context";
264
265 CGLSetCurrentContext(this->gl_context);
266
267 return OpenGLBackend::Create(&GetOGLProcAddressCallback, this->GetScreenSize());
268}
269
271{
272 return [ [ OTTD_CGLLayerView alloc ] initWithFrame:this->cocoaview.bounds context:this->gl_context ];
273}
274
276{
277 if (this->window == nil || this->setup) return;
278
279 if (_screen.dst_ptr != nullptr) this->ReleaseVideoPointer();
280
281 CGLSetCurrentContext(this->gl_context);
282 NSRect frame = [ this->cocoaview getRealRect:[ this->cocoaview frame ] ];
283 OpenGLBackend::Get()->Resize(frame.size.width, frame.size.height, force);
284 if (this->buffer_locked) _screen.dst_ptr = this->GetVideoPointer();
285 this->dirty_rect = {};
286
287 /* Redraw screen */
288 this->GameSizeChanged();
289}
290
292{
293 CGLSetCurrentContext(this->gl_context);
294 if (BlitterFactory::GetCurrentBlitter()->NeedsAnimationBuffer()) {
296 }
298}
299
301{
302 CGLSetCurrentContext(this->gl_context);
303
304 if (this->anim_buffer != nullptr) OpenGLBackend::Get()->ReleaseAnimBuffer(this->dirty_rect);
306 this->dirty_rect = {};
307 _screen.dst_ptr = nullptr;
308 this->anim_buffer = nullptr;
309}
310
312{
314
317
318 /* Always push a changed palette to OpenGL. */
319 CGLSetCurrentContext(this->gl_context);
323 }
324 }
325
326 [ CATransaction begin ];
327 [ this->cocoaview.subviews[0].layer setNeedsDisplay ];
328 [ CATransaction commit ];
329}
330
331#endif /* WITH_COCOA or DOXYGEN_API */
static Blitter * GetCurrentBlitter()
Get the current active blitter (always set by calling SelectBlitter).
Definition factory.hpp:139
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.
Definition base.hpp:53
void Paint()
Render video buffer to the screen.
Definition opengl.cpp:1065
uint8_t * GetAnimBuffer()
Get a pointer to the memory for the separate animation buffer.
Definition opengl.cpp:1196
void * GetVideoBuffer()
Get a pointer to the memory for the video driver to draw to.
Definition opengl.cpp:1174
bool Resize(int w, int h, bool force=false)
Change the size of the drawing window and allocate matching resources.
Definition opengl.cpp:939
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:490
void UpdatePalette(const Colour *pal, uint first, uint length)
Update the stored palette.
Definition opengl.cpp:1051
void ReleaseAnimBuffer(const Rect &update_rect)
Update animation buffer texture after the animation buffer was filled.
Definition opengl.cpp:1257
void ClearCursorCache()
Queue a request for cursor cache clear.
Definition opengl.cpp:1161
static OpenGLBackend * Get()
Get singleton instance of this class.
Definition opengl.h:86
void DrawMouseCursor()
Draw mouse cursor on screen.
Definition opengl.cpp:1097
void ReleaseVideoBuffer(const Rect &update_rect)
Update video buffer texture after the video buffer was filled.
Definition opengl.cpp:1219
static void Destroy()
Free resources and destroy singleton back-end class.
Definition opengl.cpp:503
RAII class for measuring simple elements of performance.
uint8_t * anim_buffer
Animation buffer from OpenGL back-end.
Definition cocoa_ogl.h:20
void * GetVideoPointer() override
Get a pointer to the video buffer.
Definition cocoa_ogl.mm:291
std::string driver_info
Information string about selected driver.
Definition cocoa_ogl.h:21
void PopulateSystemSprites() override
Populate all sprites in cache.
Definition cocoa_ogl.mm:238
void ReleaseVideoPointer() override
Hand video buffer back to the drawing backend.
Definition cocoa_ogl.mm:300
std::optional< std::string_view > Start(const StringList &param) override
Start this driver.
Definition cocoa_ogl.mm:186
std::string_view GetName() const override
Get the name of this driver.
Definition cocoa_ogl.h:42
void Paint() override
Paint the window.
Definition cocoa_ogl.mm:311
NSView * AllocateDrawView() override
Allocate the view to show the game on.
Definition cocoa_ogl.mm:270
void ClearSystemSprites() override
Clear all cached sprites.
Definition cocoa_ogl.mm:245
void Stop() override
Stop Cocoa video driver.
Definition cocoa_ogl.mm:229
void AllocateBackingStore(bool force=false) override
Resize the window.
Definition cocoa_ogl.mm:275
bool ToggleFullscreen(bool fullscreen) override
Toggle between windowed and full screen mode for cocoa display driver.
Definition cocoa_v.mm:179
void UpdateVideoModes()
Update the video mode.
Definition cocoa_v.mm:322
std::optional< std::string_view > Initialize()
Common driver initialization.
Definition cocoa_v.mm:104
OTTD_CocoaWindow * window
Pointer to window object.
Definition cocoa_v.h:31
bool MakeWindow(int width, int height)
Build window and view with a given size.
Definition cocoa_v.mm:347
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
Rect dirty_rect
Region of the screen that needs redrawing.
Definition cocoa_v.h:67
void Stop() override
Stop Cocoa video driver.
Definition cocoa_v.mm:84
bool buffer_locked
Video buffer was locked by the main thread.
Definition cocoa_v.h:68
bool setup
Window is currently being created.
Definition cocoa_v.h:29
The Cocoa OpenGL video driver.
static FVideoDriver_CocoaOpenGL iFVideoDriver_CocoaOpenGL
Storage for instance of the FVideoDriver_CocoaOpenGL class.
Definition cocoa_ogl.mm:183
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:49
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
Functions related to debugging.
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
Factory to 'query' all available blitters.
Types for recording game performance data.
@ PFE_VIDEO
Speed of painting drawn video buffer.
Geometry functions.
Functions related to the gfx engine.
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:1554
Functions related to MacOS support.
Includes of mac os specific headers wich contain objective c.
Integer math functions.
OpenGL video driver support.
Some generic types.
@ Stop
Go to the depot and stop there.
Definition order_type.h:178
bool CopyPalette(Palette &local_palette, bool force_copy)
Copy the current palette if the palette was updated.
Definition palette.cpp:230
Definition of base types and functions in a cross-platform compatible way.
std::vector< std::string > StringList
Type for a list of strings.
Definition string_type.h:60