From 85a130cefd1e5b2ef4d19e8bca78963984637816 Mon Sep 17 00:00:00 2001
From: Alexander Gauggel <agauggel@uni-koblenz.de>
Date: Sun, 30 May 2021 17:13:16 +0200
Subject: [PATCH] [#53] Cube now textured, can't think of something funny
 anymore...

---
 config/Sources.cmake                          |   2 +
 include/vkcv/Core.hpp                         |  47 +++++---
 include/vkcv/DescriptorConfig.hpp             |   8 +-
 include/vkcv/DescriptorWrites.hpp             |  43 +++++++
 include/vkcv/Image.hpp                        |   3 +
 include/vkcv/PipelineConfig.hpp               |  22 ++--
 .../first_mesh/resources/shaders/frag.spv     | Bin 652 -> 920 bytes
 .../first_mesh/resources/shaders/shader.frag  |   6 +-
 projects/first_mesh/src/main.cpp              |  48 ++++++--
 projects/first_triangle/src/main.cpp          | 101 ++++++++---------
 src/vkcv/Core.cpp                             |  37 +++++-
 src/vkcv/DescriptorConfig.cpp                 |   2 +-
 src/vkcv/DescriptorManager.cpp                | 106 +++++++++++++++++-
 src/vkcv/DescriptorManager.hpp                |  22 +++-
 src/vkcv/Image.cpp                            |   4 +
 src/vkcv/PipelineConfig.cpp                   |  15 ++-
 src/vkcv/PipelineManager.cpp                  |   2 +-
 17 files changed, 350 insertions(+), 118 deletions(-)
 create mode 100644 include/vkcv/DescriptorWrites.hpp

diff --git a/config/Sources.cmake b/config/Sources.cmake
index e7a36ff1..8fc0aa9a 100644
--- a/config/Sources.cmake
+++ b/config/Sources.cmake
@@ -70,4 +70,6 @@ set(vkcv_sources
 		
 		${vkcv_source}/vkcv/SamplerManager.hpp
 		${vkcv_source}/vkcv/SamplerManager.cpp
+        
+        ${vkcv_include}/vkcv/DescriptorWrites.hpp
 )
diff --git a/include/vkcv/Core.hpp b/include/vkcv/Core.hpp
index 6451d81a..cf75b8e7 100644
--- a/include/vkcv/Core.hpp
+++ b/include/vkcv/Core.hpp
@@ -20,6 +20,7 @@
 #include "Result.hpp"
 #include "vkcv/DescriptorConfig.hpp"
 #include "Sampler.hpp"
+#include "DescriptorWrites.hpp"
 
 namespace vkcv
 {
@@ -64,21 +65,21 @@ namespace vkcv
 
         Context m_Context;
 
-        SwapChain m_swapchain;
-        std::vector<vk::ImageView> m_swapchainImageViews;
-        const Window& m_window;
+        SwapChain					m_swapchain;
+        std::vector<vk::ImageView>	m_swapchainImageViews;
+        const Window&				m_window;
 
-        std::unique_ptr<PassManager> m_PassManager;
-        std::unique_ptr<PipelineManager> m_PipelineManager;
-        std::unique_ptr<DescriptorManager> m_DescriptorManager;
-        std::unique_ptr<BufferManager> m_BufferManager;
-        std::unique_ptr<SamplerManager> m_SamplerManager;
-        std::unique_ptr<ImageManager> m_ImageManager;
+        std::unique_ptr<PassManager>		m_PassManager;
+        std::unique_ptr<PipelineManager>	m_PipelineManager;
+        std::unique_ptr<DescriptorManager>	m_DescriptorManager;
+        std::unique_ptr<BufferManager>		m_BufferManager;
+        std::unique_ptr<SamplerManager>		m_SamplerManager;
+        std::unique_ptr<ImageManager>		m_ImageManager;
 
-		CommandResources m_CommandResources;
-		SyncResources m_SyncResources;
-		uint32_t m_currentSwapchainImageIndex;
-		std::vector<vk::Framebuffer> m_TemporaryFramebuffers;
+		CommandResources				m_CommandResources;
+		SyncResources					m_SyncResources;
+		uint32_t						m_currentSwapchainImageIndex;
+		std::vector<vk::Framebuffer>	m_TemporaryFramebuffers;
 
         /**
          * recreates the swapchain
@@ -212,7 +213,10 @@ namespace vkcv
          *   @return
          */
         [[nodiscard]]
-        ResourcesHandle createResourceDescription(const std::vector<DescriptorSet> &descriptorSets);
+        ResourcesHandle createResourceDescription(const std::vector<DescriptorSetConfig> &descriptorSets);
+		void writeResourceDescription(ResourcesHandle handle, size_t setIndex, const DescriptorWrites& writes);
+
+		vk::DescriptorSetLayout getDescritorSetLayout(ResourcesHandle handle, size_t setIndex);
 
 		/**
 		 * @brief start recording command buffers and increment frame index
@@ -222,9 +226,18 @@ namespace vkcv
 		/**
 		 * @brief render a beautiful triangle
 		*/
-		void renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle,
-			const int width, const int height, const size_t pushConstantSize, const void* pushConstantData, 
-			const std::vector<VertexBufferBinding> & vertexBufferBindings, const BufferHandle indexBuffer, const size_t indexCount);
+		void renderMesh(
+			const PassHandle						renderpassHandle, 
+			const PipelineHandle					pipelineHandle,
+			const int								width, 
+			const int								height, 
+			const size_t							pushConstantSize, 
+			const void*								pushConstantData, 
+			const std::vector<VertexBufferBinding>	&vertexBufferBindings, 
+			const BufferHandle						indexBuffer, 
+			const size_t							indexCount,
+			const vkcv::ResourcesHandle				resourceHandle,
+			const size_t							resourceDescriptorSetIndex);
 
 		/**
 		 * @brief end recording and present image
diff --git a/include/vkcv/DescriptorConfig.hpp b/include/vkcv/DescriptorConfig.hpp
index 81162597..161273db 100644
--- a/include/vkcv/DescriptorConfig.hpp
+++ b/include/vkcv/DescriptorConfig.hpp
@@ -11,7 +11,8 @@ namespace vkcv
         UNIFORM_BUFFER,
         STORAGE_BUFFER,
         SAMPLER,
-        IMAGE
+        IMAGE_SAMPLED,
+		IMAGE_STORAGE
     };    
     
     /*
@@ -40,10 +41,9 @@ namespace vkcv
     * @param[in] a number of bindings that were created beforehand
     * @param[in] the number of (identical) sets that should be created from the attached bindings
     */
-    struct DescriptorSet
+    struct DescriptorSetConfig
     {
-        DescriptorSet() = delete;
-        explicit DescriptorSet(std::vector<DescriptorBinding> bindings) noexcept;
+        explicit DescriptorSetConfig(std::vector<DescriptorBinding> bindings) noexcept;
 
         std::vector<DescriptorBinding> bindings;
     };
diff --git a/include/vkcv/DescriptorWrites.hpp b/include/vkcv/DescriptorWrites.hpp
new file mode 100644
index 00000000..d67e8e32
--- /dev/null
+++ b/include/vkcv/DescriptorWrites.hpp
@@ -0,0 +1,43 @@
+#pragma once
+#include "Handles.hpp"
+#include <vector>
+
+namespace vkcv {
+	struct SampledImageDescriptorWrite {
+		inline SampledImageDescriptorWrite(uint32_t binding, ImageHandle image) : binding(binding), image(image) {};
+		uint32_t	binding;
+		ImageHandle	image;
+	};
+
+	struct StorageImageDescriptorWrite {
+		inline StorageImageDescriptorWrite(uint32_t binding, ImageHandle image) : binding(binding), image(image) {};
+		uint32_t	binding;
+		ImageHandle	image;
+	};
+
+	struct UniformBufferDescriptorWrite {
+		inline UniformBufferDescriptorWrite(uint32_t binding, BufferHandle buffer) : binding(binding), buffer(buffer) {};
+		uint32_t		binding;
+		BufferHandle	buffer;
+	};
+
+	struct StorageBufferDescriptorWrite {
+		inline StorageBufferDescriptorWrite(uint32_t binding, BufferHandle buffer) : binding(binding), buffer(buffer) {};
+		uint32_t		binding;
+		BufferHandle	buffer;
+	};
+
+	struct SamplerDescriptorWrite {
+		inline SamplerDescriptorWrite(uint32_t binding, SamplerHandle sampler) : binding(binding), sampler(sampler) {};
+		uint32_t		binding;
+		SamplerHandle	sampler;
+	};
+
+	struct DescriptorWrites {
+		std::vector<SampledImageDescriptorWrite>		sampledImageWrites;
+		std::vector<StorageImageDescriptorWrite>		storageImageWrites;
+		std::vector<UniformBufferDescriptorWrite>	uniformBufferWrites;
+		std::vector<StorageBufferDescriptorWrite>	storageBufferWrites;
+		std::vector<SamplerDescriptorWrite>			samplerWrites;
+	};
+}
\ No newline at end of file
diff --git a/include/vkcv/Image.hpp b/include/vkcv/Image.hpp
index 5050513b..d56fac9c 100644
--- a/include/vkcv/Image.hpp
+++ b/include/vkcv/Image.hpp
@@ -28,6 +28,9 @@ namespace vkcv {
 		
 		[[nodiscard]]
 		vk::ImageLayout getLayout() const;
+
+		[[nodiscard]]
+		vkcv::ImageHandle getHandle() const;
 		
 		void switchLayout(vk::ImageLayout newLayout);
 		
diff --git a/include/vkcv/PipelineConfig.hpp b/include/vkcv/PipelineConfig.hpp
index fdf5df74..a8e1334f 100644
--- a/include/vkcv/PipelineConfig.hpp
+++ b/include/vkcv/PipelineConfig.hpp
@@ -24,17 +24,19 @@ namespace vkcv {
          * @param passHandle handle for Render Pass
          */
         PipelineConfig(
-			const ShaderProgram&				shaderProgram, 
-			uint32_t							width, 
-			uint32_t							height, 
-			PassHandle							&passHandle,
-			const std::vector<VertexAttribute>	&vertexAttributes);
+			const ShaderProgram&						shaderProgram, 
+			uint32_t									width, 
+			uint32_t									height, 
+			PassHandle									&passHandle,
+			const std::vector<VertexAttribute>			&vertexAttributes,
+			const std::vector<vk::DescriptorSetLayout>	&descriptorLayouts);
 
-		ShaderProgram					m_ShaderProgram;
-        uint32_t						m_Height;
-        uint32_t						m_Width;
-        PassHandle						m_PassHandle;
-		std::vector<VertexAttribute>	m_vertexAttributes;
+		ShaderProgram							m_ShaderProgram;
+        uint32_t								m_Height;
+        uint32_t								m_Width;
+        PassHandle								m_PassHandle;
+		std::vector<VertexAttribute>			m_vertexAttributes;
+		std::vector<vk::DescriptorSetLayout>	m_descriptorLayouts;
     };
 
 }
