浏览代码

More work on the UI

Panagiotis Christopoulos Charitos 8 年之前
父节点
当前提交
bb569747ea

+ 63 - 0
programs/Ui.ankiprog

@@ -0,0 +1,63 @@
+<!-- 
+Copyright (C) 2009-2017, Panagiotis Christopoulos Charitos and contributors.
+All rights reserved.
+Code licensed under the BSD License.
+http://www.anki3d.org/LICENSE
+-->
+<shaderProgram>
+	<mutators>
+		<mutator name="IDENTITY_TEX" values="0 1"/>
+	</mutators>
+
+	<shaders>
+		<shader type="vert">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+layout(location = 0) in vec2 in_pos;
+layout(location = 1) in vec2 in_uv;
+layout(location = 3) in vec4 in_col;
+
+layout(location = 0) out vec2 out_uv;
+layout(location = 1) out vec4 out_col;
+
+out gl_PerVertex
+{
+	vec4 gl_Position;
+};
+
+void main()
+{
+	out_uv = in_uv;
+	out_col = in_col;
+
+	gl_Position = vec4(in_pos, 0.0, 1.0);
+}
+			]]></source>
+		</shader>
+
+		<shader type="frag">
+			<source><![CDATA[
+#include "shaders/Common.glsl"
+
+layout(location = 0) in vec2 in_uv;
+layout(location = 1) in vec4 in_col;
+
+layout(location = 0) out vec4 out_col;
+
+#if !IDENTITY_TEX
+layout(ANKI_TEX_BINDING(0, 0)) uniform sampler2D u_tex;
+#endif
+
+void main()
+{
+	out_col = in_col 
+#if !IDENTITY_TEX
+		* texture(u_tex, in_uv)
+#endif
+		;
+}
+			]]></source>
+		</shader>
+	</shaders>
+</shaderProgram>

+ 1 - 1
src/anki/renderer/Is.cpp

@@ -102,7 +102,7 @@ Error Is::initInternal(const ConfigSet& config)
 		.add("CLUSTER_COUNT", U32(m_clusterCount))
 		.add("IR_MIPMAP_COUNT", U32(m_r->getIr().getReflectionTextureMipmapCount()));
 
-	m_prog->getOrCreateVariant(consts.m_constantValues, m_progVariant);
+	m_prog->getOrCreateVariant(consts.get(), m_progVariant);
 
 	//
 	// Create framebuffer

+ 3 - 3
src/anki/renderer/Pps.cpp

@@ -72,11 +72,11 @@ Error Pps::initInternal(const ConfigSet& config)
 	consts.add("LUT_SIZE", U32(LUT_SIZE)).add("FB_SIZE", UVec2(m_r->getWidth(), m_r->getHeight()));
 
 	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(mutations.m_mutations, consts.m_constantValues, variant);
+	m_prog->getOrCreateVariant(mutations.get(), consts.get(), variant);
 	m_grProgs[0] = variant->getProgram();
 
-	mutations.m_mutations[3].m_value = 1;
-	m_prog->getOrCreateVariant(mutations.m_mutations, consts.m_constantValues, variant);
+	mutations[3].m_value = 1;
+	m_prog->getOrCreateVariant(mutations.get(), consts.get(), variant);
 	m_grProgs[1] = variant->getProgram();
 
 	return ErrorCode::NONE;

+ 3 - 3
src/anki/renderer/Ssao.cpp

@@ -62,7 +62,7 @@ Error SsaoMain::init(const ConfigSet& config)
 		.add("STRENGTH", F32(3.0))
 		.add("HISTORY_FEEDBACK", F32(1.0f / 8.0f));
 	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(consts.m_constantValues, variant);
+	m_prog->getOrCreateVariant(consts.get(), variant);
 	m_grProg = variant->getProgram();
 
 	return ErrorCode::NONE;
@@ -143,7 +143,7 @@ Error SsaoHBlur::init(const ConfigSet& config)
 	consts.add("TEXTURE_SIZE", UVec2(m_ssao->m_width, m_ssao->m_height));
 
 	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(mutators.m_mutations, consts.m_constantValues, variant);
