Browse Source

Improve backbuffer depth buffer.

- Setting the depth buffer for the backbuffer is now done as a boolean instead of a bit depth integer, in love.conf or love.window.setMode.
- Error if depth writes are enabled when the active canvas setup or backbuffer does not have a depth buffer (now it matches stencil behaviour).
- Don't allocate a backbuffer depth-stencil buffer if they're not requested. Metal also determines the format for that buffer based on which combination of depth and stencil is requested. OpenGL still has to allocate the depth-stencil buffer for the backbuffer all the time, because changing it requires the context to be recreated.
Sasha Szpakowski 1 year ago
parent
commit
aaab9791d5

+ 35 - 0
src/modules/graphics/Graphics.cpp

@@ -185,6 +185,8 @@ Graphics::Graphics()
 	, height(0)
 	, pixelWidth(0)
 	, pixelHeight(0)
+	, backbufferHasStencil(false)
+	, backbufferHasDepth(false)
 	, created(false)
 	, active(true)
 	, batchedDrawState()
@@ -617,6 +619,34 @@ Texture *Graphics::getTextureOrDefaultForActiveShader(Texture *tex)
 	return getDefaultTexture(TEXTURE_2D, DATA_BASETYPE_FLOAT);
 }
 
+void Graphics::validateStencilState(const StencilState &s) const
+{
+	if (s.action != STENCIL_KEEP)
+	{
+		const auto &rts = states.back().renderTargets;
+		love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
+
+		if (!isRenderTargetActive() && !backbufferHasStencil)
+			throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
+		else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
+			throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas.");
+	}
+}
+
+void Graphics::validateDepthState(bool depthwrite) const
+{
+	if (depthwrite)
+	{
+		const auto &rts = states.back().renderTargets;
+		love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
+
+		if (!isRenderTargetActive() && !backbufferHasDepth)
+			throw love::Exception("The window must have depth enabled to draw to the main screen's depth buffer.");
+		else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) == 0 && (dstexture == nullptr || !isPixelFormatDepth(dstexture->getPixelFormat())))
+			throw love::Exception("Drawing to the depth buffer with a Canvas active requires either depth=true or a custom depth-type Canvas to be used, in setCanvas.");
+	}
+}
+
 int Graphics::getWidth() const
 {
 	return width;
@@ -671,6 +701,11 @@ void Graphics::reset()
 	origin();
 }
 
+void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight)
+{
+	backbufferChanged(width, height, pixelwidth, pixelheight, backbufferHasStencil, backbufferHasDepth, getRequestedBackbufferMSAA());
+}
+
 /**
  * State functions.
  **/

+ 10 - 5
src/modules/graphics/Graphics.h

@@ -506,16 +506,15 @@ public:
 	virtual void present(void *screenshotCallbackData) = 0;
 
 	/**
-	 * Sets the current graphics display viewport dimensions.
+	 * Called when the backbuffer changes.
 	 **/
-	virtual void setViewportSize(int width, int height, int pixelwidth, int pixelheight) = 0;
+	virtual void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) = 0;
+	void backbufferChanged(int width, int height, int pixelwidth, int pixelheight);
 
 	/**
 	 * Sets the current graphics display viewport and initializes the renderer.
-	 * @param width The viewport width.
-	 * @param height The viewport height.
 	 **/
