Beispiel #1
0
	void GUIWidget::_updateLayout()
	{
		bs_frame_mark();

		// Determine dirty contents and layouts
		FrameStack<GUIElementBase*> todo;
		todo.push(mPanel);

		while (!todo.empty())
		{
			GUIElementBase* currentElem = todo.top();
			todo.pop();

			if (currentElem->_isDirty())
			{
				GUIElementBase* updateParent = currentElem->_getUpdateParent();
				assert(updateParent != nullptr || currentElem == mPanel);

				if (updateParent != nullptr)
					_updateLayout(updateParent);
				else // Must be root panel
					_updateLayout(mPanel);
			}
			else
			{
				UINT32 numChildren = currentElem->_getNumChildren();
				for (UINT32 i = 0; i < numChildren; i++)
					todo.push(currentElem->_getChild(i));
			}
		}

		bs_frame_clear();
	}
Beispiel #2
0
	void GUIInputTool::updateText(const GUIElement* element, const TEXT_SPRITE_DESC& textDesc)
	{
		mElement = element;
		mTextDesc = textDesc;
		mNumChars = UTF8::count(mTextDesc.text);

		mLineDescs.clear();

		bs_frame_mark();
		{
			const U32String utf32text = UTF8::toUTF32(mTextDesc.text);
			TextData<FrameAlloc> textData(utf32text, mTextDesc.font, mTextDesc.fontSize,
				mTextDesc.width, mTextDesc.height, mTextDesc.wordWrap, mTextDesc.wordBreak);

			UINT32 numLines = textData.getNumLines();
			UINT32 numPages = textData.getNumPages();

			mNumQuads = 0;
			for (UINT32 i = 0; i < numPages; i++)
				mNumQuads += textData.getNumQuadsForPage(i);

			if (mQuads != nullptr)
				bs_delete(mQuads);

			mQuads = bs_newN<Vector2>(mNumQuads * 4);

			TextSprite::genTextQuads(textData, mTextDesc.width, mTextDesc.height, mTextDesc.horzAlign, mTextDesc.vertAlign, mTextDesc.anchor,
				mQuads, nullptr, nullptr, mNumQuads);

			// Store cached line data
			UINT32 curCharIdx = 0;
			UINT32 curLineIdx = 0;

			Vector2I* alignmentOffsets = bs_frame_new<Vector2I>(numLines);
			TextSprite::getAlignmentOffsets(textData, mTextDesc.width, mTextDesc.height, mTextDesc.horzAlign, 
				mTextDesc.vertAlign, alignmentOffsets);

			for (UINT32 i = 0; i < numLines; i++)
			{
				const TextDataBase::TextLine& line = textData.getLine(i);

				// Line has a newline char only if it wasn't created by word wrap and it isn't the last line
				bool hasNewline = line.hasNewlineChar() && (curLineIdx != (numLines - 1));

				UINT32 startChar = curCharIdx;
				UINT32 endChar = curCharIdx + line.getNumChars() + (hasNewline ? 1 : 0);
				UINT32 lineHeight = line.getYOffset();
				INT32 lineYStart = alignmentOffsets[curLineIdx].y;

				GUIInputLineDesc lineDesc(startChar, endChar, lineHeight, lineYStart, hasNewline);
				mLineDescs.push_back(lineDesc);

				curCharIdx = lineDesc.getEndChar();
				curLineIdx++;
			}

			bs_frame_delete(alignmentOffsets);
		}
		bs_frame_clear();
	}