+	m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
 
 	m_grProg = variant->getProgram();
 
@@ -187,7 +187,7 @@ Error SsaoVBlur::init(const ConfigSet& config)
 	consts.add("TEXTURE_SIZE", UVec2(m_ssao->m_width, m_ssao->m_height));
 
 	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(mutators.m_mutations, consts.m_constantValues, variant);
+	m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
 
 	m_grProg = variant->getProgram();
 

+ 1 - 1
src/anki/renderer/Volumetric.cpp

@@ -55,7 +55,7 @@ Error VolumetricMain::init(const ConfigSet& config)
 		.add("NOISE_MAP_SIZE", U32(m_noiseTex->getWidth()));
 
 	const ShaderProgramResourceVariant* variant;
-	m_prog->getOrCreateVariant(mutators.m_mutations, consts.m_constantValues, variant);
+	m_prog->getOrCreateVariant(mutators.get(), consts.get(), variant);
 	m_grProg = variant->getProgram();
 
 	return ErrorCode::NONE;

+ 27 - 4
src/anki/resource/ShaderProgramResource.h

@@ -368,6 +368,14 @@ public:
 		getOrCreateVariant(WeakArray<const ShaderProgramResourceMutation>(), constants, variant);
 	}
 
+	/// Get or create a graphics shader program variant.
+	/// @note It's thread-safe.
+	void getOrCreateVariant(
+		WeakArray<const ShaderProgramResourceMutation> mutations, const ShaderProgramResourceVariant*& variant) const
+	{
+		getOrCreateVariant(mutations, WeakArray<const ShaderProgramResourceConstantValue>(), variant);
+	}
+
 	/// Get or create a graphics shader program variant.
 	/// @note It's thread-safe.
 	void getOrCreateVariant(const ShaderProgramResourceVariant*& variant) const
@@ -427,8 +435,6 @@ template<U count>
 class ShaderProgramResourceConstantValueInitList
 {
 public:
-	Array<ShaderProgramResourceConstantValue, count> m_constantValues;
-
 	ShaderProgramResourceConstantValueInitList(ShaderProgramResourcePtr ptr)
 		: m_ptr(ptr)
 	{
@@ -452,9 +458,16 @@ public:
 		return *this;
 	}
 
+	WeakArray<const ShaderProgramResourceConstantValue> get() const
+	{
+		ANKI_ASSERT(m_count == count);
+		return WeakArray<const ShaderProgramResourceConstantValue>(&m_constantValues[0], m_count);
+	}
+
 private:
 	ShaderProgramResourcePtr m_ptr;
 	U m_count = 0;
+	Array<ShaderProgramResourceConstantValue, count> m_constantValues;
 };
 
 /// Smart initializer of multiple ShaderProgramResourceMutation.
@@ -462,8 +475,6 @@ template<U count>
 class ShaderProgramResourceMutationInitList
 {
 public:
-	Array<ShaderProgramResourceMutation, count> m_mutations;
-
 	ShaderProgramResourceMutationInitList(ShaderProgramResourcePtr ptr)
 		: m_ptr(ptr)
 	{
@@ -484,9 +495,21 @@ public:
 		return *this;
 	}
 
+	WeakArray<const ShaderProgramResourceMutation> get() const
+	{
+		ANKI_ASSERT(m_count == count);
+		return WeakArray<const ShaderProgramResourceMutation>(&m_mutations[0], m_count);
+	}
+
+	ShaderProgramResourceMutation& operator[](U idx)
+	{
+		return m_mutations[idx];
+	}
+
 private:
 	ShaderProgramResourcePtr m_ptr;
 	U m_count = 0;
+	Array<ShaderProgramResourceMutation, count> m_mutations;
 };
 /// @}
 

+ 179 - 0
src/anki/ui/Canvas.cpp

@@ -5,13 +5,22 @@
 
 #include <anki/ui/Canvas.h>
 #include <anki/ui/Font.h>
+#include <anki/ui/UiManager.h>
+#include <anki/resource/ResourceManager.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
 
