Skip to content

Commit 21f7309

Browse files
jcm93jcm
and
jcm
authored
ruby: Use cleaner OpenGL render pattern, misc. CGL fixes (#1543)
### OpenGL rendering (all platforms) - librashader specifies that the output viewport should be the same size as the output framebuffer texture. This was not the case for the OpenGL render code. * Previously, librashader under OpenGL would render onto an intermediate framebuffer sized to the "output" size (the entire window view size), rather than the "target" size (the final composited size of the game area within the output area). The `libra_viewport_t` would be sized to the target size, but the underlying buffer would be larger. * Now, we size the intermediate framebuffer to the "target" size, let librashader render onto it with a `libra_viewport_t` that matches that size. In the final pass we sample this buffer within an area of the "output"-sized buffer as appropriate. This prior behavior would lead to scaling issues with shaders in the Metal backend. The same issues did not seem to be obviously present in OpenGL in my testing, but we should nevertheless probably fix this in case it is causing any of the subtle issues with shaders that have been reported, and also in case something breaks in the future as a result of not following this recommendation. (The above is also unrelated to the scaling issues addressed by #1508) ### CGL fix-ups (macOS) - Backports the native fullscreen and monitor selection options to OpenGL, and removes unnecessary custom window code from the OpenGL driver. - Removes a seemingly unnecessary output call from `reshape` that would cause flickering during resizes. This has been tested on macOS but should probably be tested on other platforms as well to make sure nothing breaks. Co-authored-by: jcm <[email protected]>
1 parent 6cd4470 commit 21f7309

File tree

4 files changed

+49
-58
lines changed

4 files changed

+49
-58
lines changed

Diff for: ruby/video/cgl.cpp

+43-53
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,6 @@ struct VideoCGL;
1212
-(BOOL) acceptsFirstResponder;
1313
@end
1414

15-
@interface RubyWindowCGL : NSWindow <NSWindowDelegate> {
16-
@public
17-
VideoCGL* video;
18-
}
19-
-(id) initWith:(VideoCGL*)video;
20-
-(BOOL) canBecomeKeyWindow;
21-
-(BOOL) canBecomeMainWindow;
22-
@end
23-
2415
struct VideoCGL : VideoDriver, OpenGL {
2516
VideoCGL& self = *this;
2617
VideoCGL(Video& super) : VideoDriver(super) {}
@@ -34,14 +25,52 @@ struct VideoCGL : VideoDriver, OpenGL {
3425
auto ready() -> bool override { return _ready; }
3526

3627
auto hasFullScreen() -> bool override { return true; }
28+
auto hasNativeFullScreen() -> bool override { return true; }
29+
auto hasMonitor() -> bool override { return !_nativeFullScreen; }
3730
auto hasContext() -> bool override { return true; }
3831
auto hasBlocking() -> bool override { return true; }
3932
auto hasForceSRGB() -> bool override { return false; }
4033
auto hasFlush() -> bool override { return true; }
4134
auto hasShader() -> bool override { return true; }
4235

4336
auto setFullScreen(bool fullScreen) -> bool override {
44-
return initialize();
37+
// todo: fix/make consistent mouse cursor hide behavior
38+
39+
if (_nativeFullScreen) {
40+
[view.window toggleFullScreen:nil];
41+
} else {
42+
/// This option implements non-idiomatic macOS fullscreen behavior that sets the window frame equal to the selected display's
43+
/// frame size and hides the cursor. This version of fullscreen is desirable because it allows us to render around the camera
44+
/// housing on newer Macs (important for bezel-style shaders), has snappier entrance/exit and tabbing behavior, and functions
45+
/// better with recording and capture software such as OBS.
46+
if (fullScreen) {
47+
auto monitor = Video::monitor(self.monitor);
48+
NSScreen *handle = (__bridge NSScreen *)(void *)monitor.nativeHandle; //eew
49+
frameBeforeFullScreen = view.window.frame;
50+
[NSApp setPresentationOptions:(NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar)];
51+
[view.window setStyleMask:NSWindowStyleMaskBorderless];
52+
[view.window setFrame:handle.frame display:YES];
53+
[NSCursor setHiddenUntilMouseMoves:YES];
54+
} else {
55+
[NSApp setPresentationOptions:NSApplicationPresentationDefault];
56+
[view.window setStyleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable | NSWindowStyleMaskClosable)];
57+
[view.window setFrame:frameBeforeFullScreen display:YES];
58+
}
59+
[view.window makeFirstResponder:view];
60+
}
61+
return true;
62+
}
63+
64+
auto setNativeFullScreen(bool nativeFullScreen) -> bool override {
65+
_nativeFullScreen = nativeFullScreen;
66+
if (nativeFullScreen) {
67+
//maximize goes fullscreen
68+
[view.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenPrimary];
69+
} else {
70+
//maximize does not go fullscreen
71+
[view.window setCollectionBehavior: NSWindowCollectionBehaviorFullScreenAuxiliary];
72+
}
73+
return true;
4574
}
4675

4776
auto setContext(uintptr context) -> bool override {
@@ -135,13 +164,6 @@ struct VideoCGL : VideoDriver, OpenGL {
135164
terminate();
136165
if(!self.fullScreen && !self.context) return false;
137166

138-
if(self.fullScreen) {
139-
window = [[RubyWindowCGL alloc] initWith:this];
140-
[window setCollectionBehavior:NSWindowCollectionBehaviorFullScreenPrimary];
141-
[window toggleFullScreen:nil];
142-
//[NSApp setPresentationOptions:NSApplicationPresentationFullScreen];
143-
}
144-
145167
NSOpenGLPixelFormatAttribute attributeList[] = {
146168
NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
147169
NSOpenGLPFAColorSize, 24,
@@ -150,7 +172,7 @@ struct VideoCGL : VideoDriver, OpenGL {
150172
0
151173
};
152174

153-
auto context = self.fullScreen ? [window contentView] : (__bridge NSView*)(void *)self.context;
175+
auto context = (__bridge NSView*)(void *)self.context;
154176
auto size = [context frame].size;
155177
auto format = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributeList];
156178
auto openGLContext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:nil];
@@ -176,6 +198,7 @@ struct VideoCGL : VideoDriver, OpenGL {
176198

177199
releaseContext();
178200
clear();
201+
setNativeFullScreen(_nativeFullScreen);
179202
return _ready = true;
180203
}
181204

@@ -188,19 +211,12 @@ struct VideoCGL : VideoDriver, OpenGL {
188211
[view removeFromSuperview];
189212
view = nil;
190213
}
191-
192-
if(window) {
193-
//[NSApp setPresentationOptions:NSApplicationPresentationDefault];
194-
[window toggleFullScreen:nil];
195-
[window setCollectionBehavior:NSWindowCollectionBehaviorDefault];
196-
[window close];
197-
window = nil;
198-
}
199214
}
200215

201216
RubyVideoCGL* view = nullptr;
202-
RubyWindowCGL* window = nullptr;
203217

218+
bool _nativeFullScreen = false;
219+
NSRect frameBeforeFullScreen = NSMakeRect(0,0,0,0);
204220
bool _ready = false;
205221
std::recursive_mutex mutex;
206222
};
@@ -216,7 +232,6 @@ struct VideoCGL : VideoDriver, OpenGL {
216232

217233
-(void) reshape {
218234
[super reshape];
219-
video->output(0, 0);
220235
}
221236

222237
-(BOOL) acceptsFirstResponder {
@@ -230,28 +245,3 @@ struct VideoCGL : VideoDriver, OpenGL {
230245
}
231246

232247
@end
233-
234-
@implementation RubyWindowCGL : NSWindow
235-
236-
-(id) initWith:(VideoCGL*)videoPointer {
237-
auto primaryRect = [[[NSScreen screens] objectAtIndex:0] frame];
238-
if(self = [super initWithContentRect:primaryRect styleMask:0 backing:NSBackingStoreBuffered defer:YES]) {
239-
video = videoPointer;
240-
[self setDelegate:self];
241-
[self setReleasedWhenClosed:NO];
242-
[self setAcceptsMouseMovedEvents:YES];
243-
[self setTitle:@""];
244-
[self makeKeyAndOrderFront:nil];
245-
}
246-
return self;
247-
}
248-
249-
-(BOOL) canBecomeKeyWindow {
250-
return YES;
251-
}
252-
253-
-(BOOL) canBecomeMainWindow {
254-
return YES;
255-
}
256-
257-
@end

Diff for: ruby/video/metal/metal.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,7 @@ struct VideoMetal : VideoDriver, Metal {
586586
}
587587

588588
initialized = true;
589+
setNativeFullScreen(self.nativeFullScreen);
589590
return _ready = true;
590591
}
591592

Diff for: ruby/video/opengl/main.hpp

+3-3
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,8 @@ auto OpenGL::output() -> void {
6767
u32 y = (outputHeight - targetHeight) / 2;
6868

6969
if(_chain != NULL) {
70-
// Shader path: our intermediate framebuffer matches the output size
71-
if(!framebuffer || framebufferWidth != outputWidth || framebufferHeight != outputHeight) {
70+
// Shader path: our intermediate framebuffer matches the target size (final composited game area size)
71+
if(!framebuffer || framebufferWidth != targetWidth || framebufferHeight != targetHeight) {
7272
if(framebuffer) {
7373
glDeleteFramebuffers(1, &framebuffer);
7474
framebuffer = 0;
@@ -78,7 +78,7 @@ auto OpenGL::output() -> void {
7878
framebufferTexture = 0;
7979
}
8080

81-
framebufferWidth = outputWidth, framebufferHeight = outputHeight;
81+
framebufferWidth = targetWidth, framebufferHeight = targetHeight;
8282
glGenFramebuffers(1, &framebuffer);
8383
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
8484
glGenTextures(1, &framebufferTexture);

Diff for: ruby/video/opengl/surface.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ auto OpenGLSurface::render(u32 sourceWidth, u32 sourceHeight, u32 targetX, u32 t
2424

2525
if(_chain != NULL) {
2626
libra_source_image_gl_t input = {texture, format, sourceWidth, sourceHeight};
27-
libra_viewport_t viewport{(float)targetX, (float)targetY, targetWidth, targetHeight};
27+
libra_viewport_t viewport{0, 0, targetWidth, targetHeight};
2828
libra_output_framebuffer_gl_t output = {framebuffer, framebufferTexture, framebufferFormat};
2929

3030
if (auto error = _libra.gl_filter_chain_frame(&_chain, frameCount++, input, viewport, output, NULL, NULL)) {
@@ -33,7 +33,7 @@ auto OpenGLSurface::render(u32 sourceWidth, u32 sourceHeight, u32 targetX, u32 t
3333

3434
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
3535
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
36-
glBlitFramebuffer(0, framebufferHeight, framebufferWidth, 0, 0, 0, framebufferWidth, framebufferHeight, GL_COLOR_BUFFER_BIT, filter);
36+
glBlitFramebuffer(0, framebufferHeight, framebufferWidth, 0, targetX, targetY, framebufferWidth + targetX, framebufferHeight + targetY, GL_COLOR_BUFFER_BIT, filter);
3737
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
3838
} else {
3939
glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);

0 commit comments

Comments
 (0)