Beispiel #3
0
	Vector2I GUIHelper::calcOptimalContentsSize(const String& text, const GUIElementStyle& style, const 
		GUIDimensions& dimensions)
	{
		UINT32 wordWrapWidth = 0;

		if(style.wordWrap)
			wordWrapWidth = dimensions.maxWidth;

		UINT32 contentWidth = style.margins.left + style.margins.right + style.contentOffset.left + style.contentOffset.right;
		UINT32 contentHeight = style.margins.top + style.margins.bottom + style.contentOffset.top + style.contentOffset.bottom;

		if(style.font != nullptr && !text.empty())
		{
			bs_frame_mark();

			const U32String utf32text = UTF8::toUTF32(text);
			TextData<FrameAlloc> textData(utf32text, style.font, style.fontSize, wordWrapWidth, 0, style.wordWrap);

			contentWidth += textData.getWidth();
			contentHeight += textData.getNumLines() * textData.getLineHeight(); 

			bs_frame_clear();
		}

		return Vector2I(contentWidth, contentHeight);
	}
Beispiel #4
0
	void GUIWidget::_updateLayout(GUIElementBase* elem)
	{
		GUIElementBase* parent = elem->_getParent();
		bool isPanelOptimized = parent != nullptr && parent->_getType() == GUIElementBase::Type::Panel;

		GUIElementBase* updateParent = nullptr;

		if (isPanelOptimized)
			updateParent = parent;
		else
			updateParent = elem;

		// For GUIPanel we can do a an optimization and update only the element in question instead
		// of all the children
		if (isPanelOptimized)
		{
			GUIPanel* panel = static_cast<GUIPanel*>(updateParent);

			GUIElementBase* dirtyElement = elem;
			dirtyElement->_updateOptimalLayoutSizes();

			LayoutSizeRange elementSizeRange = panel->_getElementSizeRange(dirtyElement);
			Rect2I elementArea = panel->_getElementArea(panel->_getLayoutData().area, dirtyElement, elementSizeRange);

			GUILayoutData childLayoutData = panel->_getLayoutData();
			panel->_updateDepthRange(childLayoutData);
			childLayoutData.area = elementArea;

			panel->_updateChildLayout(dirtyElement, childLayoutData);
		}
		else
		{
			GUILayoutData childLayoutData = updateParent->_getLayoutData();
			updateParent->_updateLayout(childLayoutData);
		}
		
		// Mark dirty contents
		bs_frame_mark();
		{
			FrameStack<GUIElementBase*> todo;
			todo.push(elem);

			while (!todo.empty())
			{
				GUIElementBase* currentElem = todo.top();
				todo.pop();

				if (currentElem->_getType() == GUIElementBase::Type::Element)
					mDirtyContents.insert(static_cast<GUIElement*>(currentElem));

				currentElem->_markAsClean();

				UINT32 numChildren = currentElem->_getNumChildren();
				for (UINT32 i = 0; i < numChildren; i++)
					todo.push(currentElem->_getChild(i));
			}
		}
		bs_frame_clear();
	}
	void TextSprite::update(const TEXT_SPRITE_DESC& desc, UINT64 groupId)
	{
		bs_frame_mark();
		{
			TextData<FrameAlloc> textData(desc.text, desc.font, desc.fontSize, desc.width, desc.height, desc.wordWrap, desc.wordBreak);

			UINT32 numPages = textData.getNumPages();

			// Free all previous memory
			for (auto& cachedElem : mCachedRenderElements)
			{
				if (cachedElem.vertices != nullptr) mAlloc.free(cachedElem.vertices);
				if (cachedElem.uvs != nullptr) mAlloc.free(cachedElem.uvs);
				if (cachedElem.indexes != nullptr) mAlloc.free(cachedElem.indexes);
			}

			mAlloc.clear();

			// Resize cached mesh array to needed size
			if (mCachedRenderElements.size() != numPages)
				mCachedRenderElements.resize(numPages);

			// Actually generate a mesh
			UINT32 texPage = 0;
			for (auto& cachedElem : mCachedRenderElements)
			{
				UINT32 newNumQuads = textData.getNumQuadsForPage(texPage);

				cachedElem.vertices = (Vector2*)mAlloc.alloc(sizeof(Vector2) * newNumQuads * 4);
				cachedElem.uvs = (Vector2*)mAlloc.alloc(sizeof(Vector2) * newNumQuads * 4);
				cachedElem.indexes = (UINT32*)mAlloc.alloc(sizeof(UINT32) * newNumQuads * 6);
				cachedElem.numQuads = newNumQuads;

				const HTexture& tex = textData.getTextureForPage(texPage);

				SpriteMaterialInfo& matInfo = cachedElem.matInfo;
				matInfo.groupId = groupId;
				matInfo.texture = tex;
				matInfo.tint = desc.color;
				matInfo.type = SpriteMaterial::Text;

				texPage++;
			}

			// Calc alignment and anchor offsets and set final line positions
			for (UINT32 j = 0; j < numPages; j++)
			{
				SpriteRenderElement& renderElem = mCachedRenderElements[j];

				genTextQuads(j, textData, desc.width, desc.height, desc.horzAlign, desc.vertAlign, desc.anchor,
					renderElem.vertices, renderElem.uvs, renderElem.indexes, renderElem.numQuads);
			}
		}

		bs_frame_clear();

		updateBounds();
	}
