From 99b39065b639151fbac63622ae12b3704756d113 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Thu, 23 Apr 2020 18:38:29 -0300 Subject: [PATCH] metal: hook up the backbuffer --- src/common/config.h | 4 ++ src/modules/graphics/metal/Graphics.h | 5 ++ src/modules/graphics/metal/Graphics.mm | 37 ++++++++++++-- src/modules/graphics/metal/Metal.mm | 5 +- src/modules/graphics/metal/StreamBuffer.mm | 2 +- src/modules/window/sdl/Window.cpp | 57 ++++++++++++++++------ src/modules/window/sdl/Window.h | 2 +- 7 files changed, 89 insertions(+), 23 deletions(-) diff --git a/src/common/config.h b/src/common/config.h index 69be99fbd..05741f59b 100644 --- a/src/common/config.h +++ b/src/common/config.h @@ -124,6 +124,10 @@ # define LOVE_LEGENDARY_ACCELEROMETER_AS_JOYSTICK_HACK #endif +#if defined(LOVE_MACOS) || defined(LOVE_IOS) +# define LOVE_GRAPHICS_METAL +#endif + // Autotools config.h #ifdef HAVE_CONFIG_H # include <../config.h> diff --git a/src/modules/graphics/metal/Graphics.h b/src/modules/graphics/metal/Graphics.h index 72b20e55c..22a2f589a 100644 --- a/src/modules/graphics/metal/Graphics.h +++ b/src/modules/graphics/metal/Graphics.h @@ -23,6 +23,9 @@ #include "graphics/Graphics.h" #include "Metal.h" +@class CAMetalLayer; +@protocol CAMetalDrawable; + namespace love { namespace graphics @@ -177,6 +180,8 @@ private: id renderEncoder; id blitEncoder; + CAMetalLayer *metalLayer; + id activeDrawable; MTLRenderPassDescriptor *passDesc; uint32 dirtyRenderState; diff --git a/src/modules/graphics/metal/Graphics.mm b/src/modules/graphics/metal/Graphics.mm index 1abb4a6f5..88fd8c72e 100644 --- a/src/modules/graphics/metal/Graphics.mm +++ b/src/modules/graphics/metal/Graphics.mm @@ -155,6 +155,8 @@ Graphics::Graphics() , commandBuffer(nil) , renderEncoder(nil) , blitEncoder(nil) + , metalLayer(nil) + , activeDrawable(nil) , passDesc(nil) , dirtyRenderState(STATEBIT_ALL) , windowHasStencil(false) @@ -243,9 +245,12 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int { @autoreleasepool { this->width = width; this->height = height; + this->metalLayer = (__bridge CAMetalLayer *) context; this->windowHasStencil = windowhasstencil; + metalLayer.device = device; + setViewportSize(width, height, pixelwidth, pixelheight); created = true; @@ -286,7 +291,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int }} void Graphics::unSetMode() -{ +{ @autoreleasepool { if (!isCreated()) return; @@ -300,7 +305,9 @@ void Graphics::unSetMode() temporaryTextures.clear(); created = false; -} + metalLayer = nil; + activeDrawable = nil; +}} void Graphics::setActive(bool enable) { @@ -333,6 +340,19 @@ id Graphics::useRenderEncoder() if (renderEncoder == nil) { 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]; dirtyRenderState = STATEBIT_ALL; } @@ -346,6 +366,8 @@ void Graphics::submitRenderEncoder() { [renderEncoder endEncoding]; renderEncoder = nil; + + passDesc.colorAttachments[0].texture = nil; } } @@ -778,7 +800,7 @@ void Graphics::discard(const std::vector &colorbuffers, bool depthstencil) } void Graphics::present(void *screenshotCallbackData) -{ +{ @autoreleasepool { if (!isActive()) return; @@ -851,12 +873,19 @@ void Graphics::present(void *screenshotCallbackData) buffer->nextFrame(); batchedDrawState.indexBuffer->nextFrame(); + id cmd = getCommandBuffer(); + + if (cmd != nil && activeDrawable != nil) + [cmd presentDrawable:activeDrawable]; + submitCommandBuffer(); auto window = Module::getInstance(M_WINDOW); if (window != nullptr) window->swapBuffers(); + activeDrawable = nil; + // Reset the per-frame stat counts. drawCalls = 0; //gl.stats.shaderSwitches = 0; @@ -875,7 +904,7 @@ void Graphics::present(void *screenshotCallbackData) else temporaryTextures[i].framesSinceUse++; } -} +}} void Graphics::setColor(Colorf c) { diff --git a/src/modules/graphics/metal/Metal.mm b/src/modules/graphics/metal/Metal.mm index 538268a16..0bc8a9ba9 100644 --- a/src/modules/graphics/metal/Metal.mm +++ b/src/modules/graphics/metal/Metal.mm @@ -81,7 +81,10 @@ MTLPixelFormat Metal::convertPixelFormat(PixelFormat format, bool &isSRGB) break; 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; case PIXELFORMAT_RGBA4_UNORM: diff --git a/src/modules/graphics/metal/StreamBuffer.mm b/src/modules/graphics/metal/StreamBuffer.mm index 179b3669a..5d41bddde 100644 --- a/src/modules/graphics/metal/StreamBuffer.mm +++ b/src/modules/graphics/metal/StreamBuffer.mm @@ -51,7 +51,7 @@ public: data = (uint8 *) buffer.contents; for (int i = 0; i < BUFFER_FRAMES; i++) - frameSemaphores[i] = dispatch_semaphore_create(0); + frameSemaphores[i] = dispatch_semaphore_create(1); }} virtual ~StreamBuffer() diff --git a/src/modules/window/sdl/Window.cpp b/src/modules/window/sdl/Window.cpp index a348a6025..e24d8ae12 100644 --- a/src/modules/window/sdl/Window.cpp +++ b/src/modules/window/sdl/Window.cpp @@ -64,7 +64,7 @@ Window::Window() , mouseGrabbed(false) , window(nullptr) , glcontext(nullptr) -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL , metalView(nullptr) #endif , displayedWindowError(false) @@ -292,7 +292,7 @@ std::vector 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 needsglcontext = (windowflags & SDL_WINDOW_OPENGL) != 0; -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL bool needsmetalview = (windowflags & SDL_WINDOW_METAL) != 0; #endif @@ -314,6 +314,14 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla glcontext = nullptr; } +#ifdef LOVE_GRAPHICS_METAL + if (metalView) + { + SDL_Metal_DestroyView(metalView); + metalView = nullptr; + } +#endif + if (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) { 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; failed |= (needsglcontext && !glcontext); -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL failed |= (needsmetalview && !metalView); #endif @@ -497,7 +505,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) if (renderer == graphics::Graphics::RENDERER_OPENGL) sdlflags |= SDL_WINDOW_OPENGL; -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL if (renderer == graphics::Graphics::RENDERER_METAL) sdlflags |= SDL_WINDOW_METAL; #endif @@ -587,10 +595,12 @@ bool Window::setWindow(int width, int height, WindowSettings *settings) double scaledw, scaledh; fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh); - void *context = (void *) glcontext; -#if defined(LOVE_MACOS) || defined(LOVE_IOS) - if (renderer == graphics::Graphics::RENDERER_METAL) - context = (void *) metalView; + void *context = nullptr; + if (renderer == graphics::Graphics::RENDERER_OPENGL) + context = (void *) glcontext; +#ifdef LOVE_GRAPHICS_METAL + if (renderer == graphics::Graphics::RENDERER_METAL && metalView) + context = (void *) SDL_Metal_GetLayer(metalView); #endif 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. SDL_GetWindowSize(window, &windowWidth, &windowHeight); - SDL_GL_GetDrawableSize(window, &pixelWidth, &pixelHeight); + + pixelWidth = windowWidth; + pixelHeight = windowHeight; + + if ((wflags & SDL_WINDOW_OPENGL) != 0) + 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) { @@ -673,8 +692,12 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi // Verify MSAA setting. int buffers = 0; int samples = 0; - SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers); - SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples); + + if ((wflags & SDL_WINDOW_OPENGL) != 0) + { + SDL_GL_GetAttribute(SDL_GL_MULTISAMPLEBUFFERS, &buffers); + SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &samples); + } settings.msaa = (buffers > 0 ? samples : 0); settings.vsync = getVSync(); @@ -729,7 +752,7 @@ void Window::close(bool allowExceptions) glcontext = nullptr; } -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL if (metalView) { SDL_Metal_DestroyView(metalView); @@ -787,10 +810,11 @@ bool Window::setFullscreen(bool fullscreen, Window::FullscreenType fstype) if (SDL_SetWindowFullscreen(window, sdlflags) == 0) { - SDL_GL_MakeCurrent(window, glcontext); + if (glcontext) + SDL_GL_MakeCurrent(window, glcontext); 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) SDL_SetWindowMinimumSize(window, settings.minwidth, settings.minheight); @@ -1086,7 +1110,8 @@ bool Window::isMinimized() const void Window::swapBuffers() { - SDL_GL_SwapWindow(window); + if (glcontext) + SDL_GL_SwapWindow(window); } bool Window::hasFocus() const diff --git a/src/modules/window/sdl/Window.h b/src/modules/window/sdl/Window.h index 4928c406c..b177b231e 100644 --- a/src/modules/window/sdl/Window.h +++ b/src/modules/window/sdl/Window.h @@ -168,7 +168,7 @@ private: SDL_Window *window; SDL_GLContext glcontext; -#if defined(LOVE_MACOS) || defined(LOVE_IOS) +#ifdef LOVE_GRAPHICS_METAL SDL_MetalView metalView; #endif