mirror of
https://github.com/love2d/love.git
synced 2026-08-21 13:09:56 +02:00
metal: hook up the backbuffer
This commit is contained in:
@@ -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>
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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:
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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);
|
||||||
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)
|
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;
|
||||||
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.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)
|
||||||
{
|
{
|
||||||
SDL_GL_MakeCurrent(window, glcontext);
|
if (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,7 +1110,8 @@ bool Window::isMinimized() const
|
|||||||
|
|
||||||
void Window::swapBuffers()
|
void Window::swapBuffers()
|
||||||
{
|
{
|
||||||
SDL_GL_SwapWindow(window);
|
if (glcontext)
|
||||||
|
SDL_GL_SwapWindow(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Window::hasFocus() const
|
bool Window::hasFocus() const
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user