Beispiel #6
0
	Vector2I GUIHelper::calcTextSize(const String& text, const HFont& font, UINT32 fontSize)
	{
		Vector2I size;
		if (font != nullptr)
		{
			bs_frame_mark();

			const U32String utf32text = UTF8::toUTF32(text);
			TextData<FrameAlloc> textData(utf32text, font, fontSize, 0, 0, false);

			size.x = textData.getWidth();
			size.y = textData.getNumLines() * textData.getLineHeight();

			bs_frame_clear();
		}

		return size;
	}
	UINT8* OggVorbisEncoder::PCMToOggVorbis(UINT8* samples, const AudioDataInfo& info, UINT32& size)
	{
		struct EncodedBlock
		{
			UINT8* data;
			UINT32 size;
		};

		Vector<EncodedBlock> blocks;
		UINT32 totalEncodedSize = 0;
		auto writeCallback = [&](UINT8* buffer, UINT32 size)
		{
			EncodedBlock newBlock;
			newBlock.data = bs_frame_alloc(size);
			newBlock.size = size;

			memcpy(newBlock.data, buffer, size);
			blocks.push_back(newBlock);
			totalEncodedSize += size;
		};

		bs_frame_mark();

		OggVorbisEncoder writer;
		writer.open(writeCallback, info.sampleRate, info.bitDepth, info.numChannels);

		writer.write(samples, info.numSamples);
		writer.close();

		UINT8* outSampleBuffer = (UINT8*)bs_alloc(totalEncodedSize);
		UINT32 offset = 0;
		for (auto& block : blocks)
		{
			memcpy(outSampleBuffer + offset, block.data, block.size);
			offset += block.size;

			bs_frame_free(block.data);
		}

		bs_frame_clear();
		
		size = totalEncodedSize;
		return outSampleBuffer;
	}
Beispiel #8
0
	void TriangleClipper2D::convertToMesh(const std::function<void(Vector2*, Vector2*, UINT32)>& writeCallback)
	{
		bs_frame_mark();
		{
			FrameVector<FrameVector<UINT32>> allFaces;
			getOrderedFaces(allFaces);

			// Note: Consider using Delaunay triangulation to avoid skinny triangles
			UINT32 numWritten = 0;
			assert(BUFFER_SIZE % 3 == 0);
			for (auto& face : allFaces)
			{
				for (UINT32 i = 0; i < (UINT32)face.size() - 2; i++)
				{
					const Vector3& v0 = mesh.verts[face[0]].point;
					const Vector3& v1 = mesh.verts[face[i + 1]].point;
					const Vector3& v2 = mesh.verts[face[i + 2]].point;

					vertexBuffer[numWritten] = Vector2(v0.x, v0.y);
					uvBuffer[numWritten] = mesh.verts[face[0]].uv;
					numWritten++;

					vertexBuffer[numWritten] = Vector2(v1.x, v1.y);
					uvBuffer[numWritten] = mesh.verts[face[i + 1]].uv;
					numWritten++;

					vertexBuffer[numWritten] = Vector2(v2.x, v2.y);
					uvBuffer[numWritten] = mesh.verts[face[i + 2]].uv;
					numWritten++;

					// Only need to check this here since we guarantee the buffer is in multiples of three
					if (numWritten >= BUFFER_SIZE)
					{
						writeCallback(vertexBuffer, uvBuffer, numWritten);
						numWritten = 0;
					}
				}
			}

			if (numWritten > 0)
				writeCallback(vertexBuffer, uvBuffer, numWritten);
		}
		bs_frame_clear();
	}