-	virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) = 0;
+	virtual bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) = 0;
 
 	/**
 	 * Un-sets the current graphics display mode (uninitializing objects if
@@ -1048,6 +1047,9 @@ protected:
 
 	void releaseDefaultResources();
 
+	void validateStencilState(const StencilState &s) const;
+	void validateDepthState(bool depthwrite) const;
+
 	void restoreState(const DisplayState &s);
 	void restoreStateChecked(const DisplayState &s);
 
@@ -1063,6 +1065,9 @@ protected:
 	int pixelWidth;
 	int pixelHeight;
 
+	bool backbufferHasStencil;
+	bool backbufferHasDepth;
+
 	bool created;
 	bool active;
 

+ 2 - 3
src/modules/graphics/metal/Graphics.h

@@ -68,8 +68,8 @@ public:
 
 	Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
 
-	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
-	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
+	void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
+	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
 	void unSetMode() override;
 
 	void setActive(bool active) override;
@@ -231,7 +231,6 @@ private:
 	uint32 dirtyRenderState;
 	CullMode lastCullMode;
 	Shader::RenderPipelineKey lastRenderPipelineKey;
-	bool windowHasStencil;
 	int shaderSwitches;
 
 	StrongRef<love::graphics::Texture> backbufferMSAA;

+ 49 - 32
src/modules/graphics/metal/Graphics.mm

@@ -274,7 +274,6 @@ Graphics::Graphics()
 	, dirtyRenderState(STATEBIT_ALL)
 	, lastCullMode(CULL_MAX_ENUM)
 	, lastRenderPipelineKey()
-	, windowHasStencil(false)
 	, shaderSwitches(0)
 	, requestedBackbufferMSAA(0)
 	, attachmentStoreActions()
@@ -464,13 +463,23 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool /*rend
 	return calculateDeviceProjection(projection, flags);
 }
 
-void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
+void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 {
+	bool sizechanged = width != this->width || height != this->height
+		|| pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight;
+
+	bool dschanged = backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth;
+	bool msaachanged = msaa != this->requestedBackbufferMSAA;
+
 	this->width = width;
 	this->height = height;
 	this->pixelWidth = pixelwidth;
 	this->pixelHeight = pixelheight;
 
+	this->backbufferHasStencil = backbufferstencil;
+	this->backbufferHasDepth = backbufferdepth;
+	this->requestedBackbufferMSAA = msaa;
+
 	if (!isRenderTargetActive())
 	{
 		dirtyRenderState |= STATEBIT_VIEWPORT | STATEBIT_SCISSOR;
@@ -485,26 +494,38 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 	settings.renderTarget = true;
 	settings.readable.set(false);
 
-	backbufferMSAA.set(nullptr);
-	if (settings.msaa > 1)
+	if (sizechanged || msaachanged)
 	{
-		settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM;
-		backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN);
+		backbufferMSAA.set(nullptr);
+		if (settings.msaa > 1)
+		{
+			settings.format = isGammaCorrect() ? PIXELFORMAT_BGRA8_sRGB : PIXELFORMAT_BGRA8_UNORM;
+			backbufferMSAA.set(newTexture(settings), Acquire::NORETAIN);
+		}
 	}
 
-	settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
-	backbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
+	if (sizechanged || msaachanged || dschanged)
+	{
+		backbufferDepthStencil.set(nullptr);
+		if (backbufferstencil || backbufferdepth)
+		{
+			if (backbufferstencil && backbufferdepth)
+				settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
+			else if (backbufferstencil)
+				settings.format = PIXELFORMAT_STENCIL8;
+			else if (backbufferdepth)
+				settings.format = PIXELFORMAT_DEPTH24_UNORM;
+			backbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
+		}
+	}
 }
 
-bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
+bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 { @autoreleasepool {
 	this->width = width;
 	this->height = height;
 	this->metalLayer = (__bridge CAMetalLayer *) context;
 
-	this->windowHasStencil = windowhasstencil;
-	this->requestedBackbufferMSAA = msaa;
-
 	metalLayer.device = device;
 	metalLayer.pixelFormat = isGammaCorrect() ? MTLPixelFormatBGRA8Unorm_sRGB : MTLPixelFormatBGRA8Unorm;
 
@@ -516,7 +537,7 @@ bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int
 	metalLayer.magnificationFilter = kCAFilterNearest;
 #endif
 
-	setViewportSize(width, height, pixelwidth, pixelheight);
+	backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa);
 
 	created = true;
 
@@ -660,8 +681,10 @@ id<MTLRenderCommandEncoder> Graphics::useRenderEncoder()
 			passDesc.colorAttachments[0].depthPlane = 0;
 
 			RenderTarget rt(backbufferDepthStencil);
-			setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth, false);
-			setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil, false);
+			if (rt.texture != nullptr && isPixelFormatDepth(rt.texture->getPixelFormat()))
+				setAttachment(rt, passDesc.depthAttachment, attachmentStoreActions.depth, false);
+			if (rt.texture != nullptr && isPixelFormatStencil(rt.texture->getPixelFormat()))
+				setAttachment(rt, passDesc.stencilAttachment, attachmentStoreActions.stencil, false);
 			attachmentStoreActions.depth = MTLStoreActionDontCare;
 			attachmentStoreActions.stencil = MTLStoreActionDontCare;
 
@@ -700,11 +723,15 @@ void Graphics::submitRenderEncoder(SubmitType type)
 		for (size_t i = 0; i < rts.colors.size(); i++)
 			[renderEncoder setColorStoreAction:(store ? MTLStoreActionStore : actions.color[i]) atIndex:i];
 
-		if (rts.depthStencil.texture.get() || rts.temporaryRTFlags != 0 || isbackbuffer)
-		{
+		love::graphics::Texture *ds = rts.depthStencil.texture.get();
+		if (isbackbuffer)
+			ds = backbufferDepthStencil;
+
+		if ((rts.temporaryRTFlags & TEMPORARY_RT_DEPTH) != 0 || (ds != nullptr && isPixelFormatDepth(ds->getPixelFormat())))
 			[renderEncoder setDepthStoreAction:store ? MTLStoreActionStore : actions.depth];
+
+		if ((rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) != 0 || (ds != nullptr && isPixelFormatStencil(ds->getPixelFormat())))
 			[renderEncoder setStencilStoreAction:store ? MTLStoreActionStore : actions.stencil];
-		}
 
 		[renderEncoder endEncoding];
 		renderEncoder = nil;
@@ -1762,28 +1789,18 @@ void Graphics::setScissor()
 
 void Graphics::setStencilState(const StencilState &s)
 {
-	DisplayState &state = states.back();
-
-	if (s.action != STENCIL_KEEP)
-	{
-		const auto &rts = state.renderTargets;
-		love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
-
-		if (!isRenderTargetActive() && !windowHasStencil)
-			throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
-		else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
-			throw love::Exception("Drawing to the stencil buffer with a Canvas active requires either stencil=true or a custom stencil-type Canvas to be used, in setCanvas.");
-	}
+	validateStencilState(s);
 
 	flushBatchedDraws();
 
-	state.stencil = s;
-
+	states.back().stencil = s;
 	dirtyRenderState |= STATEBIT_STENCIL;
 }
 
 void Graphics::setDepthMode(CompareMode compare, bool write)
 {
+	validateDepthState(write);
+
 	DisplayState &state = states.back();
 
 	if (state.depthTest != compare || state.depthWrite != write)

+ 30 - 30
src/modules/graphics/opengl/Graphics.cpp

@@ -200,13 +200,23 @@ Matrix4 Graphics::computeDeviceProjection(const Matrix4 &projection, bool render
 	return calculateDeviceProjection(projection, flags);
 }
 
-void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
+void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 {
+	bool changed = width != this->width || height != this->height
+		|| pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight;
+
+	changed |= backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth;
+	changed |= msaa != this->requestedBackbufferMSAA;
+
 	this->width = width;
 	this->height = height;
 	this->pixelWidth = pixelwidth;
 	this->pixelHeight = pixelheight;
 
+	this->backbufferHasStencil = backbufferstencil;
+	this->backbufferHasDepth = backbufferdepth;
+	this->requestedBackbufferMSAA = msaa;
+
 	if (!isRenderTargetActive())
 	{
 		// Set the viewport to top-left corner.
@@ -220,11 +230,9 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 		resetProjection();
 	}
 
-	updateBackbuffer(width, height, pixelwidth, pixelheight, requestedBackbufferMSAA);
-}
+	if (!changed)
+		return;
 
-void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int pixelheight, int msaa)
-{
 	bool useinternalbackbuffer = false;
 	if (msaa > 1)
 		useinternalbackbuffer = true;
@@ -253,8 +261,17 @@ void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int p
 		settings.format = isGammaCorrect() ? PIXELFORMAT_RGBA8_sRGB : PIXELFORMAT_RGBA8_UNORM;
 		internalBackbuffer.set(newTexture(settings), Acquire::NORETAIN);
 
-		settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
-		internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
+		internalBackbufferDepthStencil.set(nullptr);
+		if (backbufferstencil || backbufferdepth)
+		{
+			if (backbufferstencil && backbufferdepth)
+				settings.format = PIXELFORMAT_DEPTH24_UNORM_STENCIL8;
+			else if (backbufferstencil)
+				settings.format = PIXELFORMAT_STENCIL8;
+			else if (backbufferdepth)
+				settings.format = PIXELFORMAT_DEPTH24_UNORM;
+			internalBackbufferDepthStencil.set(newTexture(settings), Acquire::NORETAIN);
+		}
 
 		RenderTargets rts;
 		rts.colors.push_back(internalBackbuffer.get());
@@ -269,8 +286,6 @@ void Graphics::updateBackbuffer(int width, int height, int /*pixelwidth*/, int p
 		internalBackbufferFBO = 0;
 	}
 