+Canvas::Canvas(UiManager* manager)
+	: UiObject(manager)
+{
+}
+
 Canvas::~Canvas()
 {
 	nk_free(&m_nkCtx);
+	nk_buffer_free(&m_nkCmdsBuff);
 }
 
 Error Canvas::init(FontPtr font)
@@ -25,7 +34,177 @@ Error Canvas::init(FontPtr font)
 		return ErrorCode::FUNCTION_FAILED;
 	}
 
+	nk_buffer_init(&m_nkCmdsBuff, &alloc, 1_KB);
+
+	// Create program
+	ANKI_CHECK(m_manager->getResourceManager().loadResource("programs/Ui.ankiprog", m_prog));
+	const ShaderProgramResourceVariant* variant;
+
+	{
+		ShaderProgramResourceMutationInitList<1> mutators(m_prog);
+		mutators.add("IDENTITY_TEX", 0);
+		m_prog->getOrCreateVariant(mutators.get(), variant);
+		m_texGrProg = variant->getProgram();
+	}
+
+	{
+		ShaderProgramResourceMutationInitList<1> mutators(m_prog);
+		mutators.add("IDENTITY_TEX", 1);
+		m_prog->getOrCreateVariant(mutators.get(), variant);
+		m_whiteTexGrProg = variant->getProgram();
+	}
+
 	return ErrorCode::NONE;
 }
 
