소스 검색

Add support of scissor in both GL and Vulkan

Panagiotis Christopoulos Charitos 8 년 전
부모
커밋
173de24183

+ 2 - 5
src/anki/gr/CommandBuffer.h

@@ -158,11 +158,8 @@ public:
 	/// Set the viewport.
 	void setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy);
 
-	/// Enable scissor test.
-	void setScissorTest(Bool enable);
-
-	/// Set the scissor rect.
-	void setScissorRect(U16 minx, U16 miny, U16 maxx, U16 maxy);
+	/// Set the scissor rect. To disable the scissor just set a rect bigger than the viewport. By default it's disabled.
+	void setScissor(U16 minx, U16 miny, U16 maxx, U16 maxy);
 
 	/// Set fill mode.
 	void setFillMode(FillMode mode);

+ 27 - 2
src/anki/gr/gl/CommandBuffer.cpp

@@ -244,9 +244,34 @@ void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 	}
 }
 
-void CommandBuffer::setScissorRect(U16 minx, U16 miny, U16 maxx, U16 maxy)
+void CommandBuffer::setScissor(U16 minx, U16 miny, U16 maxx, U16 maxy)
 {
-	ANKI_ASSERT(!"TODO");
+	class ScissorCommand final : public GlCommand
+	{
+	public:
+		Array<U16, 4> m_value;
+
+		ScissorCommand(U16 a, U16 b, U16 c, U16 d)
+		{
+			m_value = {{a, b, c, d}};
+		}
+
+		Error operator()(GlState& state)
+		{
+			if(state.m_scissor[0] != m_value[0] || state.m_scissor[1] != m_value[1] || state.m_scissor[2] != m_value[2]
+				|| state.m_scissor[3] != m_value[3])
+			{
+				state.m_scissor = m_value;
+				glScissor(m_value[0], m_value[1], m_value[2], m_value[3]);
+			}
+			return ErrorCode::NONE;
+		}
+	};
+
+	if(m_impl->m_state.setScissor(minx, miny, maxx, maxy))
+	{
+		m_impl->pushBackNewCommand<ScissorCommand>(minx, miny, maxx - minx, maxy - miny);
+	}
 }
 
 void CommandBuffer::setFillMode(FillMode mode)

+ 5 - 0
src/anki/gr/gl/CommandBufferImpl.cpp

@@ -184,6 +184,11 @@ void CommandBufferImpl::flushDrawcall(CommandBuffer& cmdb)
 				cmdb.setBlendOperation(i, BlendOperation::ADD, BlendOperation::ADD);
 			}
 		}
+
+		if(!m_state.m_scissorSet)
+		{
+			cmdb.setScissor(0, 0, MAX_U16, MAX_U16);
+		}
 	}
 
 	//

+ 13 - 0
src/anki/gr/gl/FramebufferImpl.cpp

@@ -158,6 +158,14 @@ void FramebufferImpl::bind(const GlState& state)
 		glPushDebugGroup(GL_DEBUG_SOURCE_APPLICATION, m_glName, 0, &m_in.getName()[0]);
 	}
 
+	// Disable the scissor to make sure clears will clear everything
+	Bool disableScissor = !(state.m_scissor[0] == 0 && state.m_scissor[1] == 0 && state.m_scissor[2] == MAX_U16
+		&& state.m_scissor[3] == MAX_U16);
+	if(disableScissor)
+	{
+		glDisable(GL_SCISSOR_TEST);
+	}
+
 	if(m_bindDefault)
 	{
 		glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -262,6 +270,11 @@ void FramebufferImpl::bind(const GlState& state)
 			}
 		}
 	}
+
+	if(disableScissor)
+	{
+		glEnable(GL_SCISSOR_TEST);
+	}
 }
 
 void FramebufferImpl::endRenderPass() const

+ 2 - 0
src/anki/gr/gl/GlState.cpp

@@ -134,6 +134,8 @@ void GlState::initRenderThread()
 	glEnable(GL_PROGRAM_POINT_SIZE);
 	glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
 	glEnable(GL_CULL_FACE);
+	glEnable(GL_SCISSOR_TEST);
+	glScissor(0, 0, MAX_U16, MAX_U16);
 
 	// Create default VAO
 	glGenVertexArrays(1, &m_defaultVao);

+ 2 - 0
src/anki/gr/gl/GlState.h

