コード例 #1
0
ファイル: D3D12Renderer.cpp プロジェクト: Napoleon314/Venus3D
//--------------------------------------------------------------------------
void D3D12Renderer::Term()
{
	for (auto pkWindow : m_kRenderWindowList)
	{
		pkWindow->Term();
	}
	VE_ASSERT(m_kRenderWindowList.empty());

	m_kSRVHeap.Term();
	m_kDSVHeap.Term();
	m_kRTVHeap.Term();

	VE_SAFE_RELEASE(m_pkDevice);
	VE_SAFE_RELEASE(m_pkDefaultAdapter);
	VE_SAFE_RELEASE(m_pkDXGIFactory);

	D3D12GetDebugInterface = nullptr;
	D3D12CreateDevice = nullptr;
	D3D12SerializeRootSignature = nullptr;
	CreateDXGIFactory1 = nullptr;
	D3DCompile = nullptr;

	m_spD3D12 = nullptr;
	m_spDXGI = nullptr;
	m_spD3DCompiler = nullptr;
}
コード例 #2
0
//--------------------------------------------------------------------------
void D3D12RenderWindow::Init(D3D12Renderer& kRenderer) noexcept
{
	if ((!m_kNode.is_attach()) && m_spTargetWindow)
	{
		D3D12_COMMAND_QUEUE_DESC kQueueDesc = {};
		kQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
		kQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
		VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandQueue(&kQueueDesc, IID_PPV_ARGS(&m_pkCommandQueue)), S_OK);
		DXGI_SWAP_CHAIN_DESC kSwapChainDesc = {};
		kSwapChainDesc.BufferCount = D3D12Renderer::FRAME_COUNT;
		kSwapChainDesc.BufferDesc.Width = m_spTargetWindow->GetWidth();
		kSwapChainDesc.BufferDesc.Height = m_spTargetWindow->GetHeight();
		kSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;
		kSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		kSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		kSwapChainDesc.OutputWindow = (HWND)(m_spTargetWindow->GetNativeHandle());
		kSwapChainDesc.SampleDesc.Count = 1;
		kSwapChainDesc.Windowed = TRUE;
		IDXGISwapChain* pkSwapChain;
		VE_ASSERT_GE(kRenderer.m_pkDXGIFactory->CreateSwapChain(m_pkCommandQueue, &kSwapChainDesc, &pkSwapChain), S_OK);
		VE_ASSERT_GE(pkSwapChain->QueryInterface(IID_PPV_ARGS(&m_pkSwapChain)), S_OK);
		VE_SAFE_RELEASE(pkSwapChain);
		VE_ASSERT(m_pkCommandQueue && m_pkSwapChain);
		for (uint32_t i(0); i < D3D12Renderer::FRAME_COUNT; ++i)
		{
			FrameCache& kFrame = m_akFrameCache[i];
			VE_ASSERT_GE(m_pkSwapChain->GetBuffer(i, IID_PPV_ARGS(&kFrame.m_pkBufferResource)), S_OK);
			kFrame.m_hHandle.ptr = kRenderer.m_kRTVHeap.GetCPUStart().ptr + kRenderer.m_kRTVHeap.Alloc();
			kRenderer.m_pkDevice->CreateRenderTargetView(
				kFrame.m_pkBufferResource, nullptr, kFrame.m_hHandle);
			VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator(
				D3D12_COMMAND_LIST_TYPE_DIRECT,
				IID_PPV_ARGS(&kFrame.m_pkDirectAllocator)), S_OK);
			VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator(
				D3D12_COMMAND_LIST_TYPE_BUNDLE,
				IID_PPV_ARGS(&kFrame.m_pkBundleAllocator)), S_OK);
			kFrame.m_u64FenceValue = 0;

			VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT,
				kFrame.m_pkDirectAllocator, nullptr, IID_PPV_ARGS(&kFrame.m_pkTestList)), S_OK);
			VE_ASSERT_GE(kFrame.m_pkTestList->Close(), S_OK);
		}

		m_u64FenceValue = 0;
		VE_ASSERT_GE(kRenderer.m_pkDevice->CreateFence(m_u64FenceValue++,
			D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pkFence)), S_OK);
		m_kFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
		VE_ASSERT(m_kFenceEvent);
		const uint64_t u64FenceToWaitFor = m_u64FenceValue++;
		VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, u64FenceToWaitFor), S_OK);
		VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(u64FenceToWaitFor, m_kFenceEvent), S_OK);
		WaitForSingleObject(m_kFenceEvent, INFINITE);
		m_u32FramePtr = m_pkSwapChain->GetCurrentBackBufferIndex();
		m_u64FrameIndex = 0;

		m_spTargetWindow->Show();

		kRenderer.m_kRenderWindowList.attach_back(m_kNode);
	}
}
コード例 #3
0
//--------------------------------------------------------------------------
void VeRenderWindowD3D12::ResizeBundleList(VeSizeT stNum) noexcept
{
	for (VeInt32 i(0); i < VeRendererD3D12::FRAME_COUNT; ++i)
	{
		FrameCache& kFrame = m_akFrameCache[i];
		VE_ASSERT_GE(kFrame.m_pkBundleAllocator->Reset(), S_OK);
		VeSizeT stCurrentNum = kFrame.m_kBundleCommandList.size();
		if (stNum >= stCurrentNum)
		{
			for (auto& list : kFrame.m_kBundleCommandList)
			{
				VE_ASSERT_GE(list->Reset(kFrame.m_pkBundleAllocator, nullptr), S_OK);
			}
			kFrame.m_kBundleCommandList.resize(stNum);
			VeRendererD3D12& kRenderer = *VeMemberCast(
				&VeRendererD3D12::m_kRenderWindowList, m_kNode.get_list());
			for (VeSizeT i(stCurrentNum); i < stNum; ++i)
			{
				VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandList(0,
					D3D12_COMMAND_LIST_TYPE_BUNDLE, kFrame.m_pkBundleAllocator,
					nullptr, IID_PPV_ARGS(&kFrame.m_kBundleCommandList[i])), S_OK);
			}
		}
		else if (stNum < stCurrentNum)
		{
			for (VeSizeT i(stNum); i < stCurrentNum; ++i)
			{
				VE_ASSERT_GE(kFrame.m_kBundleCommandList[i]->Close(), S_OK);
				VE_SAFE_RELEASE(kFrame.m_kBundleCommandList[i]);
			}
			kFrame.m_kBundleCommandList.resize(stNum);
		}
	}	
}
コード例 #4
0
//--------------------------------------------------------------------------
void D3D12RenderWindow::Term() noexcept
{
	if (m_kNode.is_attach())
	{
		D3D12Renderer& kRenderer = *vtd::member_cast(
			&D3D12Renderer::m_kRenderWindowList, m_kNode.get_list());

		const uint64_t u64LastCompleted = m_pkFence->GetCompletedValue();
		VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, m_u64FenceValue), S_OK);
		if (u64LastCompleted < m_u64FenceValue)
		{
			VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(m_u64FenceValue, m_kFenceEvent), S_OK);
			WaitForSingleObject(m_kFenceEvent, INFINITE);
		}
		CloseHandle(m_kFenceEvent);
		VE_SAFE_RELEASE(m_pkFence);

		for (auto& kFrame : m_akFrameCache)
		{
			VE_SAFE_RELEASE(kFrame.m_pkTestList);

			for (auto& list : kFrame.m_kDirectCommandList)
			{
				VE_SAFE_RELEASE(list);
			}
			VE_SAFE_RELEASE(kFrame.m_pkDirectAllocator);
			kFrame.m_kDirectCommandList.clear();
			for (auto& list : kFrame.m_kBundleCommandList)
			{
				VE_SAFE_RELEASE(list);
			}
			VE_SAFE_RELEASE(kFrame.m_pkBundleAllocator);
			kFrame.m_kBundleCommandList.clear();
			kRenderer.m_kRTVHeap.Free((uint32_t)(kFrame.m_hHandle.ptr - kRenderer.m_kRTVHeap.GetCPUStart().ptr));
			VE_SAFE_RELEASE(kFrame.m_pkBufferResource);
		}
		VE_SAFE_RELEASE(m_pkCommandQueue);
		VE_SAFE_RELEASE(m_pkSwapChain);
		m_kNode.detach();
	}
}
コード例 #5
0
//--------------------------------------------------------------------------
void VeRenderWindowD3D12::Term() noexcept
{
	if (m_kNode.is_attach())
	{
		VeRendererD3D12& kRenderer = *VeMemberCast(
			&VeRendererD3D12::m_kRenderWindowList, m_kNode.get_list());

		const VeUInt64 u64LastCompleted = m_pkFence->GetCompletedValue();
		VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, m_u64FenceValue), S_OK);
		if (u64LastCompleted < m_u64FenceValue)
		{
			VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(m_u64FenceValue, m_kFenceEvent), S_OK);
			WaitForSingleObject(m_kFenceEvent, INFINITE);
		}
		CloseHandle(m_kFenceEvent);
		VE_SAFE_RELEASE(m_pkFence);

		m_kResourceMap.clear();
		m_kRecorderList.clear();
		m_kCameraList.clear();
		m_kProcessList.clear();

		for (VeInt32 i(VeRendererD3D12::FRAME_COUNT - 1); i >= 0; --i)
		{
			FrameCache& kFrame = m_akFrameCache[i];
			for (auto& list : kFrame.m_kDirectCommandList)
			{
				VE_SAFE_RELEASE(list);
			}
			VE_SAFE_RELEASE(kFrame.m_pkDirectAllocator);
			kFrame.m_kDirectCommandList.clear();
			for (auto& list : kFrame.m_kBundleCommandList)
			{
				VE_SAFE_RELEASE(list);
			}
			VE_SAFE_RELEASE(kFrame.m_pkBundleAllocator);
			kFrame.m_kBundleCommandList.clear();
			kRenderer.m_kRTVHeap.Free(kFrame.m_hHandle.ptr - kRenderer.m_kRTVHeap.GetCPUStart().ptr);
			VE_SAFE_RELEASE(kFrame.m_pkBufferResource);
		}
		VE_SAFE_RELEASE(m_pkCommandQueue);
		VE_SAFE_RELEASE(m_pkSwapChain);
		m_kNode.detach();
	}	
}
コード例 #6
0
ファイル: D3D12Renderer.cpp プロジェクト: Napoleon314/Venus3D
//--------------------------------------------------------------------------
void D3D12Renderer::Init()
{
	m_spD3D12 = VE_NEW VeSharedLib(LIB_D3D12);
	if (!m_spD3D12->Load())
	{
		THROW("Failed to load " LIB_D3D12 ".");
	}
	m_spDXGI = VE_NEW VeSharedLib(LIB_DXGI);
	if (!m_spDXGI->Load())
	{
		THROW("Failed to load " LIB_DXGI ".");
	}
	m_spD3DCompiler = VE_NEW VeSharedLib(LIB_D3DCOMPLIER);
	if (!m_spD3DCompiler->Load())
	{
		THROW("Failed to load " LIB_D3DCOMPLIER ".");
	}

	D3D12GetDebugInterface = (decltype(D3D12GetDebugInterface))
		m_spD3D12->GetProc("D3D12GetDebugInterface");
	if (!D3D12GetDebugInterface)
	{
		THROW("Failed to fetch function D3D12GetDebugInterface.");
	}

	D3D12CreateDevice = (decltype(D3D12CreateDevice))
		m_spD3D12->GetProc("D3D12CreateDevice");
	if (!D3D12CreateDevice)
	{
		THROW("Failed to fetch function D3D12CreateDevice.");
	}

	D3D12SerializeRootSignature = (decltype(D3D12SerializeRootSignature))
		m_spD3D12->GetProc("D3D12SerializeRootSignature");
	if (!D3D12SerializeRootSignature)
	{
		THROW("Failed to fetch function D3D12SerializeRootSignature.");
	}

	CreateDXGIFactory1 = (decltype(CreateDXGIFactory1))
		m_spDXGI->GetProc("CreateDXGIFactory1");
	if (!CreateDXGIFactory1)
	{
		THROW("Failed to fetch function CreateDXGIFactory1.");
	}

	D3DCompile = (decltype(D3DCompile))
		m_spD3DCompiler->GetProc("D3DCompile");
	if (!D3DCompile)
	{
		THROW("Failed to fetch function D3DCompile.");
	}

#	ifdef VE_DEBUG
	{
		ID3D12Debug* pkDebugController(nullptr);
		if (SUCCEEDED(D3D12GetDebugInterface(IID_PPV_ARGS(&pkDebugController))))
		{
			pkDebugController->EnableDebugLayer();
		}
		VE_SAFE_RELEASE(pkDebugController);
	}
#	endif

	if (VE_FAILED(CreateDXGIFactory1(IID_PPV_ARGS(&m_pkDXGIFactory))))
	{
		THROW("Failed to create DXGI factory.");
	}

	if (m_pkDXGIFactory->EnumAdapters1(0, &m_pkDefaultAdapter) == DXGI_ERROR_NOT_FOUND)
	{
		THROW("Failed to get main adapter.");
	}

	if (VE_FAILED(D3D12CreateDevice(m_pkDefaultAdapter,
		D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_pkDevice))))
	{
		THROW("Failed to create d3d12 device.");
	}

	m_kRTVHeap.Init(m_pkDevice);
	m_kDSVHeap.Init(m_pkDevice);
	m_kSRVHeap.Init(m_pkDevice);

	VeCoreLogI("D3D12Renderer created successfully.");
}
コード例 #7
0
//--------------------------------------------------------------------------
void VeRenderWindowD3D12::Init(VeRendererD3D12& kRenderer) noexcept
{
	if ((!m_kNode.is_attach()) && m_spTargetWindow)
	{
		D3D12_COMMAND_QUEUE_DESC kQueueDesc = {};
		kQueueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
		kQueueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
		if (FAILED(kRenderer.m_pkDevice->CreateCommandQueue(&kQueueDesc,
			IID_PPV_ARGS(&m_pkCommandQueue))))
		{
			VE_SAFE_RELEASE(m_pkCommandQueue);
			VE_SAFE_RELEASE(m_pkSwapChain);
			return;
		}
		DXGI_SWAP_CHAIN_DESC kSwapChainDesc = {};
		kSwapChainDesc.BufferCount = VeRendererD3D12::FRAME_COUNT;
		kSwapChainDesc.BufferDesc.Width = m_spTargetWindow->GetWidth();
		kSwapChainDesc.BufferDesc.Height = m_spTargetWindow->GetHeight();
		kSwapChainDesc.BufferDesc.Format = DXGI_FORMAT_R10G10B10A2_UNORM;			
		kSwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		kSwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
		kSwapChainDesc.OutputWindow = m_spTargetWindow->GetWMInfo().win.window;
		kSwapChainDesc.SampleDesc.Count = 1;
		kSwapChainDesc.Windowed = TRUE;
		IDXGISwapChain* pkSwapChain;
		if (FAILED(kRenderer.m_pkDXGIFactory->CreateSwapChain(m_pkCommandQueue,
			&kSwapChainDesc, &pkSwapChain)))
		{
			VE_SAFE_RELEASE(m_pkCommandQueue);
			VE_SAFE_RELEASE(pkSwapChain);
			return;
		}
		if (FAILED(pkSwapChain->QueryInterface(IID_PPV_ARGS(&m_pkSwapChain))))
		{
			VE_SAFE_RELEASE(m_pkCommandQueue);
			VE_SAFE_RELEASE(pkSwapChain);
			VE_SAFE_RELEASE(m_pkSwapChain);
			return;
		}
		else
		{
			VE_SAFE_RELEASE(pkSwapChain);
		}
		VE_ASSERT(m_pkCommandQueue && m_pkSwapChain);
		for (VeInt32 i(0); i < VeRendererD3D12::FRAME_COUNT; ++i)
		{
			FrameCache& kFrame = m_akFrameCache[i];
			VE_ASSERT_GE(m_pkSwapChain->GetBuffer(i, IID_PPV_ARGS(&kFrame.m_pkBufferResource)), S_OK);
			kFrame.m_hHandle.ptr = kRenderer.m_kRTVHeap.GetCPUStart().ptr + kRenderer.m_kRTVHeap.Alloc();
			kRenderer.m_pkDevice->CreateRenderTargetView(
				kFrame.m_pkBufferResource, nullptr, kFrame.m_hHandle);
			VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator(
				D3D12_COMMAND_LIST_TYPE_DIRECT,
				IID_PPV_ARGS(&kFrame.m_pkDirectAllocator)), S_OK);
			VE_ASSERT_GE(kRenderer.m_pkDevice->CreateCommandAllocator(
				D3D12_COMMAND_LIST_TYPE_BUNDLE,
				IID_PPV_ARGS(&kFrame.m_pkBundleAllocator)), S_OK);
			kFrame.m_u64FenceValue = 0;
		}		

		m_u64FenceValue = 0;
		VE_ASSERT_GE(kRenderer.m_pkDevice->CreateFence(m_u64FenceValue++,
			D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_pkFence)), S_OK);
		m_kFenceEvent = CreateEventEx(nullptr, FALSE, FALSE, EVENT_ALL_ACCESS);
		VE_ASSERT(m_kFenceEvent);
		const VeUInt64 u64FenceToWaitFor = m_u64FenceValue++;
		VE_ASSERT_GE(m_pkCommandQueue->Signal(m_pkFence, u64FenceToWaitFor), S_OK);
		VE_ASSERT_GE(m_pkFence->SetEventOnCompletion(u64FenceToWaitFor, m_kFenceEvent), S_OK);
		WaitForSingleObject(m_kFenceEvent, INFINITE);
		m_u32FrameIndex = m_pkSwapChain->GetCurrentBackBufferIndex();
		kRenderer.m_kRenderWindowList.attach_back(m_kNode);
	}

	m_kViewport.TopLeftX = 0;
	m_kViewport.TopLeftY = 0;
	m_kViewport.Width = m_spTargetWindow->GetWidth();
	m_kViewport.Height = m_spTargetWindow->GetHeight();
	m_kViewport.MinDepth = 0.0f;
	m_kViewport.MaxDepth = 1.0f;

	m_kScissorRect.left = 0;
	m_kScissorRect.right = m_spTargetWindow->GetWidth();
	m_kScissorRect.top = 0;
	m_kScissorRect.bottom = m_spTargetWindow->GetHeight();

	{
		m_vertexBufferView.BufferLocation = kRenderer.m_kRenderBufferList.get_tail_node()->m_Content->m_pkResource->GetGPUVirtualAddress();
		m_vertexBufferView.StrideInBytes = sizeof(VE_FLOAT3);
		m_vertexBufferView.SizeInBytes = kRenderer.m_kRenderBufferList.get_head_node()->m_Content->GetSize();
	}
}
コード例 #8
0
ファイル: HLSLCompiler.cpp プロジェクト: snailwork/Texas-cs
void Compile(VeChar8* pcFileName, VeChar8* pcDstDir)
{
	VeChar8* pcFile = VeStrrchr(pcFileName, '/');
	VeSizeT stNum = pcFile - pcFileName;
	VeChar8 acBuffer[2048];
	VeMemcpy(acBuffer, pcFileName, stNum);
	acBuffer[stNum] = 0;
	++pcFile;
	VeFileDir kFile(acBuffer);
	VeChar8* pcContent;
	VeChar8* pcTemp = VeStrtok(pcDstDir, "/", &pcContent);
	VE_ASSERT(pcTemp && *pcTemp);
	VeFileDir kDstFile(pcTemp);
	pcTemp = VeStrtok(NULL, "/", &pcContent);
	while(pcTemp && *pcTemp)
	{
		kDstFile.Change(pcTemp);
		pcTemp = VeStrtok(NULL, "/", &pcContent);
	}
	

	VeBinaryIStreamPtr spStream = kFile.OpenSync(pcFile);
	VE_ASSERT(spStream);
	VeXMLDocument kDoc;
	(*spStream) >> kDoc;
	VE_ASSERT(!kDoc.Error());
	VeXMLElement* pkRoot = kDoc.RootElement();
	VeXMLElement* pkGroup = pkRoot->FirstChildElement("Group");
	while(pkGroup)
	{
		VeXMLElement* pkShader = pkGroup->FirstChildElement();
		while(pkShader)
		{
			const VeChar8* pcName = pkShader->Value();
			const VeChar8* pcSrc = pkShader->GetAttribute("src");
			const VeChar8* pcEntry = pkShader->GetAttribute("entry");
			VeStringA kFile(acBuffer);
			kFile += '/';
			kFile += pcSrc;
			VeVector<const VeChar8*> kProfileList;
			VeXMLElement* pkProfile = pkShader->FirstChildElement("Profile");
			while(pkProfile)
			{
				const VeChar8* pcProfile = pkProfile->GetAttribute("value");
				kProfileList.PushBack(pcProfile);
				pkProfile = pkProfile->NextSiblingElement("Profile");
			}
			VeVector<D3D_SHADER_MACRO> kMacroList;
			VeXMLElement* pkMacro = pkShader->FirstChildElement("Macro");
			while(pkMacro)
			{
				D3D_SHADER_MACRO kMac;
				kMac.Name = pkMacro->GetAttribute("name");
				kMac.Definition = pkMacro->GetAttribute("define");
				kMacroList.PushBack(kMac);
				pkMacro = pkMacro->NextSiblingElement("Macro");
			}
			D3D_SHADER_MACRO kLast = {NULL, NULL};
			kMacroList.PushBack(kLast);
			for(VeVector<const VeChar8*>::iterator it = kProfileList.Begin(); it != kProfileList.End(); ++it)
			{
				HRESULT hRes = S_OK;
				ID3DBlob* pkOut;
				ID3DBlob* pkErrorBlob;
				hRes = D3DX11CompileFromFile(kFile, kMacroList.Begin(), NULL, pcEntry, *it, 
					D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_OPTIMIZATION_LEVEL3 | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR,
					0, NULL, &pkOut, &pkErrorBlob, NULL);
				if(VE_FAILED(hRes))
				{
					if(pkErrorBlob)
					{
						VE_LOG_EString("HLSLComplier", (VeChar8*)pkErrorBlob->GetBufferPointer());
					}
				}
				else
				{
					VeStringA kOutputName(pcName);
					kOutputName += '.';
					kOutputName += *it;
					VeMemoryOStreamPtr spOutputStream = VE_NEW VeMemoryOStream();
					spOutputStream->AddBlob(pkOut->GetBufferPointer(), pkOut->GetBufferSize());
					kDstFile.WriteAsync(kOutputName, spOutputStream, g_kWriteDelegate);
				}
				VE_SAFE_RELEASE(pkOut);
				VE_SAFE_RELEASE(pkErrorBlob);
			}
			pkShader = pkShader->NextSiblingElement();
		}
		pkGroup = pkGroup->NextSiblingElement("Group");
	}
}