\ No newline at end of file
diff --git a/projects/first_mesh/resources/shaders/frag.spv b/projects/first_mesh/resources/shaders/frag.spv
index 50030afba4d1c527a1f9bc59e16cf50a50f72f94..087e4e22fb2fcec27d99b3ff2aa1a705fe755796 100644
GIT binary patch
literal 920
zcmYk4UrQTN5XDF1rZHAitHzqN#Xs+%4{a%kf{N@*XrO7+$7P#b$jT<W>~2c?_54)6
z2tB_|LifTj_spC-b7ppHn-?$4Hmqs8_Rf}P-!>I7+p&7-{r<4u%Zo|x<EIZW_N-PC
z;k2w_Tk_Z}jOHY^Wo_A8*(-6$sflhiRW^In!!5D=esJ^cHppEXW?|uid>T$%79_tO
z+_=c$G~xJzf#1Im#%UVl#oyQkaWr?qB+A5!emi)L3NM<E<He*(@WiO<^UNzXCX3=O
ziIYr{6!Gk({LJOk@9s~r$ebc|={GBuco@#o*ojR&=1apo|1ny=WmfRlB%6h?nJ*4|
zcrW9CsefLg|M;we=~c~x$+KtP)028@OwV=w18tVwo|Rj+^4`|HuGp#USnv4;V7}g|
zaAS2Re!0SECVwLJO?mkAtDZHc#?C4Mml|N^<aDHBPaa;YjPUO)d0^(_bk*^-JT=gH
zC{JJJ;q8$;J&Dr;%r1z*e<Kf{Zw$XHPi{RIm|YS3tglC1xEyAEQpA(LQWOolGG+jy
ycVC9qkyz+Fkij7i2VKW9H2o9@Jts1F#0T0mS~@b~7zaIQxt0p{PX1ZZFS38`7*62;

delta 299
zcmYk1O$x#=6oe<OwOEaR72Jv7!i5(Q1YJrIL=XiRg54{MJ%M`>N;lraGk6#eAvhxy
z3=GLPZ{ACC_phFHot_UE1h8nOcIH(8gz5GXo#G^!AJ2z)4|pgbWI^6)4NS=;a);6q
ztMQ+e7n|&9mYV?+MN&X<O}gYV4~F6cFv?j|<h98S?&@(U<(u49ldrru%wA4^rwNu)
k_l>U=S94D{E;vVCjS~NK$+LBO%Bwzx`~91|H}4x#AKFP4JOBUy

diff --git a/projects/first_mesh/resources/shaders/shader.frag b/projects/first_mesh/resources/shaders/shader.frag
index ce1efbde..71a1de69 100644
--- a/projects/first_mesh/resources/shaders/shader.frag
+++ b/projects/first_mesh/resources/shaders/shader.frag
@@ -6,7 +6,9 @@ layout(location = 1) in vec2 passUV;
 
 layout(location = 0) out vec3 outColor;
 
+layout(set=0, binding=0) uniform texture2D  meshTexture;
+layout(set=0, binding=1) uniform sampler    textureSampler;
+
 void main()	{
-	outColor = 0.5 * passNormal + 0.5;
-    //outColor = vec3(abs(passUV), 0);
+	outColor = texture(sampler2D(meshTexture, textureSampler), passUV).rgb;
 }
\ No newline at end of file
diff --git a/projects/first_mesh/src/main.cpp b/projects/first_mesh/src/main.cpp
index fbd32539..107cd432 100644
--- a/projects/first_mesh/src/main.cpp
+++ b/projects/first_mesh/src/main.cpp
@@ -5,7 +5,6 @@
 #include <chrono>
 #include <vkcv/asset/asset_loader.hpp>
 
-
 int main(int argc, const char** argv) {
 	const char* applicationName = "First Mesh";
 
@@ -100,7 +99,19 @@ int main(int argc, const char** argv) {
 		return static_cast<uint32_t>(x.type) < static_cast<uint32_t>(y.type);
 	});
 
-	const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass, mesh.vertexGroups[0].vertexBuffer.attributes);
+	vkcv::DescriptorSetConfig setConfig({
+		vkcv::DescriptorBinding(vkcv::DescriptorType::IMAGE_SAMPLED,	1, vkcv::ShaderStage::FRAGMENT),
+		vkcv::DescriptorBinding(vkcv::DescriptorType::SAMPLER,			1, vkcv::ShaderStage::FRAGMENT)
+	});
+	vkcv::ResourcesHandle set = core.createResourceDescription({ setConfig });
+
+	const vkcv::PipelineConfig trianglePipelineDefinition(
+		triangleShaderProgram, 
+		windowWidth,
+		windowHeight,
+		trianglePass,
+		mesh.vertexGroups[0].vertexBuffer.attributes,
+		{ core.getDescritorSetLayout(set, 0) });
 	vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition);
 	
 	if (!trianglePipeline) {
@@ -109,15 +120,26 @@ int main(int argc, const char** argv) {
 	}
 	
 	vkcv::Image texture = core.createImage(vk::Format::eR8G8B8A8Srgb, mesh.texture_hack.w, mesh.texture_hack.h);
-	
 	texture.fill(mesh.texture_hack.img);
 
+	vkcv::SamplerHandle sampler = core.createSampler(
+		vkcv::SamplerFilterType::LINEAR,
+		vkcv::SamplerFilterType::LINEAR,
+		vkcv::SamplerMipmapMode::LINEAR,
+		vkcv::SamplerAddressMode::REPEAT
+	);
+
 	std::vector<vkcv::VertexBufferBinding> vertexBufferBindings = {
 		{ mesh.vertexGroups[0].vertexBuffer.attributes[0].offset, vertexBuffer.getHandle() },
 		{ mesh.vertexGroups[0].vertexBuffer.attributes[1].offset, vertexBuffer.getHandle() },
 		{ mesh.vertexGroups[0].vertexBuffer.attributes[2].offset, vertexBuffer.getHandle() }
 	};
 
+	vkcv::DescriptorWrites setWrites;
+	setWrites.sampledImageWrites	= { vkcv::SampledImageDescriptorWrite(0, texture.getHandle()) };
+	setWrites.samplerWrites			= { vkcv::SamplerDescriptorWrite(1, sampler) };
+	core.writeResourceDescription(set, 0, setWrites);
+
 	auto start = std::chrono::system_clock::now();
 	while (window.isWindowOpen()) {
 		core.beginFrame();
@@ -129,15 +151,17 @@ int main(int argc, const char** argv) {
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
 		core.renderMesh(
-				trianglePass,
-				trianglePipeline,
-				windowWidth,
-				windowHeight,
-				sizeof(mvp),
-				&mvp,
-				vertexBufferBindings,
-				indexBuffer.getHandle(),
-				mesh.vertexGroups[0].numIndices
+			trianglePass,
+			trianglePipeline,
+			windowWidth,
+			windowHeight,
+			sizeof(mvp),
+			&mvp,
+			vertexBufferBindings,
+			indexBuffer.getHandle(),
+			mesh.vertexGroups[0].numIndices,
+			set,
+			0
 		);
 
 		core.endFrame();
diff --git a/projects/first_triangle/src/main.cpp b/projects/first_triangle/src/main.cpp
index d51d60e4..2c071b72 100644
--- a/projects/first_triangle/src/main.cpp
+++ b/projects/first_triangle/src/main.cpp
@@ -5,41 +5,41 @@
 #include <chrono>
 
 int main(int argc, const char** argv) {
-    const char* applicationName = "First Triangle";
+	const char* applicationName = "First Triangle";
 
 	const int windowWidth = 800;
 	const int windowHeight = 600;
-    vkcv::Window window = vkcv::Window::create(
+	vkcv::Window window = vkcv::Window::create(
 		applicationName,
 		windowWidth,
 		windowHeight,
 		false
-    );
+	);
 
-    vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
+	vkcv::CameraManager cameraManager(window, windowWidth, windowHeight);
 
-    window.initEvents();
+	window.initEvents();
 
 	vkcv::Core core = vkcv::Core::create(
-            window,
-            applicationName,
+		window,
+		applicationName,
 		VK_MAKE_VERSION(0, 0, 1),
-            {vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute},
+		{ vk::QueueFlagBits::eTransfer,vk::QueueFlagBits::eGraphics, vk::QueueFlagBits::eCompute },
 		{},
-		{"VK_KHR_swapchain"}
+		{ "VK_KHR_swapchain" }
 	);
 
-	const auto &context = core.getContext();
+	const auto& context = core.getContext();
 	const vk::Instance& instance = context.getInstance();
 	const vk::PhysicalDevice& physicalDevice = context.getPhysicalDevice();
 	const vk::Device& device = context.getDevice();
-	
+
 	struct vec3 {
 		float x, y, z;
 	};
-	
+
 	const size_t n = 5027;
-	
+
 	auto testBuffer = core.createBuffer<vec3>(vkcv::BufferType::VERTEX, n, vkcv::BufferMemoryType::DEVICE_LOCAL);
 	vec3 vec_data[n];
 
@@ -58,26 +58,26 @@ int main(int argc, const char** argv) {
 	m[1] = { 0, 0, 0 };
 	m[2] = { 0, 0, 0 };
 	buffer.unmap();*/
-	
+
 	vkcv::SamplerHandle sampler = core.createSampler(
-			vkcv::SamplerFilterType::NEAREST,
-			vkcv::SamplerFilterType::NEAREST,
-			vkcv::SamplerMipmapMode::NEAREST,
-			vkcv::SamplerAddressMode::REPEAT
+		vkcv::SamplerFilterType::NEAREST,
+		vkcv::SamplerFilterType::NEAREST,
+		vkcv::SamplerMipmapMode::NEAREST,
+		vkcv::SamplerAddressMode::REPEAT
 	);
 
 	std::cout << "Physical device: " << physicalDevice.getProperties().deviceName << std::endl;
 
 	switch (physicalDevice.getProperties().vendorID) {
-		case 0x1002: std::cout << "Running AMD huh? You like underdogs, are you a Linux user?" << std::endl; break;
-		case 0x10DE: std::cout << "An NVidia GPU, how predictable..." << std::endl; break;
-		case 0x8086: std::cout << "Poor child, running on an Intel GPU, probably integrated..."
-			"or perhaps you are from the future with a dedicated one?" << std::endl; break;
-		case 0x13B5: std::cout << "ARM? What the hell are you running on, next thing I know you're trying to run Vulkan on a leg..." << std::endl; break;
-		default: std::cout << "Unknown GPU vendor?! Either you're on an exotic system or your driver is broken..." << std::endl;
+	case 0x1002: std::cout << "Running AMD huh? You like underdogs, are you a Linux user?" << std::endl; break;
+	case 0x10DE: std::cout << "An NVidia GPU, how predictable..." << std::endl; break;
+	case 0x8086: std::cout << "Poor child, running on an Intel GPU, probably integrated..."
+		"or perhaps you are from the future with a dedicated one?" << std::endl; break;
+	case 0x13B5: std::cout << "ARM? What the hell are you running on, next thing I know you're trying to run Vulkan on a leg..." << std::endl; break;
+	default: std::cout << "Unknown GPU vendor?! Either you're on an exotic system or your driver is broken..." << std::endl;
 	}
 
-    // an example attachment for passes that output to the window
+	// an example attachment for passes that output to the window
 	const vkcv::AttachmentDescription present_color_attachment(
 		vkcv::AttachmentLayout::UNDEFINED,
 		vkcv::AttachmentLayout::COLOR_ATTACHMENT,
@@ -86,7 +86,7 @@ int main(int argc, const char** argv) {
 		vkcv::AttachmentOperation::CLEAR,
 		core.getSwapchainImageFormat());
 
-	vkcv::PassConfig trianglePassDefinition({present_color_attachment});
+	vkcv::PassConfig trianglePassDefinition({ present_color_attachment });
 	vkcv::PassHandle trianglePass = core.createPass(trianglePassDefinition);
 
 	if (!trianglePass)
@@ -99,9 +99,15 @@ int main(int argc, const char** argv) {
 	triangleShaderProgram.addShader(vkcv::ShaderStage::VERTEX, std::filesystem::path("shaders/vert.spv"));
 	triangleShaderProgram.addShader(vkcv::ShaderStage::FRAGMENT, std::filesystem::path("shaders/frag.spv"));
 	triangleShaderProgram.reflectShader(vkcv::ShaderStage::VERTEX);
-    triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT);
+	triangleShaderProgram.reflectShader(vkcv::ShaderStage::FRAGMENT);
 
-	const vkcv::PipelineConfig trianglePipelineDefinition(triangleShaderProgram, windowWidth, windowHeight, trianglePass, {});
+	const vkcv::PipelineConfig trianglePipelineDefinition(
+		triangleShaderProgram,
+		windowWidth,
+		windowHeight,
+		trianglePass,
+		{},
+		{});
 	vkcv::PipelineHandle trianglePipeline = core.createGraphicsPipeline(trianglePipelineDefinition);
 	
 	if (!trianglePipeline)
@@ -110,24 +116,6 @@ int main(int argc, const char** argv) {
 		return EXIT_FAILURE;
 	}
 
-	//just an example
-	//creates 20 descriptor sets, each containing bindings for 50 uniform buffers, images, and samplers
-	std::vector<vkcv::DescriptorSet> sets;
-
-	for (uint32_t i = 0; i < 20; i++)
-	{
-		vkcv::DescriptorBinding uniformBufBinding(vkcv::DescriptorType::UNIFORM_BUFFER, 50, vkcv::ShaderStage::VERTEX);
-        vkcv::DescriptorBinding storageBufBinding(vkcv::DescriptorType::STORAGE_BUFFER, 50, vkcv::ShaderStage::VERTEX);
-        vkcv::DescriptorBinding imageBinding(vkcv::DescriptorType::IMAGE, 50, vkcv::ShaderStage::VERTEX);
-        vkcv::DescriptorBinding samplerBinding(vkcv::DescriptorType::SAMPLER, 50, vkcv::ShaderStage::VERTEX);
-
-        vkcv::DescriptorSet set({uniformBufBinding, storageBufBinding, imageBinding, samplerBinding});
-
-		sets.push_back(set);
-        auto resourceHandle = core.createResourceDescription(sets);
-        std::cout << "Resource " << resourceHandle << " created." << std::endl;
-	}
-	
 	std::vector<vkcv::VertexBufferBinding> vertexBufferBindings;
 
 	/*
@@ -157,16 +145,17 @@ int main(int argc, const char** argv) {
 		const glm::mat4 mvp = cameraManager.getCamera().getProjection() * cameraManager.getCamera().getView();
 
 	    core.renderMesh(
-	    		trianglePass,
-	    		trianglePipeline,
-	    		windowWidth,
-	    		windowHeight,
-	    		sizeof(mvp),
-	    		&mvp,
-	    		vertexBufferBindings,
-	    		triangleIndexBuffer.getHandle(),
-	    		3
-		);
+			trianglePass,
+			trianglePipeline,
+			windowWidth,
+			windowHeight,
+			sizeof(mvp),
+			&mvp,
+			vertexBufferBindings,
+			triangleIndexBuffer.getHandle(),
+			3,
+			vkcv::ResourcesHandle(),
+			0);
 	    
 	    core.endFrame();
 	}
diff --git a/src/vkcv/Core.cpp b/src/vkcv/Core.cpp
index d8a67ebd..0b0d3a24 100644
--- a/src/vkcv/Core.cpp
+++ b/src/vkcv/Core.cpp
@@ -173,9 +173,19 @@ namespace vkcv
 		return device.createFramebuffer(createInfo);
 	}
 
-	void Core::renderMesh(const PassHandle renderpassHandle, const PipelineHandle pipelineHandle, 
-		const int width, const int height, const size_t pushConstantSize, const void *pushConstantData,
-		const std::vector<VertexBufferBinding>& vertexBufferBindings, const BufferHandle indexBuffer, const size_t indexCount) {
+	void Core::renderMesh(
+		const PassHandle						renderpassHandle, 
+		const PipelineHandle					pipelineHandle, 
+		const int								width, 
+		const int								height, 
+		const size_t							pushConstantSize, 
+		const void								*pushConstantData,
+		const std::vector<VertexBufferBinding>& vertexBufferBindings, 
+		const BufferHandle						indexBuffer, 
+		const size_t							indexCount,
+		const vkcv::ResourcesHandle				resourceHandle,
+		const size_t							resourceDescriptorSetIndex
+		) {
 
 		if (m_currentSwapchainImageIndex == std::numeric_limits<uint32_t>::max()) {
 			return;
@@ -254,6 +264,11 @@ namespace vkcv
 				cmdBuffer.bindVertexBuffers(i, (vertexBuffer), (vertexBinding.offset));
 			}
 			
+			if (resourceHandle) {
+				const vk::DescriptorSet descriptorSet = m_DescriptorManager->getDescriptorSet(resourceHandle, resourceDescriptorSetIndex);
+				cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, descriptorSet, nullptr);
+			}
+			
 			cmdBuffer.bindIndexBuffer(vulkanIndexBuffer, 0, vk::IndexType::eUint16);	//FIXME: choose proper size
 			cmdBuffer.pushConstants(pipelineLayout, vk::ShaderStageFlagBits::eAll, 0, pushConstantSize, pushConstantData);
 			cmdBuffer.drawIndexed(indexCount, 1, 0, 0, {});
@@ -332,8 +347,22 @@ namespace vkcv
     	return Image::create(m_ImageManager.get(), format, width, height, depth);
 	}
 
-    ResourcesHandle Core::createResourceDescription(const std::vector<DescriptorSet> &descriptorSets)
+    ResourcesHandle Core::createResourceDescription(const std::vector<DescriptorSetConfig> &descriptorSets)
     {
         return m_DescriptorManager->createResourceDescription(descriptorSets);
     }
+
+	void Core::writeResourceDescription(ResourcesHandle handle, size_t setIndex, const DescriptorWrites &writes) {
+		m_DescriptorManager->writeResourceDescription(
+			handle, 
+			setIndex, 
+			writes, 
+			*m_ImageManager, 
+			*m_BufferManager, 
+			*m_SamplerManager);
+	}
+
+	vk::DescriptorSetLayout Core::getDescritorSetLayout(ResourcesHandle handle, size_t setIndex) {
+		return m_DescriptorManager->getDescriptorSetLayout(handle, setIndex);
+	}
 }
diff --git a/src/vkcv/DescriptorConfig.cpp b/src/vkcv/DescriptorConfig.cpp
index f437ab68..c4f6e326 100644
--- a/src/vkcv/DescriptorConfig.cpp
+++ b/src/vkcv/DescriptorConfig.cpp
@@ -14,7 +14,7 @@ namespace vkcv {
         shaderStage{shaderStage}
     {};
 
-    DescriptorSet::DescriptorSet(std::vector<DescriptorBinding> bindings) noexcept :
+    DescriptorSetConfig::DescriptorSetConfig(std::vector<DescriptorBinding> bindings) noexcept :
         bindings{std::move(bindings)}
     {};
 }
diff --git a/src/vkcv/DescriptorManager.cpp b/src/vkcv/DescriptorManager.cpp
index c42db30f..5cb05f7a 100644
--- a/src/vkcv/DescriptorManager.cpp
+++ b/src/vkcv/DescriptorManager.cpp
@@ -40,7 +40,7 @@ namespace vkcv
         m_Device.destroy(m_Pool);
     }
 
-    ResourcesHandle DescriptorManager::createResourceDescription(const std::vector<DescriptorSet> &descriptorSets)
+    ResourcesHandle DescriptorManager::createResourceDescription(const std::vector<DescriptorSetConfig> &descriptorSets)
     {
         std::vector<vk::DescriptorSet> vk_sets;
         std::vector<vk::DescriptorSetLayout> vk_setLayouts;
@@ -86,6 +86,105 @@ namespace vkcv
         return ResourcesHandle(m_NextResourceDescriptionID++);
     }
 
+	void DescriptorManager::writeResourceDescription(
+		ResourcesHandle			handle, 
+		size_t					setIndex,
+		const DescriptorWrites	&writes,
+		const ImageManager		&imageManager, 
+		const BufferManager		&bufferManager,
+		const SamplerManager	&samplerManager) {
+
+		vk::DescriptorSet set = m_ResourceDescriptions[handle.getId()].descriptorSets[setIndex];
+
+		std::vector<vk::WriteDescriptorSet> vulkanWrites;
+
+		for (const auto& write : writes.sampledImageWrites) {
+			vk::DescriptorImageInfo imageInfo(
+				nullptr,
+				imageManager.getVulkanImageView(write.image),
+				vk::ImageLayout::eShaderReadOnlyOptimal);
+
+			vk::WriteDescriptorSet vulkanWrite(
+				set,
+				write.binding,
+				(uint32_t)0,
+				vk::DescriptorType::eSampledImage,
+				imageInfo);
+			vulkanWrites.push_back(vulkanWrite);
+		}
+
+		for (const auto& write : writes.storageImageWrites) {
+			vk::DescriptorImageInfo imageInfo(
+				nullptr,
+				imageManager.getVulkanImageView(write.image),
+				vk::ImageLayout::eGeneral);
+
+			vk::WriteDescriptorSet vulkanWrite(
+				set,
+				write.binding,
+				(uint32_t)0,
+				vk::DescriptorType::eStorageImage,
+				imageInfo);
+			vulkanWrites.push_back(vulkanWrite);
+		}
+
+		for (const auto& write : writes.uniformBufferWrites) {
+			vk::DescriptorBufferInfo bufferInfo(
+				bufferManager.getBuffer(write.buffer),
+				(uint32_t)0,
+				bufferManager.getBufferSize(write.buffer));
+
+			vk::WriteDescriptorSet vulkanWrite(
+				set,
+				write.binding,
+				(uint32_t)0,
+				vk::DescriptorType::eUniformBuffer,
+				nullptr,
+				bufferInfo);
+			vulkanWrites.push_back(vulkanWrite);
+		}
+
+		for (const auto& write : writes.storageBufferWrites) {
+			vk::DescriptorBufferInfo bufferInfo(
+				bufferManager.getBuffer(write.buffer),
+				(uint32_t)0,
+				bufferManager.getBufferSize(write.buffer));
+
+			vk::WriteDescriptorSet vulkanWrite(
+				set,
+				write.binding,
+				(uint32_t)0,
+				vk::DescriptorType::eStorageBuffer,
+				nullptr,
+				bufferInfo);
+			vulkanWrites.push_back(vulkanWrite);
+		}
+
+		for (const auto& write : writes.samplerWrites) {
+			vk::DescriptorImageInfo imageInfo(
+				samplerManager.getVulkanSampler(write.sampler),
+				nullptr,
+				vk::ImageLayout::eGeneral);
+
+			vk::WriteDescriptorSet vulkanWrite(
+				set,
+				write.binding,
+				(uint32_t)0,
+				vk::DescriptorType::eSampler,
+				imageInfo);
+			vulkanWrites.push_back(vulkanWrite);
+		}
+		m_Device.updateDescriptorSets(vulkanWrites, nullptr);
+	}
+
+	vk::DescriptorSet DescriptorManager::getDescriptorSet(ResourcesHandle handle, size_t index) {
+		return m_ResourceDescriptions[handle.getId()].descriptorSets[index];
+	}
+
+	vk::DescriptorSetLayout DescriptorManager::getDescriptorSetLayout(ResourcesHandle handle, size_t index) {
+		return m_ResourceDescriptions[handle.getId()].descriptorSetLayouts[index];
+	}
+
     vk::DescriptorType DescriptorManager::convertDescriptorTypeFlag(DescriptorType type) {
         switch (type)
         {
@@ -95,9 +194,12 @@ namespace vkcv
                 return vk::DescriptorType::eStorageBuffer;
             case DescriptorType::SAMPLER:
                 return vk::DescriptorType::eSampler;
-            case DescriptorType::IMAGE:
+            case DescriptorType::IMAGE_SAMPLED:
                 return vk::DescriptorType::eSampledImage;
+			case DescriptorType::IMAGE_STORAGE:
+				return vk::DescriptorType::eStorageImage;
             default:
+				std::cerr << "Error: DescriptorManager::convertDescriptorTypeFlag, unknown DescriptorType" << std::endl;
                 return vk::DescriptorType::eUniformBuffer;
         }
     }
diff --git a/src/vkcv/DescriptorManager.hpp b/src/vkcv/DescriptorManager.hpp
index 744f5570..937fb278 100644
--- a/src/vkcv/DescriptorManager.hpp
+++ b/src/vkcv/DescriptorManager.hpp
@@ -2,6 +2,11 @@
 
 #include "vkcv/Handles.hpp"
 #include "vkcv/DescriptorConfig.hpp"
+#include "vkcv/DescriptorWrites.hpp"
+
+#include "ImageManager.hpp"
+#include "vkcv/BufferManager.hpp"
+#include "SamplerManager.hpp"
 
 namespace vkcv
 {
@@ -18,11 +23,22 @@ namespace vkcv
 		* @param[in] vector of filled vkcv::DescriptorSet structs
 		* @return index into that objects a resource handle
 		*/
-        ResourcesHandle createResourceDescription(const std::vector<DescriptorSet> & descriptorSets);
+        ResourcesHandle createResourceDescription(const std::vector<DescriptorSetConfig> & descriptorSets);
+
+		void writeResourceDescription(
+			ResourcesHandle			handle,
+			size_t					setIndex,
+			const DescriptorWrites& writes,
+			const ImageManager& imageManager,
+			const BufferManager& bufferManager,
+			const SamplerManager& samplerManager);
+
+		vk::DescriptorSet		getDescriptorSet(ResourcesHandle handle, size_t index);
+		vk::DescriptorSetLayout getDescriptorSetLayout(ResourcesHandle handle, size_t index);
 
 	private:
-		vk::Device m_Device;
-        vk::DescriptorPool m_Pool;
+		vk::Device			m_Device;
+        vk::DescriptorPool	m_Pool;
 
 
 		/**
diff --git a/src/vkcv/Image.cpp b/src/vkcv/Image.cpp
index c4341b4f..7104f784 100644
--- a/src/vkcv/Image.cpp
+++ b/src/vkcv/Image.cpp
@@ -38,6 +38,10 @@ namespace vkcv{
 		m_manager->switchImageLayout(m_handle, m_layout, newLayout);
 		m_layout = newLayout;
 	}
+
+	vkcv::ImageHandle Image::getHandle() const {
+		return m_handle;
+	}
 	
 	void Image::fill(void *data, size_t size) {
 		m_manager->fillImage(m_handle, data, size);
diff --git a/src/vkcv/PipelineConfig.cpp b/src/vkcv/PipelineConfig.cpp
index b5a8e98c..d3172584 100644
--- a/src/vkcv/PipelineConfig.cpp
+++ b/src/vkcv/PipelineConfig.cpp
@@ -9,15 +9,18 @@
 namespace vkcv {
 
     PipelineConfig::PipelineConfig(
-		const ShaderProgram& shaderProgram, 
-		uint32_t width, 
-		uint32_t height, 
-		PassHandle &passHandle, 
-		const std::vector<VertexAttribute> &vertexAttributes):
+		const ShaderProgram&						shaderProgram, 
+		uint32_t									width, 
+		uint32_t									height, 
+		PassHandle									&passHandle, 
+		const std::vector<VertexAttribute>			&vertexAttributes,
+		const std::vector<vk::DescriptorSetLayout>	&descriptorLayouts)
+		:
 		m_ShaderProgram(shaderProgram),
 		m_Height(height),
 		m_Width(width),
 		m_PassHandle(passHandle),
-		m_vertexAttributes(vertexAttributes)
+		m_vertexAttributes(vertexAttributes),
+		m_descriptorLayouts(descriptorLayouts)
 		{}
 }
diff --git a/src/vkcv/PipelineManager.cpp b/src/vkcv/PipelineManager.cpp
index ca6d44b5..1b0d665e 100644
--- a/src/vkcv/PipelineManager.cpp
+++ b/src/vkcv/PipelineManager.cpp
@@ -186,7 +186,7 @@ namespace vkcv
         // pipeline layout
         vk::PipelineLayoutCreateInfo pipelineLayoutCreateInfo(
 			{},
-			{},
+			(config.m_descriptorLayouts),
 			(pushConstantRange));
         vk::PipelineLayout vkPipelineLayout{};
         if (m_Device.createPipelineLayout(&pipelineLayoutCreateInfo, nullptr, &vkPipelineLayout) != vk::Result::eSuccess)
-- 
GitLab