Beispiel #9
0
	bool Resource::areDependenciesLoaded() const
	{
		bs_frame_mark();

		bool areLoaded = true;
		{
			FrameVector<HResource> dependencies;
			getResourceDependencies(dependencies);

			for (auto& dependency : dependencies)
			{
				if (dependency != nullptr && !dependency.isLoaded())
				{
					areLoaded = false;
					break;
				}
			}
		}

		bs_frame_clear();
		return areLoaded;
	}
Beispiel #10
0
	Win32Window::~Win32Window()
	{
		if (m->hWnd && !m->isExternal)
		{
			// Handle modal windows
			bs_frame_mark();
			
			{
				FrameVector<HWND> windowsToEnable;
				{
					Lock lock(sWindowsMutex);

					// Hidden dependency: All windows must be re-enabled before a window is destroyed, otherwise the incorrect
					// window in the z order will be activated.
					bool reenableWindows = false;
					if (!sModalWindowStack.empty())
					{
						// Start from back because the most common case is closing the top-most modal window
						for (auto iter = sModalWindowStack.rbegin(); iter != sModalWindowStack.rend(); ++iter)
						{
							if (*iter == this)
							{
								auto iterFwd = std::next(iter).base(); // erase doesn't accept reverse iter, so convert

								sModalWindowStack.erase(iterFwd);
								break;
							}
						}

						if (!sModalWindowStack.empty()) // Enable next modal window
						{
							Win32Window* curModalWindow = sModalWindowStack.back();
							windowsToEnable.push_back(curModalWindow->m->hWnd);
						}
						else
							reenableWindows = true; // No more modal windows, re-enable any remaining window
					}

					if (reenableWindows)
					{
						for (auto& window : sAllWindows)
							windowsToEnable.push_back(window->m->hWnd);
					}
				}

				for(auto& entry : windowsToEnable)
					EnableWindow(entry, TRUE);
			}
			bs_frame_clear();

			DestroyWindow(m->hWnd);
		}

		{
			Lock lock(sWindowsMutex);

			auto iterFind = std::find(sAllWindows.begin(), sAllWindows.end(), this);
			sAllWindows.erase(iterFind);
		}

		bs_delete(m);
	}