+void Canvas::handleInput()
+{
+	// TODO
+}
+
+void Canvas::beginBuilding()
+{
+#if ANKI_EXTRA_CHECKS
+	ANKI_ASSERT(!m_building);
+	m_building = true;
+#endif
+}
+
+void Canvas::endBuilding()
+{
+#if ANKI_EXTRA_CHECKS
+	ANKI_ASSERT(m_building);
+	m_building = false;
+#endif
+}
+
+void Canvas::appendToCommandBuffer(CommandBufferPtr cmdb)
+{
+	//
+	// Allocate vertex data
+	//
+	struct Vert
+	{
+		Vec2 m_pos;
+		Vec2 m_uv;
+		Array<U8, 4> m_col;
+	};
+
+	static const struct nk_draw_vertex_layout_element VERT_LAYOUT[] = {
+		{NK_VERTEX_POSITION, NK_FORMAT_FLOAT, NK_OFFSETOF(Vert, m_pos)},
+		{NK_VERTEX_TEXCOORD, NK_FORMAT_FLOAT, NK_OFFSETOF(Vert, m_uv)},
+		{NK_VERTEX_COLOR, NK_FORMAT_R8G8B8A8, NK_OFFSETOF(Vert, m_col)},
+		{NK_VERTEX_LAYOUT_END}};
+
+	struct GpuAllocCtx
+	{
+		StagingGpuMemoryManager* m_alloc;
+		StagingGpuMemoryToken m_token;
+	};
+
+	auto allocVertDataCallback = [](nk_handle handle, void* old, nk_size size) -> void* {
+		GpuAllocCtx* ctx = static_cast<GpuAllocCtx*>(handle.ptr);
+		void* out = ctx->m_alloc->allocateFrame(size, StagingGpuMemoryType::VERTEX, ctx->m_token);
+		ANKI_ASSERT(out);
+		return out;
+	};
+
+	auto freeVertDataCallback = [](nk_handle, void*) -> void {
+		// Do nothing
+	};
+
+	GpuAllocCtx idxCtx;
+	idxCtx.m_alloc = &m_manager->getStagingGpuMemoryManager();
+	nk_allocator idxAlloc;
+	idxAlloc.userdata.ptr = &idxCtx;
+	idxAlloc.alloc = allocVertDataCallback;
+	idxAlloc.free = freeVertDataCallback;
+
+	nk_buffer idxBuff = {};
+	nk_buffer_init(&idxBuff, &idxAlloc, 1_KB);
+
+	GpuAllocCtx vertCtx;
+	vertCtx.m_alloc = &m_manager->getStagingGpuMemoryManager();
+	nk_allocator vertAlloc;
+	vertAlloc.userdata.ptr = &vertCtx;
+	vertAlloc.alloc = allocVertDataCallback;
+	vertAlloc.free = freeVertDataCallback;
+
+	nk_buffer vertBuff = {};
+	nk_buffer_init(&vertBuff, &vertAlloc, 1_KB);
+
+	nk_convert_config config = {};
+	config.vertex_layout = VERT_LAYOUT;
+	config.vertex_size = sizeof(Vert);
+	config.vertex_alignment = NK_ALIGNOF(Vert);
+	config.null.texture.ptr = nullptr;
+	config.null.uv = {0, 0};
+	config.circle_segment_count = 22;
+	config.curve_segment_count = 22;
+	config.arc_segment_count = 22;
+	config.global_alpha = 1.0f;
+	config.shape_AA = NK_ANTI_ALIASING_ON;
+	config.line_AA = NK_ANTI_ALIASING_ON;
+
+	nk_convert(&m_nkCtx, &m_nkCmdsBuff, &vertBuff, &idxBuff, &config);
+
+	//
+	// Draw
+	//
+	cmdb->bindVertexBuffer(0, vertCtx.m_token.m_buffer, vertCtx.m_token.m_offset, sizeof(Vert));
+	cmdb->setVertexAttribute(0, 0, PixelFormat(ComponentFormat::R32G32, TransformFormat::FLOAT), 0);
+	cmdb->setVertexAttribute(1, 0, PixelFormat(ComponentFormat::R32G32, TransformFormat::FLOAT), sizeof(Vec2));
+	cmdb->setVertexAttribute(2, 0, PixelFormat(ComponentFormat::R8G8B8A8, TransformFormat::UNORM), sizeof(Vec2) * 2);
+
+	cmdb->bindIndexBuffer(idxCtx.m_token.m_buffer, idxCtx.m_token.m_offset, IndexType::U16);
+
+	cmdb->setViewport(0, 0, 1024, 1024); // TODO
+
+	cmdb->bindShaderProgram(m_texGrProg);
+	ShaderProgramPtr boundProg = m_texGrProg;
+	cmdb->setBlendFactors(0, BlendFactor::SRC_ALPHA, BlendFactor::ONE_MINUS_SRC_ALPHA);
+
+	const nk_draw_command* cmd = nullptr;
+	U offset = 0;
+	nk_draw_foreach(cmd, &m_nkCtx, &m_nkCmdsBuff)
+	{
+		if(!cmd->elem_count)
+		{
+			continue;
+		}
+
+		// Set texture and program
+		ShaderProgramPtr progToBind;
+		switch(cmd->texture.id)
+		{
+		case 0:
+			progToBind = m_whiteTexGrProg;
+			break;
+		case FONT_TEXTURE_INDEX:
+			progToBind = m_texGrProg;
+			cmdb->bindTexture(0, 0, m_font->getTexture());
+			break;
+		}
+
+		if(boundProg != progToBind)
+		{
+			cmdb->bindShaderProgram(progToBind);
+			boundProg = progToBind;
+		}
+
+		// TODO set scissor
+
+		// Draw
+		cmdb->drawElements(PrimitiveTopology::TRIANGLES, cmd->elem_count, 1, offset);
+
+		// Advance
+		offset += cmd->elem_count;
+	}
+
+	//
+	// Done
+	//
+	nk_clear(&m_nkCtx);
+}
+
 } // end namespace anki

+ 15 - 5
src/anki/ui/Canvas.h

@@ -6,6 +6,8 @@
 #pragma once
 
 #include <anki/ui/UiObject.h>