-	requestedBackbufferMSAA = msaa;
-
 	if (restoreFBO)
 		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, prevFBO);
 }
@@ -300,14 +315,8 @@ GLuint Graphics::getSystemBackbufferFBO() const
 #endif
 }
 
-bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
+bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 {
-	this->width = width;
-	this->height = height;
-
-	this->windowHasStencil = windowhasstencil;
-	this->requestedBackbufferMSAA = msaa;
-
 	// Okay, setup OpenGL.
 	gl.initContext();
 
@@ -364,7 +373,7 @@ bool Graphics::setMode(void */*context*/, int width, int height, int pixelwidth,
 
 	setDebug(isDebugEnabled());
 
-	setViewportSize(width, height, pixelwidth, pixelheight);
+	backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa);
 
 	if (batchedDrawState.vb[0] == nullptr)
 	{
@@ -1436,18 +1445,7 @@ void Graphics::setScissor()
 
 void Graphics::setStencilState(const StencilState &s)
 {
-	DisplayState &state = states.back();
-
-	if (s.action != STENCIL_KEEP)
-	{
-		const auto &rts = state.renderTargets;
-		love::graphics::Texture *dstexture = rts.depthStencil.texture.get();
-
-		if (!isRenderTargetActive() && !windowHasStencil)
-			throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer.");
-		else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dstexture == nullptr || !isPixelFormatStencil(dstexture->getPixelFormat())))
-			throw love::Exception("Drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type texture to be used, in setRenderTarget.");
-	}
+	validateStencilState(s);
 
 	flushBatchedDraws();
 
@@ -1507,11 +1505,13 @@ void Graphics::setStencilState(const StencilState &s)
 	if (s.writeMask != gl.getStencilWriteMask())
 		gl.setStencilWriteMask(s.writeMask);
 
-	state.stencil = s;
+	states.back().stencil = s;
 }
 
 void Graphics::setDepthMode(CompareMode compare, bool write)
 {
+	validateDepthState(write);
+
 	DisplayState &state = states.back();
 
 	if (state.depthTest != compare || state.depthWrite != write)

+ 2 - 2
src/modules/graphics/opengl/Graphics.h

@@ -64,8 +64,8 @@ public:
 
 	Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
 
-	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
-	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
+	void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
+	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
 	void unSetMode() override;
 
 	void setActive(bool active) override;

+ 36 - 26
src/modules/graphics/vulkan/Graphics.cpp

@@ -587,9 +587,10 @@ void Graphics::present(void *screenshotCallbackdata)
 	beginFrame();
 }
 
