mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
Merge branch '12.0-development' into metal
This commit is contained in:
@@ -107,11 +107,24 @@ love::graphics::Graphics *createInstance()
|
||||
Graphics::Graphics()
|
||||
: windowHasStencil(false)
|
||||
, mainVAO(0)
|
||||
, internalBackbufferFBO(0)
|
||||
, requestedBackbufferMSAA(0)
|
||||
, bufferMapMemory(nullptr)
|
||||
, bufferMapMemorySize(2 * 1024 * 1024)
|
||||
, defaultBuffers()
|
||||
, supportedFormats()
|
||||
{
|
||||
gl = OpenGL();
|
||||
|
||||
try
|
||||
{
|
||||
bufferMapMemory = new char[bufferMapMemorySize];
|
||||
}
|
||||
catch (std::exception &)
|
||||
{
|
||||
// Handled in getBufferMapMemory.
|
||||
}
|
||||
|
||||
auto window = getInstance<love::window::Window>(M_WINDOW);
|
||||
|
||||
if (window != nullptr)
|
||||
@@ -121,21 +134,22 @@ Graphics::Graphics()
|
||||
if (window->isOpen())
|
||||
{
|
||||
int w, h;
|
||||
love::window::WindowSettings settings;
|
||||
window->getWindow(w, h, settings);
|
||||
love::window::WindowSettings s;
|
||||
window->getWindow(w, h, s);
|
||||
|
||||
double dpiW = w;
|
||||
double dpiH = h;
|
||||
window->windowToDPICoords(&dpiW, &dpiH);
|
||||
|
||||
void *context = nullptr; // TODO
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), settings.stencil, settings.depth);
|
||||
setMode(context, (int) dpiW, (int) dpiH, window->getPixelWidth(), window->getPixelHeight(), s.stencil, s.msaa);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Graphics::~Graphics()
|
||||
{
|
||||
delete[] bufferMapMemory;
|
||||
}
|
||||
|
||||
const char *Graphics::getName() const
|
||||
@@ -188,14 +202,94 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
|
||||
// Set up the projection matrix
|
||||
projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
|
||||
}
|
||||
|
||||
updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA);
|
||||
}
|
||||
|
||||
bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, int /*backbufferdepth*/)
|
||||
void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int pixelheight, int msaa)
|
||||
{
|
||||
bool useinternalbackbuffer = false;
|
||||
if (msaa > 1)
|
||||
useinternalbackbuffer = true;
|
||||
|
||||
// Our internal backbuffer code needs glBlitFramebuffer.
|
||||
if (!(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_ES_VERSION_3_0
|
||||
|| GLAD_EXT_framebuffer_blit || GLAD_ANGLE_framebuffer_blit || GLAD_NV_framebuffer_blit))
|
||||
{
|
||||
if (!(msaa > 1 && GLAD_APPLE_framebuffer_multisample))
|
||||
useinternalbackbuffer = false;
|
||||
}
|
||||
|
||||
GLuint prevFBO = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
|
||||
bool restoreFBO = prevFBO != getInternalBackbufferFBO();
|
||||
|
||||
if (useinternalbackbuffer)
|
||||
{
|
||||
Texture::Settings settings;
|
||||
settings.width = width;
|
||||
settings.height = height;
|
||||
settings.dpiScale = (float)pixelheight / (float)height;
|
||||
settings.msaa = msaa;
|
||||
settings.renderTarget = true;
|
||||
settings.readable.set(false);
|
||||
|
||||
settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_UNORM_sRGB : PIXELFORMAT_RGBA8_UNORM;
|
||||
internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN);
|
||||
|
||||
settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
|
||||
internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
|
||||
|
||||
RenderTargets rts;
|
||||
rts.colors.push_back(internalBackbuffer.get());
|
||||
rts.depthStencil.texture = internalBackbufferDepthStencil;
|
||||
|
||||
internalBackbufferFBO = bindCachedFBO(rts);
|
||||
}
|
||||
else
|
||||
{
|
||||
internalBackbuffer.set(nullptr);
|
||||
internalBackbufferDepthStencil.set(nullptr);
|
||||
internalBackbufferFBO = 0;
|
||||
}
|
||||
|
||||
requestedBackbufferMSAA = msaa;
|
||||
|
||||
if (restoreFBO)
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, prevFBO);
|
||||
}
|
||||
|
||||
GLuint Graphics::getInternalBackbufferFBO() const
|
||||
{
|
||||
if (internalBackbufferFBO != 0)
|
||||
return internalBackbufferFBO;
|
||||
else
|
||||
return getSystemBackbufferFBO();
|
||||
}
|
||||
|
||||
GLuint Graphics::getSystemBackbufferFBO() const
|
||||
{
|
||||
#ifdef LOVE_IOS
|
||||
// Hack: iOS uses a custom FBO.
|
||||
SDL_SysWMinfo info = {};
|
||||
SDL_VERSION(&info.version);
|
||||
SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
|
||||
|
||||
if (info.info.uikit.resolveFramebuffer != 0)
|
||||
return info.info.uikit.resolveFramebuffer;
|
||||
else
|
||||
return info.info.uikit.framebuffer;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
|
||||
{
|
||||
this->width = width;
|
||||
this->height = height;
|
||||
|
||||
this->windowHasStencil = backbufferstencil;
|
||||
this->windowHasStencil = windowhasstencil;
|
||||
this->requestedBackbufferMSAA = msaa;
|
||||
|
||||
// Okay, setup OpenGL.
|
||||
gl.initContext();
|
||||
@@ -211,8 +305,6 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
created = true;
|
||||
initCapabilities();
|
||||
|
||||
setViewportSize(width, height, pixelwidth, pixelheight);
|
||||
|
||||
// Enable blending
|
||||
gl.setEnableState(OpenGL::ENABLE_BLEND, true);
|
||||
|
||||
@@ -252,6 +344,8 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
|
||||
setDebug(isDebugEnabled());
|
||||
|
||||
setViewportSize(width, height, pixelwidth, pixelheight);
|
||||
|
||||
if (batchedDrawState.vb[0] == nullptr)
|
||||
{
|
||||
// Initial sizes that should be good enough for most cases. It will
|
||||
@@ -263,7 +357,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
|
||||
|
||||
if (capabilities.features[FEATURE_TEXEL_BUFFER] && defaultBuffers[BUFFERTYPE_TEXEL].get() == nullptr)
|
||||
{
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_TEXEL, 0, BUFFERUSAGE_STATIC);
|
||||
Buffer::Settings settings(Buffer::TYPEFLAG_TEXEL, BUFFERUSAGE_STATIC);
|
||||
std::vector<Buffer::DataDeclaration> format = {{"", DATAFORMAT_FLOAT_VEC4, 0}};
|
||||
|
||||
const float texel[] = {0.0f, 0.0f, 0.0f, 1.0f};
|
||||
@@ -335,6 +429,9 @@ void Graphics::unSetMode()
|
||||
|
||||
flushBatchedDraws();
|
||||
|
||||
internalBackbuffer.set(nullptr);
|
||||
internalBackbufferDepthStencil.set(nullptr);
|
||||
|
||||
// Unload all volatile objects. These must be reloaded after the display
|
||||
// mode change.
|
||||
Volatile::unloadAll();
|
||||
@@ -552,7 +649,7 @@ void Graphics::setRenderTargetsInternal(const RenderTargets &rts, int w, int h,
|
||||
|
||||
if (iswindow)
|
||||
{
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
|
||||
|
||||
// The projection matrix is flipped compared to rendering to a texture,
|
||||
// due to OpenGL considering (0,0) bottom-left instead of top-left.
|
||||
@@ -594,6 +691,8 @@ void Graphics::endPass()
|
||||
// Discard the depth/stencil buffer if we're using an internal cached one.
|
||||
if (depthstencil == nullptr && (rts.temporaryRTFlags & (TEMPORARY_RT_DEPTH | TEMPORARY_RT_STENCIL)) != 0)
|
||||
discard({}, true);
|
||||
else if (!rts.getFirstTarget().texture.get())
|
||||
discard({}, true); // Backbuffer
|
||||
|
||||
// Resolve MSAA buffers. MSAA is only supported for 2D render targets so we
|
||||
// don't have to worry about resolving to slices.
|
||||
@@ -646,15 +745,12 @@ void Graphics::endPass()
|
||||
}
|
||||
}
|
||||
|
||||
// generateMipmaps can't be used for depth/stencil textures.
|
||||
for (const auto &rt : rts.colors)
|
||||
{
|
||||
if (rt.texture->getMipmapsMode() == Texture::MIPMAPS_AUTO && rt.mipmap == 0)
|
||||
rt.texture->generateMipmaps();
|
||||
}
|
||||
|
||||
int dsmipmap = rts.depthStencil.mipmap;
|
||||
if (depthstencil != nullptr && depthstencil->getMipmapsMode() == Texture::MIPMAPS_AUTO && dsmipmap == 0)
|
||||
depthstencil->generateMipmaps();
|
||||
}
|
||||
|
||||
void Graphics::clear(OptionalColorf c, OptionalInt stencil, OptionalDouble depth)
|
||||
@@ -812,7 +908,7 @@ void Graphics::discard(OpenGL::FramebufferTarget target, const std::vector<bool>
|
||||
attachments.reserve(colorbuffers.size());
|
||||
|
||||
// glDiscardFramebuffer uses different attachment enums for the default FBO.
|
||||
if (!isRenderTargetActive() && gl.getDefaultFBO() == 0)
|
||||
if (!isRenderTargetActive() && getInternalBackbufferFBO() == 0)
|
||||
{
|
||||
if (colorbuffers.size() > 0 && colorbuffers[0])
|
||||
attachments.push_back(GL_COLOR);
|
||||
@@ -879,7 +975,7 @@ void Graphics::cleanupRenderTexture(love::graphics::Texture *texture)
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::bindCachedFBO(const RenderTargets &targets)
|
||||
GLuint Graphics::bindCachedFBO(const RenderTargets &targets)
|
||||
{
|
||||
GLuint fbo = framebufferObjects[targets];
|
||||
|
||||
@@ -962,6 +1058,8 @@ void Graphics::bindCachedFBO(const RenderTargets &targets)
|
||||
|
||||
framebufferObjects[targets] = fbo;
|
||||
}
|
||||
|
||||
return fbo;
|
||||
}
|
||||
|
||||
void Graphics::present(void *screenshotCallbackData)
|
||||
@@ -977,13 +1075,34 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
flushBatchedDraws();
|
||||
endPass();
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
|
||||
int w = getPixelWidth();
|
||||
int h = getPixelHeight();
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
|
||||
|
||||
// Copy internal backbuffer to system backbuffer. When MSAA is used this
|
||||
// is a direct MSAA resolve.
|
||||
if (internalBackbuffer.get())
|
||||
{
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, getSystemBackbufferFBO());
|
||||
|
||||
// Discard system backbuffer to prevent it from copying its contents
|
||||
// from VRAM to chip memory.
|
||||
discard(OpenGL::FRAMEBUFFER_DRAW, {true}, true);
|
||||
|
||||
// updateBackbuffer checks for glBlitFramebuffer support.
|
||||
if (GLAD_APPLE_framebuffer_multisample && internalBackbuffer->getMSAA() > 1)
|
||||
glResolveMultisampleFramebufferAPPLE();
|
||||
else
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
|
||||
// Discarding the internal backbuffer directly after resolving it should
|
||||
// eliminate any copy back to vram it might need to do.
|
||||
discard(OpenGL::FRAMEBUFFER_READ, {true}, false);
|
||||
}
|
||||
|
||||
if (!pendingScreenshotCallbacks.empty())
|
||||
{
|
||||
int w = getPixelWidth();
|
||||
int h = getPixelHeight();
|
||||
|
||||
size_t row = 4 * w;
|
||||
size_t size = row * h;
|
||||
|
||||
@@ -1002,26 +1121,7 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
throw love::Exception("Out of memory.");
|
||||
}
|
||||
|
||||
#ifdef LOVE_IOS
|
||||
SDL_SysWMinfo info = {};
|
||||
SDL_VERSION(&info.version);
|
||||
SDL_GetWindowWMInfo(SDL_GL_GetCurrentWindow(), &info);
|
||||
|
||||
if (info.info.uikit.resolveFramebuffer != 0)
|
||||
{
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_DRAW, info.info.uikit.resolveFramebuffer);
|
||||
|
||||
// We need to do an explicit MSAA resolve on iOS, because it uses
|
||||
// GLES FBOs rather than a system framebuffer.
|
||||
if (GLAD_ES_VERSION_3_0)
|
||||
glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
|
||||
else if (GLAD_APPLE_framebuffer_multisample)
|
||||
glResolveMultisampleFramebufferAPPLE();
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_READ, info.info.uikit.resolveFramebuffer);
|
||||
}
|
||||
#endif
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getSystemBackbufferFBO());
|
||||
glReadPixels(0, 0, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
|
||||
|
||||
// Replace alpha values with full opacity.
|
||||
@@ -1085,6 +1185,8 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
if (window != nullptr)
|
||||
window->swapBuffers();
|
||||
|
||||
gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, getInternalBackbufferFBO());
|
||||
|
||||
// Reset the per-frame stat counts.
|
||||
drawCalls = 0;
|
||||
gl.stats.shaderSwitches = 0;
|
||||
@@ -1105,6 +1207,16 @@ void Graphics::present(void *screenshotCallbackData)
|
||||
}
|
||||
}
|
||||
|
||||
int Graphics::getRequestedBackbufferMSAA() const
|
||||
{
|
||||
return requestedBackbufferMSAA;
|
||||
}
|
||||
|
||||
int Graphics::getBackbufferMSAA() const
|
||||
{
|
||||
return internalBackbuffer.get() ? internalBackbuffer->getMSAA() : 0;
|
||||
}
|
||||
|
||||
void Graphics::setScissor(const Rect &rect)
|
||||
{
|
||||
flushBatchedDraws();
|
||||
@@ -1354,6 +1466,21 @@ void Graphics::setWireframe(bool enable)
|
||||
states.back().wireframe = enable;
|
||||
}
|
||||
|
||||
void *Graphics::getBufferMapMemory(size_t size)
|
||||
{
|
||||
// We don't need anything more complicated because get/release calls are
|
||||
// never interleaved (as of when this comment was written.)
|
||||
if (bufferMapMemory == nullptr || size > bufferMapMemorySize)
|
||||
return malloc(size);
|
||||
return bufferMapMemory;
|
||||
}
|
||||
|
||||
void Graphics::releaseBufferMapMemory(void *mem)
|
||||
{
|
||||
if (mem != bufferMapMemory)
|
||||
free(mem);
|
||||
}
|
||||
|
||||
Graphics::Renderer Graphics::getRenderer() const
|
||||
{
|
||||
return RENDERER_OPENGL;
|
||||
|
||||
Reference in New Issue
Block a user