Beispiel #11
0
	Win32Window::Win32Window(const WINDOW_DESC& desc)
	{
		m = bs_new<Pimpl>();
		m->isModal = desc.modal;
		m->isHidden = desc.hidden;

		HMONITOR hMonitor = desc.monitor;
		if (!desc.external)
		{
			m->style = WS_CLIPCHILDREN;

			INT32 left = desc.left;
			INT32 top = desc.top;

			// If we didn't specified the adapter index, or if we didn't find it
			if (hMonitor == nullptr)
			{
				POINT windowAnchorPoint;

				// Fill in anchor point.
				windowAnchorPoint.x = left;
				windowAnchorPoint.y = top;

				// Get the nearest monitor to this window.
				hMonitor = MonitorFromPoint(windowAnchorPoint, MONITOR_DEFAULTTOPRIMARY);
			}

			// Get the target monitor info
			MONITORINFO monitorInfo;
			memset(&monitorInfo, 0, sizeof(MONITORINFO));
			monitorInfo.cbSize = sizeof(MONITORINFO);
			GetMonitorInfo(hMonitor, &monitorInfo);

			UINT32 width = desc.width;
			UINT32 height = desc.height;

			// No specified top left -> Center the window in the middle of the monitor
			if (left == -1 || top == -1)
			{
				int screenw = monitorInfo.rcWork.right - monitorInfo.rcWork.left;
				int screenh = monitorInfo.rcWork.bottom - monitorInfo.rcWork.top;

				// clamp window dimensions to screen size
				int outerw = (int(width) < screenw) ? int(width) : screenw;
				int outerh = (int(height) < screenh) ? int(height) : screenh;

				if (left == -1)
					left = monitorInfo.rcWork.left + (screenw - outerw) / 2;
				else if (hMonitor != nullptr)
					left += monitorInfo.rcWork.left;

				if (top == -1)
					top = monitorInfo.rcWork.top + (screenh - outerh) / 2;
				else if (hMonitor != nullptr)
					top += monitorInfo.rcWork.top;
			}
			else if (hMonitor != nullptr)
			{
				left += monitorInfo.rcWork.left;
				top += monitorInfo.rcWork.top;
			}

			if (!desc.fullscreen)
			{
				if (desc.parent)
				{
					if (desc.toolWindow)
						m->styleEx = WS_EX_TOOLWINDOW;
					else
						m->style |= WS_CHILD;
				}
				else
				{
					if (desc.toolWindow)
						m->styleEx = WS_EX_TOOLWINDOW;
				}

				if (!desc.parent || desc.toolWindow)
				{
					if(desc.showTitleBar)
					{
						if(desc.showBorder || desc.allowResize)
							m->style |= WS_OVERLAPPEDWINDOW;
						else
							m->style |= WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_MAXIMIZEBOX;
					}
					else
					{
						if(desc.showBorder || desc.allowResize)
							m->style |= WS_POPUP | WS_BORDER;
						else
							m->style |= WS_POPUP;
					}
				}

				if (!desc.outerDimensions)
				{
					// Calculate window dimensions required to get the requested client area
					RECT rect;
					SetRect(&rect, 0, 0, width, height);
					AdjustWindowRect(&rect, m->style, false);
					width = rect.right - rect.left;
					height = rect.bottom - rect.top;

					// Clamp width and height to the desktop dimensions
					int screenw = GetSystemMetrics(SM_CXSCREEN);
					int screenh = GetSystemMetrics(SM_CYSCREEN);

					if ((int)width > screenw)
						width = screenw;

					if ((int)height > screenh)
						height = screenh;

					if (left < 0)
						left = (screenw - width) / 2;

					if (top < 0)
						top = (screenh - height) / 2;
				}

				if (desc.backgroundPixels != nullptr)
					m->styleEx |= WS_EX_LAYERED;
			}
			else
			{
				m->style |= WS_POPUP;
				top = 0;
				left = 0;
			}

			UINT classStyle = 0;
			if (desc.enableDoubleClick)
				classStyle |= CS_DBLCLKS;

			// Register the window class
			WNDCLASS wc = { classStyle, desc.wndProc, 0, 0, desc.module,
				LoadIcon(nullptr, IDI_APPLICATION), LoadCursor(nullptr, IDC_ARROW),
				(HBRUSH)GetStockObject(BLACK_BRUSH), 0, "Win32Wnd" };

			RegisterClass(&wc);

			// Create main window
			m->hWnd = CreateWindowEx(m->styleEx, "Win32Wnd", desc.title.c_str(), m->style,
				left, top, width, height, desc.parent, nullptr, desc.module, desc.creationParams);
			m->isExternal = false;
		}
		else
		{
			m->hWnd = desc.external;
			m->isExternal = true;
		}

		RECT rect;
		GetWindowRect(m->hWnd, &rect);
		m->top = rect.top;
		m->left = rect.left;

		GetClientRect(m->hWnd, &rect);
		m->width = rect.right;
		m->height = rect.bottom;

		// Set background, if any
		if (desc.backgroundPixels != nullptr)
		{
			HBITMAP backgroundBitmap = Win32PlatformUtility::createBitmap(
				desc.backgroundPixels, desc.backgroundWidth, desc.backgroundHeight, true);

			HDC hdcScreen = GetDC(nullptr);
			HDC hdcMem = CreateCompatibleDC(hdcScreen);
			HBITMAP hOldBitmap = (HBITMAP)SelectObject(hdcMem, backgroundBitmap);

			BLENDFUNCTION blend = { 0 };
			blend.BlendOp = AC_SRC_OVER;
			blend.SourceConstantAlpha = 255;
			blend.AlphaFormat = AC_SRC_ALPHA;

			POINT origin;
			origin.x = m->left;
			origin.y = m->top;

			SIZE size;
			size.cx = m->width;
			size.cy = m->height;

			POINT zero = { 0 };

			UpdateLayeredWindow(m->hWnd, hdcScreen, &origin, &size,
				hdcMem, &zero, RGB(0, 0, 0), &blend, desc.alphaBlending ? ULW_ALPHA : ULW_OPAQUE);

			SelectObject(hdcMem, hOldBitmap);
			DeleteDC(hdcMem);
			ReleaseDC(nullptr, hdcScreen);
		}

		// Handle modal windows
		bs_frame_mark();

		{
			FrameVector<HWND> windowsToDisable;
			FrameVector<HWND> windowsToBringToFront;
			{
				Lock lock(sWindowsMutex);

				if (m->isModal)
				{
					if (!sModalWindowStack.empty())
					{
						Win32Window* curModalWindow = sModalWindowStack.back();
						windowsToDisable.push_back(curModalWindow->m->hWnd);
					}
					else
					{
						for (auto& window : sAllWindows)
							windowsToDisable.push_back(window->m->hWnd);
					}

					sModalWindowStack.push_back(this);
				}
				else
				{
					// A non-modal window was opened while another modal one is open,
					// immediately deactivate it and make sure the modal windows stay on top.
					if (!sModalWindowStack.empty())
					{
						windowsToDisable.push_back(m->hWnd);

						for (auto window : sModalWindowStack)
							windowsToBringToFront.push_back(window->m->hWnd);
					}
				}

				sAllWindows.push_back(this);
			}

			for(auto& entry : windowsToDisable)
				EnableWindow(entry, FALSE);

			for (auto& entry : windowsToBringToFront)
				BringWindowToTop(entry);
		}

		if(desc.hidden)
			setHidden(true);

		bs_frame_clear();
	}
	void CoreObjectManager::syncDownload(FrameAlloc* allocator)
	{
		Lock lock(mObjectsMutex);

		mCoreSyncData.push_back(CoreStoredSyncData());
		CoreStoredSyncData& syncData = mCoreSyncData.back();

		syncData.alloc = allocator;
		
		// Add all objects dependant on the dirty objects
		bs_frame_mark();
		{
			FrameSet<CoreObject*> dirtyDependants;
			for (auto& objectData : mDirtyObjects)
			{
				auto iterFind = mDependants.find(objectData.first);
				if (iterFind != mDependants.end())
				{
					const Vector<CoreObject*>& dependants = iterFind->second;
					for (auto& dependant : dependants)
					{
						if (!dependant->isCoreDirty())
						{
							dependant->mCoreDirtyFlags |= 0xFFFFFFFF; // To ensure the loop below doesn't skip it
							dirtyDependants.insert(dependant);
						}
					}
				}
			}

			for (auto& dirtyDependant : dirtyDependants)
			{
				UINT64 id = dirtyDependant->getInternalID();

				mDirtyObjects[id] = { dirtyDependant, -1 };
			}
		}

		bs_frame_clear();
		
		// Order in which objects are recursed in matters, ones with lower ID will have been created before
		// ones with higher ones and should be updated first.
		for (auto& objectData : mDirtyObjects)
		{
			std::function<void(CoreObject*)> syncObject = [&](CoreObject* curObj)
			{
				if (!curObj->isCoreDirty())
					return; // We already processed it as some other object's dependency

				// Sync dependencies before dependants
				// Note: I don't check for recursion. Possible infinite loop if two objects
				// are dependent on one another.
				
				UINT64 id = curObj->getInternalID();
				auto iterFind = mDependencies.find(id);

				if (iterFind != mDependencies.end())
				{
					const Vector<CoreObject*>& dependencies = iterFind->second;
					for (auto& dependency : dependencies)
						syncObject(dependency);
				}

				SPtr<CoreObjectCore> objectCore = curObj->getCore();
				if (objectCore == nullptr)
				{
					curObj->markCoreClean();
					return;
				}

				CoreSyncData objSyncData = curObj->syncToCore(allocator);
				curObj->markCoreClean();

				syncData.entries.push_back(CoreStoredSyncObjData(objectCore,
					curObj->getInternalID(), objSyncData));
			};

			CoreObject* object = objectData.second.object;
			if (object != nullptr)
				syncObject(object);
			else
			{
				// Object was destroyed but we still need to sync its modifications before it was destroyed
				if (objectData.second.syncDataId != -1)
					syncData.entries.push_back(mDestroyedSyncData[objectData.second.syncDataId]);
			}
		}

		mDirtyObjects.clear();
		mDestroyedSyncData.clear();
	}
	void CoreObjectManager::updateDependencies(CoreObject* object, Vector<CoreObject*>* dependencies)
	{
		UINT64 id = object->getInternalID();

		bs_frame_mark();
		{
			FrameVector<CoreObject*> toRemove;
			FrameVector<CoreObject*> toAdd;

			Lock lock(mObjectsMutex);

			// Add dependencies and clear old dependencies from dependants
			{
				if (dependencies != nullptr)
					std::sort(dependencies->begin(), dependencies->end());

				auto iterFind = mDependencies.find(id);
				if (iterFind != mDependencies.end())
				{
					const Vector<CoreObject*>& oldDependencies = iterFind->second;

					if (dependencies != nullptr)
					{
						std::set_difference(dependencies->begin(), dependencies->end(),
							dependencies->begin(), dependencies->end(), toRemove.begin());

						std::set_difference(oldDependencies.begin(), oldDependencies.end(),
							oldDependencies.begin(), oldDependencies.end(), toAdd.begin());
					}
					else
					{
						for (auto& dependency : oldDependencies)
							toRemove.push_back(dependency);
					}

					for (auto& dependency : toRemove)
					{
						UINT64 dependencyId = dependency->getInternalID();
						auto iterFind2 = mDependants.find(dependencyId);

						if (iterFind2 != mDependants.end())
						{
							Vector<CoreObject*>& dependants = iterFind2->second;
							auto findIter3 = std::find(dependants.begin(), dependants.end(), object);
							dependants.erase(findIter3);

							if (dependants.size() == 0)
								mDependants.erase(iterFind2);
						}
					}
				}
				else
				{
					if (dependencies != nullptr)
					{
						for (auto& dependency : *dependencies)
							toAdd.push_back(dependency);
					}
				}

				if (dependencies != nullptr)
					mDependencies[id] = *dependencies;
			}

			// Register dependants
			{
				for (auto& dependency : toAdd)
				{
					UINT64 dependencyId = dependency->getInternalID();
					Vector<CoreObject*>& dependants = mDependants[dependencyId];
					dependants.push_back(object);
				}
			}
		}
		bs_frame_clear();
	}