-void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelheight)
+void Graphics::backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 {
-	if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height))
+	if (swapChain != VK_NULL_HANDLE && (pixelwidth != this->pixelWidth || pixelheight != this->pixelHeight || width != this->width || height != this->height
+		|| backbufferstencil != this->backbufferHasStencil || backbufferdepth != this->backbufferHasDepth || msaa != requestedMsaa))
 		requestSwapchainRecreation();
 
 	this->width = width;
@@ -597,17 +598,21 @@ void Graphics::setViewportSize(int width, int height, int pixelwidth, int pixelh
 	this->pixelWidth = pixelwidth;
 	this->pixelHeight = pixelheight;
 
+	this->backbufferHasStencil = backbufferstencil;
+	this->backbufferHasDepth = backbufferdepth;
+	this->requestedMsaa = msaa;
+
 	if (!isRenderTargetActive())
 		resetProjection();
+
+	if (swapChain != VK_NULL_HANDLE)
+		msaaSamples = getMsaaCount(requestedMsaa);
 }
 
-bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa)
+bool Graphics::setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa)
 {
-	requestedMsaa = msaa;
-	windowHasStencil = windowhasstencil;
-
 	// Must be called before the swapchain is created.
-	setViewportSize(width, height, pixelwidth, pixelheight);
+	backbufferChanged(width, height, pixelwidth, pixelheight, backbufferstencil, backbufferdepth, msaa);
 
 	cleanUpFunctions.clear();
 	cleanUpFunctions.resize(MAX_FRAMES_IN_FLIGHT);
@@ -1003,16 +1008,7 @@ void Graphics::setScissor()
 
 void Graphics::setStencilState(const StencilState &s)
 {
-	if (s.action != STENCIL_KEEP)
-	{
-		const auto& rts = states.back().renderTargets;
-		auto dsTexture = rts.depthStencil.texture.get();
-
-		if (!isRenderTargetActive() && !windowHasStencil)
-			throw love::Exception("The window must have stenciling enabled to draw to the main screen's stencil buffer");
-		else if (isRenderTargetActive() && (rts.temporaryRTFlags & TEMPORARY_RT_STENCIL) == 0 && (dsTexture == nullptr || !isPixelFormatStencil(dsTexture->getPixelFormat())))
-			throw love::Exception("drawing to the stencil buffer with a render target active requires either stencil=true or a custom stencil-type to be used, in setRenderTarget");
-	}
+	validateStencilState(s);
 
 	flushBatchedDraws();
 
@@ -1033,6 +1029,8 @@ void Graphics::setStencilState(const StencilState &s)
 
 void Graphics::setDepthMode(CompareMode compare, bool write)
 {
+	validateDepthState(write);
+
 	flushBatchedDraws();
 
 	if (optionalDeviceExtensions.extendedDynamicState)
@@ -1284,11 +1282,12 @@ void Graphics::beginFrame()
 
 	if (transitionColorDepthLayouts)
 	{
-		Vulkan::cmdTransitionImageLayout(
-			commandBuffers.at(currentFrame),
-			depthImage,
-			VK_IMAGE_LAYOUT_UNDEFINED,
-			VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
+		if (depthImage)
+			Vulkan::cmdTransitionImageLayout(
+				commandBuffers.at(currentFrame),
+				depthImage,
+				VK_IMAGE_LAYOUT_UNDEFINED,
+				VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
 
 		if (colorImage)
 			Vulkan::cmdTransitionImageLayout(
@@ -2935,6 +2934,13 @@ VkFormat Graphics::findDepthFormat()
 
 void Graphics::createDepthResources()
 {
+	if (!backbufferHasDepth && !backbufferHasStencil)
+	{
+		depthImage = VK_NULL_HANDLE;
+		depthImageView = VK_NULL_HANDLE;
+		return;
+	}
+
 	VkImageCreateInfo imageInfo{};
 	imageInfo.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
 	imageInfo.imageType = VK_IMAGE_TYPE_2D;
@@ -2966,8 +2972,9 @@ void Graphics::createDepthResources()
 	imageViewInfo.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
 	imageViewInfo.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
 	imageViewInfo.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
-	imageViewInfo.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
-	if (windowHasStencil)
+	if (backbufferHasDepth)
+		imageViewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_DEPTH_BIT;
+	if (backbufferHasStencil)
 		imageViewInfo.subresourceRange.aspectMask |= VK_IMAGE_ASPECT_STENCIL_BIT;
 	imageViewInfo.subresourceRange.baseMipLevel = 0;
 	imageViewInfo.subresourceRange.levelCount = 1;
@@ -3076,8 +3083,11 @@ void Graphics::cleanupSwapChain()
 		vkDestroyImageView(device, colorImageView, nullptr);
 		vmaDestroyImage(vmaAllocator, colorImage, colorImageAllocation);
 	}
-	vkDestroyImageView(device, depthImageView, nullptr);
-	vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
+	if (depthImage)
+	{
+		vkDestroyImageView(device, depthImageView, nullptr);
+		vmaDestroyImage(vmaAllocator, depthImage, depthImageAllocation);
+	}
 	for (const auto &swapChainImageView : swapChainImageViews)
 		vkDestroyImageView(device, swapChainImageView, nullptr);
 	swapChainImageViews.clear();

+ 2 - 3
src/modules/graphics/vulkan/Graphics.h

@@ -284,8 +284,8 @@ public:
 	Matrix4 computeDeviceProjection(const Matrix4 &projection, bool rendertotexture) const override;
 	void discard(const std::vector<bool>& colorbuffers, bool depthstencil) override;
 	void present(void *screenshotCallbackdata) override;
-	void setViewportSize(int width, int height, int pixelwidth, int pixelheight) override;
-	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool windowhasstencil, int msaa) override;
+	void backbufferChanged(int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
+	bool setMode(void *context, int width, int height, int pixelwidth, int pixelheight, bool backbufferstencil, bool backbufferdepth, int msaa) override;
 	void unSetMode() override;
 	void setActive(bool active) override;
 	int getRequestedBackbufferMSAA() const override;
@@ -394,7 +394,6 @@ private:
 	VkInstance instance = VK_NULL_HANDLE;
 	VkPhysicalDevice physicalDevice = VK_NULL_HANDLE;
 	uint32_t deviceApiVersion = VK_API_VERSION_1_0;
-	bool windowHasStencil = false;
 	int requestedMsaa = 0;
 	VkDevice device = VK_NULL_HANDLE; 
 	OptionalInstanceExtensions optionalInstanceExtensions;

+ 1 - 1
src/modules/window/Window.h

@@ -262,7 +262,7 @@ struct WindowSettings
 	int vsync = 1;
 	int msaa = 0;
 	bool stencil = true;
-	int depth = 0;
+	bool depth = false;
 	bool resizable = false;
 	int minwidth = 1;
 	int minheight = 1;

+ 5 - 6
src/modules/window/sdl/Window.cpp

@@ -127,8 +127,7 @@ void Window::setGLFramebufferAttributes(bool sRGB)
 	SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
 	SDL_GL_SetAttribute(SDL_GL_RETAINED_BACKING, 0);
 
-	// Always use 24/8 depth/stencil (make sure any Graphics implementations
-	// that have their own backbuffer match this, too).
+	// Always use 24/8 depth/stencil.
 	// Changing this after initial window creation would need the context to be
 	// destroyed and recreated, which we really don't want.
 	SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
@@ -639,12 +638,12 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
 				context = (void *) SDL_Metal_GetLayer(metalView);
 #endif
 
-			graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.msaa);
+			graphics->setMode(context, (int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.depth, f.msaa);
 			this->settings.msaa = graphics->getBackbufferMSAA();
 		}
 		else
 		{
-			graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight);
+			graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight, f.stencil, f.depth, f.msaa);
 		}
 	}
 
@@ -687,7 +686,7 @@ bool Window::onSizeChanged(int width, int height)
 	{
 		double scaledw, scaledh;
 		fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh);
-		graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight);
+		graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight);
 	}
 
 	return true;