+#include <anki/gr/CommandBuffer.h>
+#include <anki/resource/ShaderProgramResource.h>
 
 namespace anki
 {
@@ -17,12 +19,9 @@ namespace anki
 class Canvas : public UiObject
 {
 public:
-	Canvas(UiManager* manager)
-		: UiObject(manager)
-	{
-	}
+	Canvas(UiManager* manager);
 
-	~Canvas();
+	virtual ~Canvas();
 
 	ANKI_USE_RESULT Error init(FontPtr font);
 
@@ -40,9 +39,20 @@ public:
 	/// End building.
 	void endBuilding();
 
+	void appendToCommandBuffer(CommandBufferPtr cmdb);
+
 private:
 	FontPtr m_font;
 	nk_context m_nkCtx = {};
+	nk_buffer m_nkCmdsBuff = {};
+
+	ShaderProgramResourcePtr m_prog;
+	ShaderProgramPtr m_texGrProg;
+	ShaderProgramPtr m_whiteTexGrProg;
+
+#if ANKI_EXTRA_CHECKS
+	Bool8 m_building = false;
+#endif
 };
 /// @}
 

+ 1 - 1
src/anki/ui/NuklearConfig.h

@@ -9,7 +9,7 @@
 
 #define NK_INCLUDE_FIXED_TYPES
 #define NK_INCLUDE_STANDARD_VARARGS
-// #define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
+#define NK_INCLUDE_VERTEX_BUFFER_OUTPUT
 #define NK_INCLUDE_FONT_BAKING
 // #define NK_INCLUDE_DEFAULT_FONT
 // #define NK_INCLUDE_COMMAND_USERDATA

+ 15 - 1
src/anki/ui/UiImmediateModeBuilder.h

@@ -5,7 +5,7 @@
 
 #pragma once
 
-#include <anki/ui/Common.h>
+#include <anki/ui/UiObject.h>
 
 namespace anki
 {
@@ -17,7 +17,21 @@ namespace anki
 class UiImmediateModeBuilder : public UiObject
 {
 public:
+	UiImmediateModeBuilder(UiManager* manager)
+		: UiObject(manager)
+	{
+	}
+
+	virtual ~UiImmediateModeBuilder()
+	{
+	}
+
 	virtual void build(CanvasPtr ctx) = 0;
+
+	ANKI_USE_RESULT Error init() const
+	{
+		return ErrorCode::NONE;
+	}
 };
 /// @}
 

+ 5 - 2
src/anki/ui/UiManager.cpp

@@ -16,16 +16,19 @@ UiManager::~UiManager()
 {
 }
 
-Error UiManager::init(HeapAllocator<U8> alloc, ResourceManager* resources, GrManager* gr)
+Error UiManager::init(
+	HeapAllocator<U8> alloc, ResourceManager* resources, GrManager* gr, StagingGpuMemoryManager* gpuMem)
 {
 	ANKI_ASSERT(resources);
 	ANKI_ASSERT(gr);
+	ANKI_ASSERT(gpuMem);
 
 	m_alloc = alloc;
 	m_resources = resources;
 	m_gr = gr;
+	m_gpuMem = gpuMem;
 
 	return ErrorCode::NONE;
 }
 
-} // end namespace anki
+} // end namespace anki

+ 12 - 1
src/anki/ui/UiManager.h

@@ -13,6 +13,7 @@ namespace anki
 // Forward
 class ResourceManager;
 class GrManager;
+class StagingGpuMemoryManager;
 
 /// @addtogroup ui
 /// @{
@@ -25,7 +26,8 @@ public:
 
 	~UiManager();
 
-	ANKI_USE_RESULT Error init(HeapAllocator<U8> alloc, ResourceManager* resources, GrManager* gr);
+	ANKI_USE_RESULT Error init(
+		HeapAllocator<U8> alloc, ResourceManager* resources, GrManager* gr, StagingGpuMemoryManager* gpuMem);
 
 	UiAllocator getAllocator() const
 	{
@@ -34,14 +36,22 @@ public:
 
 	ResourceManager& getResourceManager()
 	{
+		ANKI_ASSERT(m_resources);
 		return *m_resources;
 	}
 
 	GrManager& getGrManager()
 	{
+		ANKI_ASSERT(m_gr);
 		return *m_gr;
 	}
 
+	StagingGpuMemoryManager& getStagingGpuMemoryManager()
+	{
+		ANKI_ASSERT(m_gpuMem);
+		return *m_gpuMem;
+	}
+
 	/// Create a new UI object.
 	template<typename T, typename... Args>
 	ANKI_USE_RESULT Error newInstance(IntrusivePtr<T>& ptr, Args&&... args)
@@ -54,6 +64,7 @@ private:
 	UiAllocator m_alloc;
 	ResourceManager* m_resources = nullptr;
 	GrManager* m_gr = nullptr;
+	StagingGpuMemoryManager* m_gpuMem = nullptr;
 };
 /// @}
 