Beispiel #14
0
	void VulkanImage::getBarriers(const VkImageSubresourceRange& range, Vector<VkImageMemoryBarrier>& barriers)
	{
		UINT32 numSubresources = range.levelCount * range.layerCount;

		// Nothing to do
		if (numSubresources == 0)
			return;

		UINT32 mip = range.baseMipLevel;
		UINT32 face = range.baseArrayLayer;
		UINT32 lastMip = range.baseMipLevel + range.levelCount - 1;
		UINT32 lastFace = range.baseArrayLayer + range.layerCount - 1;

		VkImageMemoryBarrier defaultBarrier;
		defaultBarrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
		defaultBarrier.pNext = nullptr;
		defaultBarrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		defaultBarrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
		defaultBarrier.image = getHandle();
		defaultBarrier.subresourceRange.aspectMask = range.aspectMask;
		defaultBarrier.subresourceRange.layerCount = 1;
		defaultBarrier.subresourceRange.levelCount = 1;
		defaultBarrier.subresourceRange.baseArrayLayer = 0;
		defaultBarrier.subresourceRange.baseMipLevel = 0;

		auto addNewBarrier = [&](VulkanImageSubresource* subresource, UINT32 face, UINT32 mip)
		{
			barriers.push_back(defaultBarrier);
			VkImageMemoryBarrier* barrier = &barriers.back();

			barrier->subresourceRange.baseArrayLayer = face;
			barrier->subresourceRange.baseMipLevel = mip;
			barrier->srcAccessMask = getAccessFlags(subresource->getLayout());
			barrier->oldLayout = subresource->getLayout();

			return barrier;
		};

		bs_frame_mark();
		{
			FrameVector<bool> processed(numSubresources, false);

			// Add first subresource
			VulkanImageSubresource* subresource = getSubresource(face, mip);
			addNewBarrier(subresource, face, mip);
			numSubresources--;
			processed[0] = true;

			while (numSubresources > 0)
			{
				// Try to expand the barrier as much as possible
				VkImageMemoryBarrier* barrier = &barriers.back();

				while (true)
				{
					// Expand by one in the X direction
					bool expandedFace = true;
					if (face < lastFace)
					{
						for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
						{
							UINT32 curMip = barrier->subresourceRange.baseMipLevel + i;
							VulkanImageSubresource* subresource = getSubresource(face + 1, curMip);
							if (barrier->oldLayout != subresource->getLayout())
							{
								expandedFace = false;
								break;
							}
						}

						if (expandedFace)
						{
							barrier->subresourceRange.layerCount++;
							numSubresources -= barrier->subresourceRange.levelCount;
							face++;

							for (UINT32 i = 0; i < barrier->subresourceRange.levelCount; i++)
							{
								UINT32 curMip = (barrier->subresourceRange.baseMipLevel + i) - range.baseMipLevel;
								UINT32 idx = curMip * range.layerCount + (face - range.baseArrayLayer);
								processed[idx] = true;
							}
						}
					}
					else
						expandedFace = false;

					// Expand by one in the Y direction
					bool expandedMip = true;
					if (mip < lastMip)
					{
						for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
						{
							UINT32 curFace = barrier->subresourceRange.baseArrayLayer + i;
							VulkanImageSubresource* subresource = getSubresource(curFace, mip + 1);
							if (barrier->oldLayout != subresource->getLayout())
							{
								expandedMip = false;
								break;
							}
						}

						if (expandedMip)
						{
							barrier->subresourceRange.levelCount++;
							numSubresources -= barrier->subresourceRange.layerCount;
							mip++;

							for (UINT32 i = 0; i < barrier->subresourceRange.layerCount; i++)
							{
								UINT32 curFace = (barrier->subresourceRange.baseArrayLayer + i) - range.baseArrayLayer;
								UINT32 idx = (mip - range.baseMipLevel) * range.layerCount + curFace;
								processed[idx] = true;
							}
						}
					}
					else
						expandedMip = false;

					// If we can't grow no more, we're done with this square
					if (!expandedMip && !expandedFace)
						break;
				}

				// Look for a new starting point (sub-resource we haven't processed yet)
				for (UINT32 i = 0; i < range.levelCount; i++)
				{
					bool found = false;
					for (UINT32 j = 0; j < range.layerCount; j++)
					{
						UINT32 idx = i * range.layerCount + j;
						if (!processed[idx])
						{
							mip = range.baseMipLevel + i;
							face = range.baseArrayLayer + j;

							found = true;
							processed[idx] = true;
							break;
						}
					}

					if (found)
					{
						VulkanImageSubresource* subresource = getSubresource(face, mip);
						addNewBarrier(subresource, face, mip);
						numSubresources--;
						break;
					}
				}
			}
		}
		bs_frame_clear();
	}