@@ -771,7 +770,7 @@ void Window::updateSettings(const WindowSettings &newsettings, bool updateGraphi
 	{
 		double scaledw, scaledh;
 		fromPixels((double) pixelWidth, (double) pixelHeight, scaledw, scaledh);
-		graphics->setViewportSize((int) scaledw, (int) scaledh, pixelWidth, pixelHeight);
+		graphics->backbufferChanged((int) scaledw, (int) scaledh, pixelWidth, pixelHeight);
 	}
 }
 

+ 11 - 2
src/modules/window/wrap_Window.cpp

@@ -68,7 +68,6 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings)
 	settings.fullscreen = luax_boolflag(L, idx, settingName(Window::SETTING_FULLSCREEN), settings.fullscreen);
 	settings.msaa = luax_intflag(L, idx, settingName(Window::SETTING_MSAA), settings.msaa);
 	settings.stencil = luax_boolflag(L, idx, settingName(Window::SETTING_STENCIL), settings.stencil);
-	settings.depth = luax_intflag(L, idx, settingName(Window::SETTING_DEPTH), settings.depth);
 	settings.resizable = luax_boolflag(L, idx, settingName(Window::SETTING_RESIZABLE), settings.resizable);
 	settings.minwidth = luax_intflag(L, idx, settingName(Window::SETTING_MIN_WIDTH), settings.minwidth);
 	settings.minheight = luax_intflag(L, idx, settingName(Window::SETTING_MIN_HEIGHT), settings.minheight);