@@ -49,6 +49,8 @@ public:
 
 	Array2d<GLuint, MAX_DESCRIPTOR_SETS, MAX_TEXTURE_BUFFER_BINDINGS> m_texBuffTextures = {};
 
+	Array<U16, 4> m_scissor = {{0, 0, MAX_U16, MAX_U16}};
+
 	GlState(GrManager* manager)
 		: m_manager(manager)
 	{

+ 18 - 0
src/anki/gr/gl/StateTracker.h

@@ -127,6 +127,24 @@ public:
 	}
 	/// @}
 
+	/// @name scissor_state
+	/// @{
+	Array<U16, 4> m_scissor = {{0, 0, MAX_U16, MAX_U16}};
+	Bool8 m_scissorSet = false;
+
+	Bool setScissor(U16 minx, U16 miny, U16 maxx, U16 maxy)
+	{
+		if(!m_scissorSet
+			|| (m_scissor[0] != minx || m_scissor[1] != miny || m_scissor[2] != maxx || m_scissor[3] != maxy))
+		{
+			m_scissor = {{minx, miny, maxx, maxy}};
+			m_scissorSet = true;
+			return true;
+		}
+		return false;
+	}
+	/// @}
+
 	/// @name rasterizer
 	/// @{
 	FillMode m_fillMode = FillMode::COUNT;

+ 2 - 7
src/anki/gr/vulkan/CommandBuffer.cpp

@@ -86,14 +86,9 @@ void CommandBuffer::setViewport(U16 minx, U16 miny, U16 maxx, U16 maxy)
 	m_impl->setViewport(minx, miny, maxx, maxy);
 }
 
-void CommandBuffer::setScissorTest(Bool enable)
+void CommandBuffer::setScissor(U16 minx, U16 miny, U16 maxx, U16 maxy)
 {
-	ANKI_ASSERT(!"TODO");
-}
-
-void CommandBuffer::setScissorRect(U16 minx, U16 miny, U16 maxx, U16 maxy)
-{
-	ANKI_ASSERT(!"TODO");
+	m_impl->setScissor(minx, miny, maxx, maxy);
 }
 
 void CommandBuffer::setFillMode(FillMode mode)

+ 20 - 0
src/anki/gr/vulkan/CommandBufferImpl.h

@@ -135,6 +135,22 @@ public:
 		}
 	}
 
+	void setScissor(U16 minx, U16 miny, U16 maxx, U16 maxy)
+	{
+		ANKI_ASSERT(minx < maxx && miny < maxy);
+		commandCommon();
+
+		if(m_scissor[0] != minx || m_scissor[1] != miny || m_scissor[2] != maxx || m_scissor[3] != maxy)
+		{
+			m_scissorDirty = true;
+
+			m_scissor[0] = minx;
+			m_scissor[1] = miny;
+			m_scissor[2] = maxx;
+			m_scissor[3] = maxy;
+		}
+	}
+
 	void setPolygonOffset(F32 factor, F32 units)
 	{
 		commandCommon();
@@ -358,7 +374,9 @@ private:
 	/// @name state_opts
 	/// @{
 	Array<U16, 4> m_viewport = {{0, 0, 0, 0}};
+	Array<U16, 4> m_scissor = {{0, 0, MAX_U16, MAX_U16}};
 	Bool8 m_viewportDirty = true;
+	Bool8 m_scissorDirty = true;
 	Array<U32, 2> m_stencilCompareMasks = {{0x5A5A5A5A, 0x5A5A5A5A}}; ///< Use a stupid number to initialize.
 	Array<U32, 2> m_stencilWriteMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
 	Array<U32, 2> m_stencilReferenceMasks = {{0x5A5A5A5A, 0x5A5A5A5A}};
@@ -451,6 +469,8 @@ private:
 		const VkImageSubresourceRange& range);
 
 	void beginRecording();
+
+	Bool flipViewport() const;
 };
 /// @}
 

+ 27 - 6
src/anki/gr/vulkan/CommandBufferImpl.inl.h

