Exemple #1
0
PRAGMA_WARNING_POP


//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void VertexBuffer::onInitialization()
{
	// Get and check the renderer instance
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer)
	{
		// Create the buffer manager
		mBufferManager = renderer->createBufferManager();

		{ // Create the root signature
			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(0, nullptr, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

			// Create the instance
			mRootSignature = renderer->createRootSignature(rootSignature);
		}

		// Vertex input layout
		static constexpr Renderer::VertexAttribute vertexAttributesLayoutVBO[] =
		{
			{ // Attribute 0
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_2,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Position",									// name[32] (char)
				"POSITION",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				sizeof(float) * 5,							// strideInBytes (uint32_t)
				0											// instancesPerElement (uint32_t)
			},
			{ // Attribute 1
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_3,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Color",									// name[32] (char)
				"COLOR",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				sizeof(float) * 2,							// alignedByteOffset (uint32_t)
				sizeof(float) * 5,							// strideInBytes (uint32_t)
				0											// instancesPerElement (uint32_t)
			}
		};
		const Renderer::VertexAttributes vertexAttributesVBO(static_cast<uint32_t>(GLM_COUNTOF(vertexAttributesLayoutVBO)), vertexAttributesLayoutVBO);
		static constexpr Renderer::VertexAttribute vertexAttributesLayoutVBOs[] =
		{
			{ // Attribute 0
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_2,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Position",									// name[32] (char)
				"POSITION",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				sizeof(float) * 2,							// strideInBytes (uint32_t)
				0											// instancesPerElement (uint32_t)
			},
			{ // Attribute 1
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_3,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Color",									// name[32] (char)
				"COLOR",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				1,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				sizeof(float) * 3,							// strideInBytes (uint32_t)
				0											// instancesPerElement (uint32_t)
			}
		};
		const Renderer::VertexAttributes vertexAttributesVBOs(static_cast<uint32_t>(GLM_COUNTOF(vertexAttributesLayoutVBOs)), vertexAttributesLayoutVBOs);

		// Vertex array object (VAO)
		// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
		// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
		// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
		//    reference of the used vertex buffer objects (VBO). If the reference counter of a
		//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.

		{ // Create vertex array object (VAO)
			// Create the vertex buffer object (VBO) holding position and color data
			// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
			// -> Traditional normalized RGB vertex colors
			static constexpr float VERTEX_POSITION_COLOR[] =
			{	 // Position     Color				// Vertex ID	Triangle on screen
				 0.0f, 1.0f,	1.0f, 0.0f, 0.0f,	// 0				0
				 1.0f, 0.0f,	0.0f, 1.0f, 0.0f,	// 1			   .   .
				-0.5f, 0.0f,	0.0f, 0.0f, 1.0f	// 2			  2.......1
			};
			Renderer::IVertexBufferPtr vertexBufferPositionColor(mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION_COLOR), VERTEX_POSITION_COLOR));

			// Create vertex array object (VAO)
			const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] = { vertexBufferPositionColor };
			mVertexArrayVBO = mBufferManager->createVertexArray(vertexAttributesVBO, static_cast<uint32_t>(GLM_COUNTOF(vertexArrayVertexBuffers)), vertexArrayVertexBuffers);
		}

		{ // Create vertex array object (VAO) using multiple vertex buffer object (VBO)
			// Create the vertex buffer object (VBO) holding color data
			// -> Traditional normalized RGB vertex colors
			static constexpr float VERTEX_COLOR[] =
			{					// Vertex ID	Triangle on screen
				1.0f, 0.0f, 0.0f,	// 0			  0.......1
				0.0f, 1.0f, 0.0f,	// 1			   .   .
				0.0f, 0.0f, 1.0f	// 2			  	2
			};
			Renderer::IVertexBufferPtr vertexBufferColor(mBufferManager->createVertexBuffer(sizeof(VERTEX_COLOR), VERTEX_COLOR));

			// Create the vertex buffer object (VBO) holding position data
			// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
			static constexpr float VERTEX_POSITION[] =
			{					// Vertex ID	Triangle on screen
				-0.5f,  0.0f,	// 0			  0.......1
				 1.0f,  0.0f,	// 1			   .   .
				 0.0f, -1.0f	// 2			  	2
			};
			Renderer::IVertexBufferPtr vertexBufferPosition(mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION));

			// Create vertex array object (VAO)
			const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] = { vertexBufferPosition, vertexBufferColor };
			mVertexArrayVBOs = mBufferManager->createVertexArray(vertexAttributesVBOs, static_cast<uint32_t>(GLM_COUNTOF(vertexArrayVertexBuffers)), vertexArrayVertexBuffers);
		}

		{
			// Get the shader source code (outsourced to keep an overview)
			const char* vertexShaderSourceCode = nullptr;
			const char* fragmentShaderSourceCode = nullptr;
			#include "VertexBuffer_GLSL_450.h"	// For Vulkan
			#include "VertexBuffer_GLSL_410.h"	// macOS 10.11 only supports OpenGL 4.1 hence it's our OpenGL minimum
			#include "VertexBuffer_GLSL_ES3.h"
			#include "VertexBuffer_HLSL_D3D9_D3D10_D3D11_D3D12.h"
			#include "VertexBuffer_Null.h"
			Renderer::IShaderLanguage& shaderLanguage = renderer->getDefaultShaderLanguage();

			{ // Create pipeline state objects (PSO) using one vertex buffer object (VBO)
				// Create the graphics program
				Renderer::IGraphicsProgramPtr graphicsProgram;
				graphicsProgram = shaderLanguage.createGraphicsProgram(
					*mRootSignature,
					vertexAttributesVBO,
					shaderLanguage.createVertexShaderFromSourceCode(vertexAttributesVBO, vertexShaderSourceCode),
					shaderLanguage.createFragmentShaderFromSourceCode(fragmentShaderSourceCode));

				// Create the graphics pipeline state objects (PSO)
				if (nullptr != graphicsProgram)
				{
					mGraphicsPipelineStateVBO = renderer->createGraphicsPipelineState(Renderer::GraphicsPipelineStateBuilder(mRootSignature, graphicsProgram, vertexAttributesVBO, getMainRenderTarget()->getRenderPass()));
				}
			}

			{ // Create graphics pipeline state objects (PSO) using multiple vertex buffer object (VBO)
				// Create the graphics program
				Renderer::IGraphicsProgramPtr graphicsProgram;
				graphicsProgram = shaderLanguage.createGraphicsProgram(
					*mRootSignature,
					vertexAttributesVBOs,
					shaderLanguage.createVertexShaderFromSourceCode(vertexAttributesVBOs, vertexShaderSourceCode),
					shaderLanguage.createFragmentShaderFromSourceCode(fragmentShaderSourceCode));

				// Create the graphics pipeline state objects (PSO)
				if (nullptr != graphicsProgram)
				{
					mGraphicsPipelineStateVBOs = renderer->createGraphicsPipelineState(Renderer::GraphicsPipelineStateBuilder(mRootSignature, graphicsProgram, vertexAttributesVBOs, getMainRenderTarget()->getRenderPass()));
				}
			}
		}

		// Since we're always submitting the same commands to the renderer, we can fill the command buffer once during initialization and then reuse it multiple times during runtime
		fillCommandBuffer();
	}
}
Exemple #2
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstGeometryShader::onInitialization()
{
	// Call the base implementation
	IApplicationRenderer::onInitialization();

	// Get and check the renderer instance
	// -> Geometry shaders supported?
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer && renderer->getCapabilities().maximumNumberOfGsOutputVertices)
	{
		// Create the buffer manager
		mBufferManager = renderer->createBufferManager();

		{ // Create the root signature
			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(0, nullptr, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

			// Create the instance
			mRootSignature = renderer->createRootSignature(rootSignature);
		}

		// Vertex input layout
		const Renderer::VertexAttribute vertexAttributesLayout[] =
		{
			{ // Attribute 0
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_1,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Position",									// name[32] (char)
				"POSITION",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				// Data source, instancing part
				0											// instancesPerElement (uint32_t)
			}
		};
		const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout);

		{ // Create vertex array object (VAO)
			// Create the vertex buffer object (VBO)
			static const float VERTEX_POSITION[] =
			{			// Vertex ID
				42.0f	// 0
			};
			Renderer::IVertexBufferPtr vertexBuffer(mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferUsage::STATIC_DRAW));

			// Create vertex array object (VAO)
			// -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
			// -> This means that there's no need to keep an own vertex buffer object (VBO) reference
			// -> When the vertex array object (VAO) is destroyed, it automatically decreases the
			//    reference of the used vertex buffer objects (VBO). If the reference counter of a
			//    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
			const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] =
			{
				{ // Vertex buffer 0
					vertexBuffer,	// vertexBuffer (Renderer::IVertexBuffer *)
					sizeof(float)	// strideInBytes (uint32_t)
				}
			};
			mVertexArray = mBufferManager->createVertexArray(vertexAttributes, glm::countof(vertexArrayVertexBuffers), vertexArrayVertexBuffers);
		}

		// Create the program: Decide which shader language should be used (for example "GLSL" or "HLSL")
		Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
		if (nullptr != shaderLanguage)
		{
			// Create the program
			Renderer::IProgramPtr program;
			{
				// Get the shader source code (outsourced to keep an overview)
				const char *vertexShaderSourceCode = nullptr;
				const char *geometryShaderSourceCode = nullptr;
				const char *fragmentShaderSourceCode = nullptr;
				#include "FirstGeometryShader_GLSL_410.h"
				#include "FirstGeometryShader_HLSL_D3D10_D3D11_D3D12.h"
				#include "FirstGeometryShader_Null.h"

				// Create the program
				program = shaderLanguage->createProgram(
					*mRootSignature,
					vertexAttributes,
					shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode),
					shaderLanguage->createGeometryShaderFromSourceCode(geometryShaderSourceCode, Renderer::GsInputPrimitiveTopology::POINTS, Renderer::GsOutputPrimitiveTopology::TRIANGLE_STRIP, 3),
					shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode));
			}

			// Create the pipeline state object (PSO)
			if (nullptr != program)
			{
				Renderer::PipelineState pipelineState = Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes);
				pipelineState.primitiveTopologyType = Renderer::PrimitiveTopologyType::POINT;
				mPipelineState = renderer->createPipelineState(pipelineState);
			}
		}

		// Since we're always submitting the same commands to the renderer, we can fill the command buffer once during initialization and then reuse it multiple times during runtime
		fillCommandBuffer();
	}
}
Exemple #3
0
//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstMesh::onInitialization()
{
    // Call the base implementation
    IApplicationRendererRuntime::onInitialization();

    // Get and check the renderer runtime instance
    RendererRuntime::IRendererRuntime* rendererRuntime = getRendererRuntime();
    if (nullptr != rendererRuntime)
    {
        Renderer::IRendererPtr renderer(getRenderer());

        // Create uniform buffers
        // -> Direct3D 9 and OpenGL ES 2 do not support uniform buffers
        // -> Direct3D 10, 11 and 12 do not support individual uniforms
        // -> The renderer is just a light weight abstraction layer, so we need to handle the differences
        if ((0 == strcmp(renderer->getName(), "Direct3D10") || 0 == strcmp(renderer->getName(), "Direct3D11") || 0 == strcmp(renderer->getName(), "Direct3D12")))
        {
            // Allocate enough memory for two 4x4 floating point matrices
            mUniformBuffer = rendererRuntime->getBufferManager().createUniformBuffer(2 * 4 * 4 * sizeof(float), nullptr, Renderer::BufferUsage::DYNAMIC_DRAW);
        }

        // Decide which shader language should be used (for example "GLSL" or "HLSL")
        Renderer::IShaderLanguagePtr shaderLanguage(renderer->getShaderLanguage());
        if (nullptr != shaderLanguage)
        {
            // Vertex input layout
            const Renderer::VertexAttribute vertexAttributesLayout[] =
            {
                {   // Attribute 0
                    // Data destination
                    Renderer::VertexAttributeFormat::FLOAT_3,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "Position",									// name[32] (char)
                    "POSITION",									// semanticName[32] (char)
                    0,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    0,											// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                },
                {   // Attribute 1
                    // Data destination
                    Renderer::VertexAttributeFormat::SHORT_2,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "TexCoord",									// name[32] (char)
                    "TEXCOORD",									// semanticName[32] (char)
                    0,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    sizeof(float) * 3,							// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                },
                {   // Attribute 2
                    // Data destination
                    Renderer::VertexAttributeFormat::SHORT_4,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
                    "QTangent",									// name[32] (char)
                    "TEXCOORD",									// semanticName[32] (char)
                    1,											// semanticIndex (uint32_t)
                    // Data source
                    0,											// inputSlot (uint32_t)
                    sizeof(float) * 3 + sizeof(short) * 2,		// alignedByteOffset (uint32_t)
                    // Data source, instancing part
                    0											// instancesPerElement (uint32_t)
                }
            };
            const Renderer::VertexAttributes vertexAttributes(glm::countof(vertexAttributesLayout), vertexAttributesLayout);

            {   // Create the root signature
                Renderer::DescriptorRangeBuilder ranges[6];
                ranges[0].initialize(Renderer::DescriptorRangeType::UBV, 1, 0, "UniformBlockDynamicVs", 0);
                ranges[1].initializeSampler(1, 0);
                ranges[2].initialize(Renderer::DescriptorRangeType::SRV, 1, 0, "DiffuseMap", 1);
                ranges[3].initialize(Renderer::DescriptorRangeType::SRV, 1, 1, "EmissiveMap", 1);
                ranges[4].initialize(Renderer::DescriptorRangeType::SRV, 1, 2, "NormalMap", 1);
                ranges[5].initialize(Renderer::DescriptorRangeType::SRV, 1, 3, "SpecularMap", 1);

                Renderer::RootParameterBuilder rootParameters[6];
                rootParameters[0].initializeAsDescriptorTable(1, &ranges[0], Renderer::ShaderVisibility::VERTEX);
                rootParameters[1].initializeAsDescriptorTable(1, &ranges[1], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[2].initializeAsDescriptorTable(1, &ranges[2], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[3].initializeAsDescriptorTable(1, &ranges[3], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[4].initializeAsDescriptorTable(1, &ranges[4], Renderer::ShaderVisibility::FRAGMENT);
                rootParameters[5].initializeAsDescriptorTable(1, &ranges[5], Renderer::ShaderVisibility::FRAGMENT);

                // Setup
                Renderer::RootSignatureBuilder rootSignature;
                rootSignature.initialize(glm::countof(rootParameters), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

                // Create the instance
                mRootSignature = renderer->createRootSignature(rootSignature);
            }

            // Create the program
            Renderer::IProgramPtr program;
            {
                // Get the shader source code (outsourced to keep an overview)
                const char *vertexShaderProfile = nullptr;
                const char *vertexShaderSourceCode = nullptr;
                const char *fragmentShaderProfile = nullptr;
                const char *fragmentShaderSourceCode = nullptr;
#include "FirstMesh_GLSL_410.h"
#include "FirstMesh_GLSL_ES2.h"
#include "FirstMesh_HLSL_D3D9.h"
#include "FirstMesh_HLSL_D3D10_D3D11_D3D12.h"
#include "FirstMesh_Null.h"

                // Create the program
                mProgram = program = shaderLanguage->createProgram(
                                         *mRootSignature,
                                         vertexAttributes,
                                         shaderLanguage->createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode, vertexShaderProfile),
                                         shaderLanguage->createFragmentShaderFromSourceCode(fragmentShaderSourceCode, fragmentShaderProfile));
            }

            // Is there a valid program?
            if (nullptr != program)
            {
                // Create the pipeline state object (PSO)
                mPipelineState = renderer->createPipelineState(Renderer::PipelineStateBuilder(mRootSignature, program, vertexAttributes));

                // Optimization: Cached data to not bother the renderer API too much
                if (nullptr == mUniformBuffer)
                {
                    mObjectSpaceToClipSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToClipSpaceMatrix");
                    mObjectSpaceToViewSpaceMatrixUniformHandle = program->getUniformHandle("ObjectSpaceToViewSpaceMatrix");
                }
            }

            // Create mesh instance
            mMeshResourceId = rendererRuntime->getMeshResourceManager().loadMeshResourceByAssetId("Example/Mesh/Character/Imrod");

            {   // Load in the diffuse, emissive, normal and specular texture
                // -> The tangent space normal map is stored with three components, two would be enough to recalculate the third component within the fragment shader
                // -> The specular map could be put into the alpha channel of the diffuse map instead of storing it as an individual texture
                RendererRuntime::TextureResourceManager& textureResourceManager = rendererRuntime->getTextureResourceManager();
                mDiffuseTextureResourceId  = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodDiffuseMap");
                mNormalTextureResourceId   = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodEmissiveMap");
                mSpecularTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodNormalMap");
                mEmissiveTextureResourceId = textureResourceManager.loadTextureResourceByAssetId("Example/Texture/Character/ImrodSpecularMap");
            }

            {   // Create sampler state
                Renderer::SamplerState samplerStateSettings = Renderer::ISamplerState::getDefaultSamplerState();
                samplerStateSettings.addressU = Renderer::TextureAddressMode::WRAP;
                samplerStateSettings.addressV = Renderer::TextureAddressMode::WRAP;
                mSamplerState = renderer->createSamplerState(samplerStateSettings);
            }
        }
    }
}
PRAGMA_WARNING_POP


//[-------------------------------------------------------]
//[ Public virtual IApplication methods                   ]
//[-------------------------------------------------------]
void FirstComputeShader::onInitialization()
{
	// Get and check the renderer instance
	Renderer::IRendererPtr renderer(getRenderer());
	if (nullptr != renderer)
	{
		// Create the buffer and texture manager
		mBufferManager = renderer->createBufferManager();
		mTextureManager = renderer->createTextureManager();

		{ // Create the graphics root signature
			// TODO(co) Compute shader: Get rid of the OpenGL/Direct3D 11 variation here
			const uint32_t offset = (renderer->getNameId() == Renderer::NameId::VULKAN || renderer->getNameId() == Renderer::NameId::OPENGL) ? 1u : 0u;
			Renderer::DescriptorRangeBuilder ranges[5];
			ranges[0].initialize(Renderer::ResourceType::UNIFORM_BUFFER,	0,			 "UniformBuffer",		  Renderer::ShaderVisibility::FRAGMENT);
			ranges[1].initialize(Renderer::ResourceType::TEXTURE_BUFFER,	0,			 "InputTextureBuffer",	  Renderer::ShaderVisibility::VERTEX);
			ranges[2].initialize(Renderer::ResourceType::STRUCTURED_BUFFER, 1u + offset, "InputStructuredBuffer", Renderer::ShaderVisibility::VERTEX);
			ranges[3].initialize(Renderer::ResourceType::TEXTURE_2D,		1,			 "AlbedoMap",			  Renderer::ShaderVisibility::FRAGMENT);
			ranges[4].initializeSampler(0, Renderer::ShaderVisibility::FRAGMENT);

			Renderer::RootParameterBuilder rootParameters[2];
			rootParameters[0].initializeAsDescriptorTable(4, &ranges[0]);
			rootParameters[1].initializeAsDescriptorTable(1, &ranges[4]);

			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(static_cast<uint32_t>(GLM_COUNTOF(rootParameters)), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT);

			// Create the instance
			mGraphicsRootSignature = renderer->createRootSignature(rootSignature);
		}

		{ // Create the first compute root signature
			Renderer::DescriptorRangeBuilder ranges[7];
			// Input
			ranges[0].initialize(Renderer::ResourceType::TEXTURE_2D,	  0,			"InputTexture2D",	  Renderer::ShaderVisibility::COMPUTE);
			ranges[1].initialize(Renderer::ResourceType::INDEX_BUFFER,    1,			"InputIndexBuffer",	  Renderer::ShaderVisibility::COMPUTE);
			ranges[2].initialize(Renderer::ResourceType::VERTEX_BUFFER,   2,			"InputVertexBuffer",  Renderer::ShaderVisibility::COMPUTE);
			ranges[3].initialize(Renderer::ResourceType::UNIFORM_BUFFER,  0,			"InputUniformBuffer", Renderer::ShaderVisibility::COMPUTE);
			// Output
			// TODO(co) Compute shader: Get rid of the OpenGL/Direct3D 11 variation here
			const uint32_t offset = (renderer->getNameId() == Renderer::NameId::VULKAN || renderer->getNameId() == Renderer::NameId::OPENGL) ? 4u : 0u;
			ranges[4].initialize(Renderer::ResourceType::TEXTURE_2D,	  0u + offset, "OutputTexture2D",	  Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);
			ranges[5].initialize(Renderer::ResourceType::INDEX_BUFFER,    1u + offset, "OutputIndexBuffer",	  Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);
			ranges[6].initialize(Renderer::ResourceType::VERTEX_BUFFER,   2u + offset, "OutputVertexBuffer",  Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);

			Renderer::RootParameterBuilder rootParameters[1];
			rootParameters[0].initializeAsDescriptorTable(7, &ranges[0]);

			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(static_cast<uint32_t>(GLM_COUNTOF(rootParameters)), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::NONE);

			// Create the instance
			mComputeRootSignature1 = renderer->createRootSignature(rootSignature);
		}

		{ // Create the second compute root signature
			Renderer::DescriptorRangeBuilder ranges[6];
			// Input
			ranges[0].initialize(Renderer::ResourceType::TEXTURE_BUFFER,	0,			 "InputTextureBuffer",	   Renderer::ShaderVisibility::COMPUTE);
			ranges[1].initialize(Renderer::ResourceType::STRUCTURED_BUFFER, 1,			 "InputStructuredBuffer",  Renderer::ShaderVisibility::COMPUTE);
			ranges[2].initialize(Renderer::ResourceType::INDIRECT_BUFFER,	2,			 "InputIndirectBuffer",	   Renderer::ShaderVisibility::COMPUTE);
			// Output
			// TODO(co) Compute shader: Get rid of the OpenGL/Direct3D 11 variation here
			const uint32_t offset = (renderer->getNameId() == Renderer::NameId::VULKAN || renderer->getNameId() == Renderer::NameId::OPENGL) ? 3u : 0u;
			ranges[3].initialize(Renderer::ResourceType::TEXTURE_BUFFER,	0u + offset, "OutputTextureBuffer",	   Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);
			ranges[4].initialize(Renderer::ResourceType::STRUCTURED_BUFFER, 1u + offset, "OutputStructuredBuffer", Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);
			ranges[5].initialize(Renderer::ResourceType::INDIRECT_BUFFER,	2u + offset, "OutputIndirectBuffer",   Renderer::ShaderVisibility::COMPUTE, Renderer::DescriptorRangeType::UAV);

			Renderer::RootParameterBuilder rootParameters[1];
			rootParameters[0].initializeAsDescriptorTable(6, &ranges[0]);

			// Setup
			Renderer::RootSignatureBuilder rootSignature;
			rootSignature.initialize(static_cast<uint32_t>(GLM_COUNTOF(rootParameters)), rootParameters, 0, nullptr, Renderer::RootSignatureFlags::NONE);

			// Create the instance
			mComputeRootSignature2 = renderer->createRootSignature(rootSignature);
		}

		// Create sampler state and wrap it into a resource group instance
		Renderer::IResource* samplerStateResource = nullptr;
		{
			Renderer::SamplerState samplerState = Renderer::ISamplerState::getDefaultSamplerState();
			samplerState.maxLOD = 0.0f;
			samplerStateResource = renderer->createSamplerState(samplerState);
			mGraphicsSamplerStateGroup = mGraphicsRootSignature->createResourceGroup(1, 1, &samplerStateResource);
		}

		{ // Texture buffer
			static constexpr float VERTEX_POSITION_OFFSET[] =
			{								// Vertex ID	Triangle on screen
				0.5f, -0.5f, 0.0f, 0.0f,	// 0				0
				0.5f, -0.5f, 0.0f, 0.0f,	// 1			   .   .
				0.5f, -0.5f, 0.0f, 0.0f,	// 2			  2.......1
			};

			// Create the texture buffer which will be read by a compute shader
			mComputeInputTextureBuffer = mBufferManager->createTextureBuffer(sizeof(VERTEX_POSITION_OFFSET), VERTEX_POSITION_OFFSET);

			// Create the texture buffer which will be filled by a compute shader
			mComputeOutputTextureBuffer = mBufferManager->createTextureBuffer(sizeof(VERTEX_POSITION_OFFSET), nullptr, Renderer::BufferFlag::UNORDERED_ACCESS | Renderer::BufferFlag::SHADER_RESOURCE);
		}

		{ // Structured buffer
			struct Vertex
			{
				float position[2];
				float padding[2];
			};
			static constexpr Vertex VERTICES[] =
			{									// Vertex ID	Triangle on screen
				{ -0.5f, 0.5f, 0.0f, 0.0f },	// 0				0
				{ -0.5f, 0.5f, 0.0f, 0.0f },	// 1			   .   .
				{ -0.5f, 0.5f, 0.0f, 0.0f },	// 2			  2.......1
			};

			// Create the structured buffer which will be read by a compute shader
			mComputeInputStructuredBuffer = mBufferManager->createStructuredBuffer(sizeof(VERTICES), VERTICES, Renderer::BufferFlag::SHADER_RESOURCE, Renderer::BufferUsage::STATIC_DRAW, sizeof(Vertex));

			// Create the structured buffer which will be filled by a compute shader
			mComputeOutputStructuredBuffer = mBufferManager->createStructuredBuffer(sizeof(VERTICES), nullptr, Renderer::BufferFlag::UNORDERED_ACCESS | Renderer::BufferFlag::SHADER_RESOURCE, Renderer::BufferUsage::STATIC_DRAW, sizeof(Vertex));
		}

		{ // Indirect buffer
			{ // Create the indirect buffer which will be read by a compute shader
				const Renderer::DrawIndexedArguments drawIndexedArguments =
				{
					0, // indexCountPerInstance (uint32_t)	- Filled by compute shader via atomics counting
					1, // instanceCount (uint32_t)
					0, // startIndexLocation (uint32_t)
					0, // baseVertexLocation (int32_t)
					0  // startInstanceLocation (uint32_t)
				};
				mComputeInputIndirectBuffer = mBufferManager->createIndirectBuffer(sizeof(Renderer::DrawIndexedArguments), &drawIndexedArguments, Renderer::IndirectBufferFlag::SHADER_RESOURCE | Renderer::IndirectBufferFlag::DRAW_INDEXED_ARGUMENTS);
			}

			// Create the indirect buffer which will be filled by a compute shader
			mComputeOutputIndirectBuffer = mBufferManager->createIndirectBuffer(sizeof(Renderer::DrawIndexedArguments), nullptr, Renderer::IndirectBufferFlag::UNORDERED_ACCESS | Renderer::IndirectBufferFlag::DRAW_INDEXED_ARGUMENTS);
		}

		// Vertex input layout
		static constexpr Renderer::VertexAttribute vertexAttributesLayout[] =
		{
			{ // Attribute 0
				// Data destination
				Renderer::VertexAttributeFormat::FLOAT_2,	// vertexAttributeFormat (Renderer::VertexAttributeFormat)
				"Position",									// name[32] (char)
				"POSITION",									// semanticName[32] (char)
				0,											// semanticIndex (uint32_t)
				// Data source
				0,											// inputSlot (uint32_t)
				0,											// alignedByteOffset (uint32_t)
				sizeof(float) * 2,							// strideInBytes (uint32_t)
				0											// instancesPerElement (uint32_t)
			}
		};
		const Renderer::VertexAttributes vertexAttributes(static_cast<uint32_t>(GLM_COUNTOF(vertexAttributesLayout)), vertexAttributesLayout);

		{ // Create the index buffer object (IBO)
			static constexpr uint16_t INDICES[] =
			{
				0, 1, 2
			};
			mComputeInputIndexBuffer = mBufferManager->createIndexBuffer(sizeof(INDICES), INDICES, Renderer::BufferFlag::SHADER_RESOURCE);
			mComputeOutputIndexBuffer = mBufferManager->createIndexBuffer(sizeof(INDICES), nullptr, Renderer::BufferFlag::UNORDERED_ACCESS);
		}

		{ // Create vertex array object (VAO)
			// Create the vertex buffer object (VBO)
			// -> Clip space vertex positions, left/bottom is (-1,-1) and right/top is (1,1)
			static constexpr float VERTEX_POSITION[] =
			{					// Vertex ID	Triangle on screen
				 0.0f, 1.0f,	// 0				0
				 1.0f, 0.0f,	// 1			   .   .
				-0.5f, 0.0f		// 2			  2.......1
			};
			mComputeInputVertexBuffer = mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), VERTEX_POSITION, Renderer::BufferFlag::SHADER_RESOURCE);
			mComputeOutputVertexBuffer = mBufferManager->createVertexBuffer(sizeof(VERTEX_POSITION), nullptr, Renderer::BufferFlag::UNORDERED_ACCESS);
		}

		{ // Create vertex array object (VAO)
		  // -> The vertex array object (VAO) keeps a reference to the used vertex buffer object (VBO)
		  // -> This means that there's no need to keep an own vertex buffer object (VBO) reference
		  // -> When the vertex array object (VAO) is destroyed, it automatically decreases the
		  //    reference of the used vertex buffer objects (VBO). If the reference counter of a
		  //    vertex buffer object (VBO) reaches zero, it's automatically destroyed.
			const Renderer::VertexArrayVertexBuffer vertexArrayVertexBuffers[] = { mComputeOutputVertexBuffer };
			mVertexArray = mBufferManager->createVertexArray(vertexAttributes, static_cast<uint32_t>(GLM_COUNTOF(vertexArrayVertexBuffers)), vertexArrayVertexBuffers, mComputeOutputIndexBuffer);
		}

		{ // Create the uniform buffer which will be read by a compute shader
			static constexpr float RGBA_COLOR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
			mComputeInputUniformBuffer = mBufferManager->createUniformBuffer(sizeof(RGBA_COLOR), RGBA_COLOR);
		}

		{ // Resource group related
			// Create the texture instance, but without providing texture data (we use the texture as render target)
			// -> Use the "Renderer::TextureFlag::RENDER_TARGET"-flag to mark this texture as a render target
			// -> Required for Vulkan, Direct3D 9, Direct3D 10, Direct3D 11 and Direct3D 12
			// -> Not required for OpenGL and OpenGL ES 3
			// -> The optimized texture clear value is a Direct3D 12 related option
			const Renderer::TextureFormat::Enum textureFormat = Renderer::TextureFormat::Enum::R8G8B8A8;
			Renderer::ITexture* computeInputTexture2D = mTextureManager->createTexture2D(16, 16, textureFormat, nullptr, Renderer::TextureFlag::SHADER_RESOURCE | Renderer::TextureFlag::RENDER_TARGET, Renderer::TextureUsage::DEFAULT, 1, reinterpret_cast<const Renderer::OptimizedTextureClearValue*>(&Color4::GREEN));
			Renderer::ITexture* computeOutputTexture2D = mTextureManager->createTexture2D(16, 16, textureFormat, nullptr, Renderer::TextureFlag::SHADER_RESOURCE | Renderer::TextureFlag::UNORDERED_ACCESS);

			{ // Create the framebuffer object (FBO) instance
				const Renderer::FramebufferAttachment colorFramebufferAttachment(computeInputTexture2D);
				mFramebuffer = renderer->createFramebuffer(*renderer->createRenderPass(1, &textureFormat), &colorFramebufferAttachment);
			}

			{ // Create first compute resource group
				Renderer::IResource* resources[7] = {
					// Input
					computeInputTexture2D, mComputeInputIndexBuffer, mComputeInputVertexBuffer, mComputeInputUniformBuffer,
					// Output
					computeOutputTexture2D, mComputeOutputIndexBuffer, mComputeOutputVertexBuffer
				};
				Renderer::ISamplerState* samplerStates[7] = {
					// Input
					static_cast<Renderer::ISamplerState*>(samplerStateResource), nullptr, nullptr, nullptr,
					// Output
					nullptr, nullptr, nullptr
				};
				mComputeResourceGroup1 = mComputeRootSignature1->createResourceGroup(0, static_cast<uint32_t>(GLM_COUNTOF(resources)), resources, samplerStates);
			}

			{ // Create second compute resource group
				Renderer::IResource* resources[6] = {
					// Input
					mComputeInputTextureBuffer, mComputeInputStructuredBuffer, mComputeInputIndirectBuffer,
					// Output
					mComputeOutputTextureBuffer, mComputeOutputStructuredBuffer, mComputeOutputIndirectBuffer
				};
				mComputeResourceGroup2 = mComputeRootSignature2->createResourceGroup(0, static_cast<uint32_t>(GLM_COUNTOF(resources)), resources, nullptr);
			}

			{ // Create graphics resource group
				Renderer::IResource* resources[4] = { mComputeInputUniformBuffer, mComputeOutputTextureBuffer, mComputeOutputStructuredBuffer, computeOutputTexture2D };
				Renderer::ISamplerState* samplerStates[4] = { nullptr, nullptr, nullptr, static_cast<Renderer::ISamplerState*>(samplerStateResource) };
				mGraphicsResourceGroup = mGraphicsRootSignature->createResourceGroup(0, static_cast<uint32_t>(GLM_COUNTOF(resources)), resources, samplerStates);
			}
		}

		{
			// Create the graphics program
			Renderer::IGraphicsProgramPtr graphicsProgram;
			{
				// Get the shader source code (outsourced to keep an overview)
				const char* vertexShaderSourceCode = nullptr;
				const char* fragmentShaderSourceCode = nullptr;
				const char* computeShaderSourceCode1 = nullptr;
				const char* computeShaderSourceCode2 = nullptr;
				#include "FirstComputeShader_GLSL_450.h"	// For Vulkan
				#include "FirstComputeShader_GLSL_430.h"	// macOS 10.11 only supports OpenGL 4.1 and hence can't be supported by this example
				#include "FirstComputeShader_HLSL_D3D11_D3D12.h"
				#include "FirstComputeShader_Null.h"

				// Create the graphics program
				Renderer::IShaderLanguage& shaderLanguage = renderer->getDefaultShaderLanguage();
				graphicsProgram = shaderLanguage.createGraphicsProgram(
					*mGraphicsRootSignature,
					vertexAttributes,
					shaderLanguage.createVertexShaderFromSourceCode(vertexAttributes, vertexShaderSourceCode),
					shaderLanguage.createFragmentShaderFromSourceCode(fragmentShaderSourceCode));

				// Create the compute pipeline state objects (PSO)
				mComputePipelineState1 = renderer->createComputePipelineState(*mComputeRootSignature1, *shaderLanguage.createComputeShaderFromSourceCode(computeShaderSourceCode1));
				mComputePipelineState2 = renderer->createComputePipelineState(*mComputeRootSignature2, *shaderLanguage.createComputeShaderFromSourceCode(computeShaderSourceCode2));
			}

			// Create the graphics pipeline state object (PSO)
			if (nullptr != graphicsProgram)
			{
				mGraphicsPipelineState = renderer->createGraphicsPipelineState(Renderer::GraphicsPipelineStateBuilder(mGraphicsRootSignature, graphicsProgram, vertexAttributes, getMainRenderTarget()->getRenderPass()));
			}
		}

		// Since we're always submitting the same commands to the renderer, we can fill the command buffer once during initialization and then reuse it multiple times during runtime
		fillCommandBuffer();
	}
}