Is SDL2 with METAL on macOS/iOS/tvOS getting much testing?


#1

I found that on macOS that after creating a window, and then creating a metal renderer, that GetRenderOutputSize returns zero for w and h, unless a call is made to SDL_SetWindowSize with the same window size as created.

Doesn’t work:

  1. create window
  2. create renderer
  3. get renderer output size

Does work:

  1. create window
  2. create renderer
  3. set renderer target to null
  4. set renderer draw colour to black
  5. render clear
  6. render present
  7. set window size to same as created
  8. get renderer output size

I’ve not tested to see which of steps 3-6 are necessary, but it’s not enough to just call set window size before steps 3-6.

Also, the renderer device doesn’t appear to get resized when you drag the macOS window to resize it, instead I have to destroy and create the renderer to make it the new size.

Finally, on iOS, the same workaround is necessary as above, but the issue doesn’t show in the same way, instead it appears that renderer output size returns sane values, but it crashes down inside the metal code somewhere to do with vertexes. The workaround fixes the issue though.

Finally finally, I’m using a slightly modified version of SDL2.0.8, so I wanted to check to see if anyone has encountered similar before putting together a sample project. I don’t think my changes are responsible for the above though, it’s just a few functions to create textures out of existing METAL textures returned from the VLC video player library so I can hardware accelerate VLC directly onto SDL textures.

The above issues occur before I get that far into my app.


#2

I think this was fixed a few weeks ago by this commit:

Let me know if it doesn’t fix your issue!

–ryan.


#3

Hi Ryan

Thanks for that - it half-fixes it. The problem is that in retina mode it is creating a metal layer that is not the correct high resolution one.

With my workaround, it was creating a metal layer double the size, as required in retina mode.

Also, it doesn’t address the fact that resizing a window doesn’t resize the metal layer - so you have to keep deleting and re-creating the renderer.

I did apply that fix in isolation however, I’ve not tried whatever else has been changed since 2.0.8. This is because as mentioned I have a branch with various other changes too so it’s not a 5 minute job to merge latest changes into my branch, so I tend to wait for the next stable release, but if you think there are other fixes that might solve the above issues then maybe I would.

Regards

Oliver


#4

So it looks like the fix needs to be more like this:

    /* Set the desired scale. */
    CGSize size = self.bounds.size;
	size.width *= scale;
	size.height *= scale;
    ((CAMetalLayer *) self.layer).drawableSize = size;
    self.layer.contentsScale = scale;

#5

(post withdrawn by author, will be automatically deleted in 24 hours unless flagged)


#6

Ok so on further investigation I reckon it’s this change that has broken things:

This does two things:

  1. prevents the initial window size from being correct
  2. prevents it being updated when the window size changes

So I think the code needs to look like this:

- (instancetype)initWithFrame:(NSRect)frame
                        scale:(CGFloat)scale
{
	if ((self = [super initWithFrame:frame])) {
        _tag = METALVIEW_TAG;
        self.wantsLayer = YES;

        /* Allow resize. */
        self.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;

        /* Set the desired scale. */
        self.layer.contentsScale = scale;
        
        /* Update drawable size. */
        [self updateDrawableSize];
	}
  
	return self;
}

/* Set the size of the metal drawables when the view is resized. */
- (void)resizeWithOldSuperviewSize:(NSSize)oldSize
{
    [super resizeWithOldSuperviewSize:oldSize];
    [self updateDrawableSize];
}

- (void)updateDrawableSize
{
    CGSize size = self.bounds.size;
    size.width *= self.layer.contentsScale;
    size.height *= self.layer.contentsScale;
    ((CAMetalLayer *) self.layer).drawableSize = size;
}