@@ -519,8 +519,7 @@ inline void CommandBufferImpl::drawcallCommon()
 	// Flush viewport
 	if(ANKI_UNLIKELY(m_viewportDirty))
 	{
-		const Bool flipViewport = m_activeFb->m_impl->isDefaultFramebuffer()
-			&& !!(getGrManagerImpl().getExtensions() & VulkanExtensions::KHR_MAINENANCE1);
+		const Bool flipvp = flipViewport();
 
 		const I minx = m_viewport[0];
 		const I miny = m_viewport[1];
@@ -532,21 +531,37 @@ inline void CommandBufferImpl::drawcallCommon()
 
 		VkViewport s;
 		s.x = minx;
-		s.y = (flipViewport) ? (fbHeight - miny) : miny; // Move to the bottom;
+		s.y = (flipvp) ? (fbHeight - miny) : miny; // Move to the bottom;
 		s.width = maxx - minx;
-		s.height = (flipViewport) ? -(maxy - miny) : (maxy - miny);
+		s.height = (flipvp) ? -(maxy - miny) : (maxy - miny);
 		s.minDepth = 0.0;
 		s.maxDepth = 1.0;
 		ANKI_CMD(vkCmdSetViewport(m_handle, 0, 1, &s), ANY_OTHER_COMMAND);
 
+		m_viewportDirty = false;
+	}
+
+	// Flush scissor
+	if(ANKI_UNLIKELY(m_scissorDirty))
+	{
+		const Bool flipvp = flipViewport();
+
+		const I minx = m_scissor[0];
+		const I miny = m_scissor[1];
+		const I maxx = m_scissor[2];
+		const I maxy = m_scissor[3];
+
+		U32 fbWidth, fbHeight;
+		m_activeFb->m_impl->getAttachmentsSize(fbWidth, fbHeight);
+
 		VkRect2D scissor = {};
 		scissor.extent.width = maxx - minx;
 		scissor.extent.height = maxy - miny;
 		scissor.offset.x = minx;
-		scissor.offset.y = (flipViewport) ? (fbHeight - maxy) : miny;
+		scissor.offset.y = (flipvp) ? (fbHeight - maxy) : miny;
 		ANKI_CMD(vkCmdSetScissor(m_handle, 0, 1, &scissor), ANY_OTHER_COMMAND);
 
-		m_viewportDirty = false;
+		m_scissorDirty = false;
 	}
 
 	ANKI_TRACE_INC_COUNTER(GR_DRAWCALLS, 1);
@@ -714,4 +729,10 @@ inline void CommandBufferImpl::copyBufferToBuffer(
 	m_microCmdb->pushObjectRef(dst);
 }
 
+inline Bool CommandBufferImpl::flipViewport() const
+{
+	return m_activeFb->m_impl->isDefaultFramebuffer()
+		&& !!(getGrManagerImpl().getExtensions() & VulkanExtensions::KHR_MAINENANCE1);
+}
+
 } // end namespace anki

+ 1 - 1
src/anki/gr/vulkan/FramebufferImpl.cpp

@@ -195,7 +195,7 @@ void FramebufferImpl::setupAttachmentDescriptor(
 {
 	// TODO This func won't work if it's default but this is a depth attachment
 
-	const VkImageLayout layout = (m_defaultFb) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_MAX_ENUM;
+	const VkImageLayout layout = (m_defaultFb) ? VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL : VK_IMAGE_LAYOUT_GENERAL;
 
 	desc = {};
 	desc.format = (m_defaultFb) ? getGrManagerImpl().getDefaultFramebufferSurfaceFormat()

+ 3 - 0
tests/gr/Gr.cpp

@@ -428,6 +428,7 @@ ANKI_TEST(Gr, SimpleDrawcall)
 		{{0, HEIGHT / 2, WIDTH / 2, HEIGHT}}}};
 
 	const U ITERATIONS = 200;
+	const U SCISSOR_MARGIN = 20;
 	for(U i = 0; i < ITERATIONS; ++i)
 	{
 		HighRezTimer timer;
@@ -441,6 +442,8 @@ ANKI_TEST(Gr, SimpleDrawcall)
 
 		auto vp = VIEWPORTS[(i / 30) % 4];
 		cmdb->setViewport(vp[0], vp[1], vp[2], vp[3]);
+		cmdb->setScissor(
+			vp[0] + SCISSOR_MARGIN, vp[1] + SCISSOR_MARGIN, vp[2] - SCISSOR_MARGIN, vp[3] - SCISSOR_MARGIN);
 		cmdb->bindShaderProgram(prog);
 		cmdb->beginRenderPass(fb);
 		cmdb->drawArrays(PrimitiveTopology::TRIANGLES, 3);