@@ -76,6 +75,16 @@ static int readWindowSettings(lua_State *L, int idx, WindowSettings &settings)
 	settings.centered = luax_boolflag(L, idx, settingName(Window::SETTING_CENTERED), settings.centered);
 	settings.usedpiscale = luax_boolflag(L, idx, settingName(Window::SETTING_USE_DPISCALE), settings.usedpiscale);
 
+	lua_getfield(L, idx, settingName(Window::SETTING_DEPTH));
+	if (lua_type(L, -1) == LUA_TNUMBER)
+	{
+		luax_markdeprecated(L, 1, "window.depth number", API_FIELD, DEPRECATED_REPLACED, "window.depth boolean field");
+		settings.depth = (int) luaL_checknumber(L, -1);
+	}
+	else if (!lua_isnoneornil(L, -1))
+		settings.depth = lua_toboolean(L, -1);
+	lua_pop(L, 1);
+
 	settings.displayindex = luax_intflag(L, idx, settingName(Window::SETTING_DISPLAYINDEX), settings.displayindex + 1) - 1;
 	lua_getfield(L, idx, settingName(Window::SETTING_DISPLAY));
 	if (!lua_isnoneornil(L, -1))
@@ -197,7 +206,7 @@ int w_getMode(lua_State *L)
 	luax_pushboolean(L, settings.stencil);
 	lua_setfield(L, -2, settingName(Window::SETTING_STENCIL));
 
-	lua_pushinteger(L, settings.depth);
+	luax_pushboolean(L, settings.depth);
 	lua_setfield(L, -2, settingName(Window::SETTING_DEPTH));
 
 	luax_pushboolean(L, settings.resizable);