+ 1 - 1
tests/framework/Framework.cpp

@@ -227,7 +227,7 @@ void initConfig(Config& cfg)
 {
 	cfg.set("width", 1920);
 	cfg.set("height", 1080);
-	cfg.set("rsrc.dataPaths", ".:../engine_data");
+	cfg.set("rsrc.dataPaths", ".:..");
 }
 
 NativeWindow* createWindow(const Config& cfg)

+ 26 - 4
tests/ui/Ui.cpp

@@ -7,6 +7,7 @@
 #include <anki/core/Config.h>
 #include <anki/util/HighRezTimer.h>
 #include <anki/Ui.h>
+#include <anki/core/StagingGpuMemoryManager.h>
 
 namespace anki
 {
@@ -23,10 +24,14 @@ static FramebufferPtr createDefaultFb(GrManager& gr)
 class Label : public UiImmediateModeBuilder
 {
 public:
-	void build(CanvasPtr canvas)
+	using UiImmediateModeBuilder::UiImmediateModeBuilder;
+
+	void build(CanvasPtr canvas) final
 	{
 		nk_context* ctx = &canvas->getContext();
-		// TODO
+		nk_begin(ctx, "Window", nk_rect(10, 10, 200, 800), NK_WINDOW_NO_SCROLLBAR);
+
+		nk_end(ctx);
 	}
 };
 
@@ -35,6 +40,7 @@ ANKI_TEST(Ui, Ui)
 	Config cfg;
 	initConfig(cfg);
 	cfg.set("vsync", 1);
+	cfg.set("debugContext", 1);
 
 	NativeWindow* win = createWindow(cfg);
 	GrManager* gr = createGrManager(cfg, win);
@@ -43,12 +49,21 @@ ANKI_TEST(Ui, Ui)
 	ResourceManager* resource = createResourceManager(cfg, gr, physics, fs);
 	UiManager* ui = new UiManager();
 
+	StagingGpuMemoryManager* stagingMem = new StagingGpuMemoryManager();
+	ANKI_TEST_EXPECT_NO_ERR(stagingMem->init(gr, cfg));
+
 	HeapAllocator<U8> alloc(allocAligned, nullptr);
-	ANKI_TEST_EXPECT_NO_ERR(ui->init(alloc, resource, gr));
+	ANKI_TEST_EXPECT_NO_ERR(ui->init(alloc, resource, gr, stagingMem));
 
 	{
 		FontPtr font;
-		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(font, "UbuntuRegular.ttf", 30));
+		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(font, "engine_data/UbuntuRegular.ttf", 30));
+
+		CanvasPtr canvas;
+		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(canvas, font));
+
+		IntrusivePtr<Label> label;
+		ANKI_TEST_EXPECT_NO_ERR(ui->newInstance(label));
 
 		FramebufferPtr fb = createDefaultFb(*gr);
 
@@ -58,6 +73,10 @@ ANKI_TEST(Ui, Ui)
 			HighRezTimer timer;
 			timer.start();
 
+			canvas->beginBuilding();
+			label->build(canvas);
+			canvas->endBuilding();
+
 			gr->beginFrame();
 
 			CommandBufferInitInfo cinit;
@@ -65,10 +84,12 @@ ANKI_TEST(Ui, Ui)
 			CommandBufferPtr cmdb = gr->newInstance<CommandBuffer>(cinit);
 
 			cmdb->beginRenderPass(fb);
+			canvas->appendToCommandBuffer(cmdb);
 			cmdb->endRenderPass();
 			cmdb->flush();
 
 			gr->swapBuffers();
+			stagingMem->endFrame();
 
 			timer.stop();
 			const F32 TICK = 1.0 / 30.0;
@@ -80,6 +101,7 @@ ANKI_TEST(Ui, Ui)
 	}
 
 	delete ui;
+	delete stagingMem;
 	delete resource;
 	delete physics;
 	delete fs;