metal: hook up the backbuffer

This commit is contained in:
Alex Szpakowski
2020-04-23 18:38:29 -03:00
parent acc4064a6c
commit 99b39065b6
7 changed files with 89 additions and 23 deletions
+4
View File
@@ -124,6 +124,10 @@
# define LOVE_LEGENDARY_ACCELEROMETER_AS_JOYSTICK_HACK # define LOVE_LEGENDARY_ACCELEROMETER_AS_JOYSTICK_HACK
#endif #endif
#if defined(LOVE_MACOS) || defined(LOVE_IOS)
# define LOVE_GRAPHICS_METAL
#endif
// Autotools config.h // Autotools config.h
#ifdef HAVE_CONFIG_H #ifdef HAVE_CONFIG_H
# include <../config.h> # include <../config.h>
+5
View File
@@ -23,6 +23,9 @@
#include "graphics/Graphics.h" #include "graphics/Graphics.h"
#include "Metal.h" #include "Metal.h"
@class CAMetalLayer;
@protocol CAMetalDrawable;
namespace love namespace love
{ {
namespace graphics namespace graphics
@@ -177,6 +180,8 @@ private:
id<MTLRenderCommandEncoder> renderEncoder; id<MTLRenderCommandEncoder> renderEncoder;
id<MTLBlitCommandEncoder> blitEncoder; id<MTLBlitCommandEncoder> blitEncoder;
CAMetalLayer *metalLayer;
id<CAMetalDrawable> activeDrawable;
MTLRenderPassDescriptor *passDesc; MTLRenderPassDescriptor *passDesc;
uint32 dirtyRenderState; uint32 dirtyRenderState;
+33 -4
View File
@@ -155,6 +155,8 @@ Graphics::Graphics()
, commandBuffer(nil) , commandBuffer(nil)
, renderEncoder(nil) , renderEncoder(nil)
, blitEncoder(nil) , blitEncoder(nil)
, metalLayer(nil)
, activeDrawable(nil)
, passDesc(nil) , passDesc(nil)
, dirtyRenderState(STATEBIT_ALL) , dirtyRenderState(STATEBIT_ALL)
, windowHasStencil(false) , windowHasStencil(false)
@@ -243,9 +245,12 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
{ @autoreleasepool { { @autoreleasepool {
this->width = width; this->width = width;
this->height = height; this->height = height;
this->metalLayer = (__bridge CAMetalLayer *) context;
this->windowHasStencil = windowhasstencil; this->windowHasStencil = windowhasstencil;
metalLayer.device = device;
setViewportSize(width, height, pixelwidth, pixelheight); setViewportSize(width, height, pixelwidth, pixelheight);
created = true; created = true;
@@ -286,7 +291,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
}} }}
void Graphics::unSetMode() void Graphics::unSetMode()
{ { @autoreleasepool {
if (!isCreated()) if (!isCreated())
return; return;
@@ -300,7 +305,9 @@ void Graphics::unSetMode()
temporaryTextures.clear(); temporaryTextures.clear();
created = false; created = false;
} metalLayer = nil;
activeDrawable = nil;
}}
void Graphics::setActive(bool enable) void Graphics::setActive(bool enable)
{ {
@@ -333,6 +340,19 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
if (renderEncoder == nil) if (renderEncoder == nil)
{ {
submitBlitEncoder(); submitBlitEncoder();
const auto &rts = states.back().renderTargets;
if (rts.getFirstTarget().texture.get() != nullptr)
{
}
else
{
if (activeDrawable == nil)
activeDrawable = [metalLayer nextDrawable];
passDesc.colorAttachments[0].texture = activeDrawable.texture;
}
renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc]; renderEncoder = [useCommandBuffer() renderCommandEncoderWithDescriptor:passDesc];
dirtyRenderState = STATEBIT_ALL; dirtyRenderState = STATEBIT_ALL;
} }
@@ -346,6 +366,8 @@ void Graphics::submitRenderEncoder()
{ {
[renderEncoder endEncoding]; [renderEncoder endEncoding];
renderEncoder = nil; renderEncoder = nil;
passDesc.colorAttachments[0].texture = nil;
} }
} }
@@ -778,7 +800,7 @@ void Graphics::discard(const std::vector<bool> &colorbuffers, bool depthstencil)
} }
void Graphics::present(void *screenshotCallbackData) void Graphics::present(void *screenshotCallbackData)
{ { @autoreleasepool {
if (!isActive()) if (!isActive())
return; return;
@@ -851,12 +873,19 @@ void Graphics::present(void *screenshotCallbackData)
buffer->nextFrame(); buffer->nextFrame();
batchedDrawState.indexBuffer->nextFrame(); batchedDrawState.indexBuffer->nextFrame();
id<MTLCommandBuffer> cmd = getCommandBuffer();
if (cmd != nil && activeDrawable != nil)
[cmd presentDrawable:activeDrawable];
submitCommandBuffer(); submitCommandBuffer();
auto window = Module::getInstance<love::window::Window>(M_WINDOW); auto window = Module::getInstance<love::window::Window>(M_WINDOW);
if (window != nullptr) if (window != nullptr)
window->swapBuffers(); window->swapBuffers();
activeDrawable = nil;
// Reset the per-frame stat counts. // Reset the per-frame stat counts.
drawCalls = 0; drawCalls = 0;
//gl.stats.shaderSwitches = 0; //gl.stats.shaderSwitches = 0;
@@ -875,7 +904,7 @@ void Graphics::present(void *screenshotCallbackData)
else else
temporaryTextures[i].framesSinceUse++; temporaryTextures[i].framesSinceUse++;
} }
} }}
void Graphics::setColor(Colorf c) void Graphics::setColor(Colorf c)
{ {
+4 -1
View File
@@ -81,7 +81,10 @@ MTLPixelFormat Metal::convertPixelFormat(PixelFormat format, bool &isSRGB)
break; break;
case PIXELFORMAT_LA8_UNORM: case PIXELFORMAT_LA8_UNORM:
mtlformat = MTLPixelFormatRGBA8Unorm; // TODO: Swizzle
// TODO: fall back to RGBA8 when swizzle isn't available. Pixel format
// size calculation will need to be adjusted as well
mtlformat = MTLPixelFormatRG8Unorm;
break; break;
case PIXELFORMAT_RGBA4_UNORM: case PIXELFORMAT_RGBA4_UNORM:
+1 -1
View File
@@ -51,7 +51,7 @@ public:
data = (uint8 *) buffer.contents; data = (uint8 *) buffer.contents;
for (int i = 0; i < BUFFER_FRAMES; i++) for (int i = 0; i < BUFFER_FRAMES; i++)
frameSemaphores[i] = dispatch_semaphore_create(0); frameSemaphores[i] = dispatch_semaphore_create(1);
}} }}
virtual ~StreamBuffer() virtual ~StreamBuffer()
+36 -11
View File
@@ -64,7 +64,7 @@ Window::Window()
, mouseGrabbed(false) , mouseGrabbed(false)
, window(nullptr) , window(nullptr)
, glcontext(nullptr) , glcontext(nullptr)
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
, metalView(nullptr) , metalView(nullptr)
#endif #endif
, displayedWindowError(false) , displayedWindowError(false)
@@ -292,7 +292,7 @@ std::vector<Window::ContextAttribs> Window::getContextAttribsList() const
bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, graphics::Graphics::Renderer renderer, int msaa, bool stencil, int depth) bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, graphics::Graphics::Renderer renderer, int msaa, bool stencil, int depth)
{ {
bool needsglcontext = (windowflags & SDL_WINDOW_OPENGL) != 0; bool needsglcontext = (windowflags & SDL_WINDOW_OPENGL) != 0;
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
bool needsmetalview = (windowflags & SDL_WINDOW_METAL) != 0; bool needsmetalview = (windowflags & SDL_WINDOW_METAL) != 0;
#endif #endif
@@ -314,6 +314,14 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
glcontext = nullptr; glcontext = nullptr;
} }
#ifdef LOVE_GRAPHICS_METAL
if (metalView)
{
SDL_Metal_DestroyView(metalView);
metalView = nullptr;
}
#endif
if (window) if (window)
{ {
SDL_DestroyWindow(window); SDL_DestroyWindow(window);
@@ -409,7 +417,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
} }
} }
} }
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
else if (renderer == graphics::Graphics::RENDERER_METAL) else if (renderer == graphics::Graphics::RENDERER_METAL)
{ {
if (create(nullptr) && window != nullptr) if (create(nullptr) && window != nullptr)
@@ -430,7 +438,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
bool failed = window == nullptr; bool failed = window == nullptr;
failed |= (needsglcontext && !glcontext); failed |= (needsglcontext && !glcontext);
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
failed |= (needsmetalview && !metalView); failed |= (needsmetalview && !metalView);
#endif #endif
@@ -497,7 +505,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
if (renderer == graphics::Graphics::RENDERER_OPENGL) if (renderer == graphics::Graphics::RENDERER_OPENGL)
sdlflags |= SDL_WINDOW_OPENGL; sdlflags |= SDL_WINDOW_OPENGL;
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
if (renderer == graphics::Graphics::RENDERER_METAL) if (renderer == graphics::Graphics::RENDERER_METAL)
sdlflags |= SDL_WINDOW_METAL; sdlflags |= SDL_WINDOW_METAL;
#endif #endif
@@ -587,10 +595,12 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
double scaledw, scaledh; double scaledw, scaledh;
fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh); fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh);
void *context = (void *) glcontext; void *context = nullptr;
#if defined(LOVE_MACOS) || defined(LOVE_IOS) if (renderer == graphics::Graphics::RENDERER_OPENGL)
if (renderer == graphics::Graphics::RENDERER_METAL) context = (void *) glcontext;
context = (void *) metalView; #ifdef LOVE_GRAPHICS_METAL
if (renderer == graphics::Graphics::RENDERER_METAL && metalView)
context = (void *) SDL_Metal_GetLayer(metalView);
#endif #endif
graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil); graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil);
@@ -629,7 +639,16 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi
// Set the new display mode as the current display mode. // Set the new display mode as the current display mode.
SDL_GetWindowSize(window, &windowWidth, &windowHeight); SDL_GetWindowSize(window, &windowWidth, &windowHeight);
pixelWidth = windowWidth;
pixelHeight = windowHeight;
if ((wflags & SDL_WINDOW_OPENGL) != 0)
SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight);
#ifdef LOVE_GRAPHICS_METAL
else if ((wflags & SDL_WINDOW_METAL) != 0)
SDL_Metal_GetDrawableSize(window, &pixelWidth, &pixelHeight);
#endif
if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP) if ((wflags & SDL_WINDOW_FULLSCREEN_DESKTOP) == SDL_WINDOW_FULLSCREEN_DESKTOP)
{ {
@@ -673,8 +692,12 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi
// Verify MSAA setting. // Verify MSAA setting.
int buffers = 0; int buffers = 0;
int samples = 0; int samples = 0;
if ((wflags & SDL_WINDOW_OPENGL) != 0)
{
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers);
SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples); SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples);
}
settings.msaa = (buffers > 0 ? samples : 0); settings.msaa = (buffers > 0 ? samples : 0);
settings.vsync = getVSync(); settings.vsync = getVSync();
@@ -729,7 +752,7 @@ void Window::close(bool allowExceptions)
glcontext = nullptr; glcontext = nullptr;
} }
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
if (metalView) if (metalView)
{ {
SDL_Metal_DestroyView(metalView); SDL_Metal_DestroyView(metalView);
@@ -787,10 +810,11 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype)
if (SDL_SetWindowFullscreen(window, sdlflags) == 0) if (SDL_SetWindowFullscreen(window, sdlflags) == 0)
{ {
if (glcontext)
SDL_GL_MakeCurrent(window, glcontext); SDL_GL_MakeCurrent(window, glcontext);
updateSettings(newsettings, true); updateSettings(newsettings, true);
// Apparently this gets un-set when we exit fullscreen (at least in OS X). // Apparently this gets un-set when we exit fullscreen (at least in macOS).
if (!fullscreen) if (!fullscreen)
SDL_SetWindowMinimumSize(window, settings.minwidth, settings.minheight); SDL_SetWindowMinimumSize(window, settings.minwidth, settings.minheight);
@@ -1086,6 +1110,7 @@ bool Window::isMinimized() const
void Window::swapBuffers() void Window::swapBuffers()
{ {
if (glcontext)
SDL_GL_SwapWindow(window); SDL_GL_SwapWindow(window);
} }
+1 -1
View File
@@ -168,7 +168,7 @@ private:
SDL_Window *window; SDL_Window *window;
SDL_GLContext glcontext; SDL_GLContext glcontext;
#if defined(LOVE_MACOS) || defined(LOVE_IOS) #ifdef LOVE_GRAPHICS_METAL
SDL_MetalView metalView; SDL_MetalView metalView;
#endif #endif