|
|
@@ -5,107 +5,169 @@
|
|
|
#include "BsMaterial.h"
|
|
|
#include "BsRenderableElement.h"
|
|
|
|
|
|
+using namespace std::placeholders;
|
|
|
+
|
|
|
namespace BansheeEngine
|
|
|
{
|
|
|
- RenderQueue::RenderQueue()
|
|
|
- :mRenderElements(&elementSorter)
|
|
|
+ RenderQueue::RenderQueue(MaterialGrouping grouping)
|
|
|
+ :mGrouping(grouping)
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
void RenderQueue::clear()
|
|
|
{
|
|
|
- mRenderElements.clear();
|
|
|
+ mSortableElements.clear();
|
|
|
+ mSortableElementIdx.clear();
|
|
|
+ mElements.clear();
|
|
|
+
|
|
|
mSortedRenderElements.clear();
|
|
|
}
|
|
|
|
|
|
void RenderQueue::add(RenderableElement* element, float distFromCamera)
|
|
|
{
|
|
|
- SortData sortData;
|
|
|
-
|
|
|
- RenderQueueElement& renderOp = sortData.element;
|
|
|
- renderOp.renderElem = element;
|
|
|
- renderOp.material = element->material;
|
|
|
- renderOp.mesh = element->mesh;
|
|
|
- renderOp.subMesh = element->subMesh;
|
|
|
+ SPtr<MaterialCore> material = element->material;
|
|
|
+ SPtr<ShaderCore> shader = material->getShader();
|
|
|
|
|
|
- sortData.distFromCamera = distFromCamera;
|
|
|
- sortData.priority = element->material->getShader()->getQueuePriority();
|
|
|
- sortData.sortType = element->material->getShader()->getQueueSortType();
|
|
|
- sortData.seqIdx = (UINT32)mRenderElements.size();
|
|
|
+ mElements.push_back(element);
|
|
|
+
|
|
|
+ UINT32 queuePriority = shader->getQueuePriority();
|
|
|
+ QueueSortType sortType = shader->getQueueSortType();
|
|
|
+ UINT32 shaderId = shader->getId();
|
|
|
+ bool separablePasses = shader->getAllowSeparablePasses();
|
|
|
|
|
|
- // TODO - Make sure elements are cached so we dont allocate memory for them every frame
|
|
|
- mRenderElements.insert(sortData);
|
|
|
- }
|
|
|
+ switch (sortType)
|
|
|
+ {
|
|
|
+ case QueueSortType::None:
|
|
|
+ distFromCamera = 0;
|
|
|
+ break;
|
|
|
+ case QueueSortType::BackToFront:
|
|
|
+ distFromCamera = -distFromCamera;
|
|
|
+ break;
|
|
|
+ }
|
|
|
|
|
|
- void RenderQueue::add(const SPtr<MaterialCore>& material, const SPtr<MeshCoreBase>& mesh, const SubMesh& subMesh, float distFromCamera)
|
|
|
- {
|
|
|
- SortData sortData;
|
|
|
+ UINT32 numPasses = material->getNumPasses();
|
|
|
+ if (!separablePasses)
|
|
|
+ numPasses = std::min(1U, numPasses);
|
|
|
|
|
|
- RenderQueueElement& renderOp = sortData.element;
|
|
|
- renderOp.renderElem = nullptr;
|
|
|
- renderOp.material = material;
|
|
|
- renderOp.mesh = mesh;
|
|
|
- renderOp.subMesh = subMesh;
|
|
|
+ for (UINT32 i = 0; i < numPasses; i++)
|
|
|
+ {
|
|
|
+ UINT32 idx = (UINT32)mSortableElementIdx.size();
|
|
|
+ mSortableElementIdx.push_back(idx);
|
|
|
|
|
|
- sortData.distFromCamera = distFromCamera;
|
|
|
- sortData.priority = material->getShader()->getQueuePriority();
|
|
|
- sortData.sortType = material->getShader()->getQueueSortType();
|
|
|
- sortData.seqIdx = (UINT32)mRenderElements.size();
|
|
|
+ mSortableElements.push_back(SortableElement());
|
|
|
+ SortableElement& sortableElem = mSortableElements.back();
|
|
|
|
|
|
- // TODO - Make sure elements are cached so we dont allocate memory for them every frame
|
|
|
- mRenderElements.insert(sortData);
|
|
|
+ sortableElem.seqIdx = idx;
|
|
|
+ sortableElem.priority = queuePriority;
|
|
|
+ sortableElem.shaderId = shaderId;
|
|
|
+ sortableElem.passIdx = i;
|
|
|
+ sortableElem.distFromCamera = distFromCamera;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- void RenderQueue::add(const RenderQueue& renderQueue)
|
|
|
+ void RenderQueue::sort()
|
|
|
{
|
|
|
- for (auto& elem : renderQueue.mRenderElements)
|
|
|
+ std::function<bool(UINT32, UINT32, const Vector<SortableElement>&)> sortMethod;
|
|
|
+
|
|
|
+ switch (mGrouping)
|
|
|
{
|
|
|
- if (elem.element.renderElem != nullptr)
|
|
|
- add(elem.element.renderElem, elem.distFromCamera);
|
|
|
- else
|
|
|
- add(elem.element.material, elem.element.mesh, elem.element.subMesh, elem.distFromCamera);
|
|
|
+ case MaterialGrouping::None:
|
|
|
+ sortMethod = &elementSorterNoGroup;
|
|
|
+ break;
|
|
|
+ case MaterialGrouping::PreferMaterial:
|
|
|
+ sortMethod = &elementSorterPreferGroup;
|
|
|
+ break;
|
|
|
+ case MaterialGrouping::PreferSortType:
|
|
|
+ sortMethod = &elementSorterPreferSort;
|
|
|
+ break;
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- void RenderQueue::sort()
|
|
|
- {
|
|
|
- // TODO - I'm ignoring "separate pass" material parameter.
|
|
|
- for (auto& sortData : mRenderElements)
|
|
|
+ // Sort only indices since we generate an entirely new data set anyway, it doesn't make sense to move sortable elements
|
|
|
+ std::sort(mSortableElementIdx.begin(), mSortableElementIdx.end(), std::bind(sortMethod, _1, _2, mSortableElements));
|
|
|
+
|
|
|
+ UINT32 prevShaderId = (UINT32)-1;
|
|
|
+ UINT32 prevPassIdx = (UINT32)-1;
|
|
|
+ RenderableElement* renderElem = nullptr;
|
|
|
+ INT32 currentElementIdx = -1;
|
|
|
+ UINT32 numPassesInCurrentElement = 0;
|
|
|
+ bool separablePasses = true;
|
|
|
+ for (UINT32 i = 0; i < (UINT32)mSortableElementIdx.size(); i++)
|
|
|
{
|
|
|
- const RenderQueueElement& renderElem = sortData.element;
|
|
|
- UINT32 numPasses = (UINT32)renderElem.material->getNumPasses();
|
|
|
- for (UINT32 i = 0; i < numPasses; i++)
|
|
|
+ UINT32 idx = mSortableElementIdx[i];
|
|
|
+
|
|
|
+ while (numPassesInCurrentElement == 0)
|
|
|
+ {
|
|
|
+ currentElementIdx++;
|
|
|
+ renderElem = mElements[currentElementIdx];
|
|
|
+ numPassesInCurrentElement = renderElem->material->getNumPasses();
|
|
|
+ separablePasses = renderElem->material->getShader()->getAllowSeparablePasses();
|
|
|
+ }
|
|
|
+
|
|
|
+ const SortableElement& elem = mSortableElements[idx];
|
|
|
+ if (separablePasses)
|
|
|
{
|
|
|
mSortedRenderElements.push_back(RenderQueueElement());
|
|
|
|
|
|
RenderQueueElement& sortedElem = mSortedRenderElements.back();
|
|
|
- sortedElem.renderElem = renderElem.renderElem;
|
|
|
- sortedElem.material = renderElem.material;
|
|
|
- sortedElem.mesh = renderElem.mesh;
|
|
|
- sortedElem.subMesh = renderElem.subMesh;
|
|
|
- sortedElem.passIdx = i;
|
|
|
+ sortedElem.renderElem = renderElem;
|
|
|
+ sortedElem.passIdx = elem.passIdx;
|
|
|
+
|
|
|
+ if (prevShaderId != elem.shaderId || prevPassIdx != elem.passIdx)
|
|
|
+ {
|
|
|
+ sortedElem.applyPass = true;
|
|
|
+ prevShaderId = elem.shaderId;
|
|
|
+ prevPassIdx = elem.passIdx;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ sortedElem.applyPass = false;
|
|
|
+
|
|
|
+ numPassesInCurrentElement--;
|
|
|
}
|
|
|
+ else
|
|
|
+ {
|
|
|
+ for (UINT32 j = 0; j < numPassesInCurrentElement; j++)
|
|
|
+ {
|
|
|
+ mSortedRenderElements.push_back(RenderQueueElement());
|
|
|
+
|
|
|
+ RenderQueueElement& sortedElem = mSortedRenderElements.back();
|
|
|
+ sortedElem.renderElem = renderElem;
|
|
|
+ sortedElem.passIdx = j;
|
|
|
+ sortedElem.applyPass = true;
|
|
|
+
|
|
|
+ prevShaderId = elem.shaderId;
|
|
|
+ prevPassIdx = j;
|
|
|
+ }
|
|
|
+
|
|
|
+ numPassesInCurrentElement = 0;
|
|
|
+ }
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- bool RenderQueue::elementSorter(const SortData& a, const SortData& b)
|
|
|
+ bool RenderQueue::elementSorterNoGroup(UINT32 aIdx, UINT32 bIdx, const Vector<SortableElement>& lookup)
|
|
|
{
|
|
|
- if (a.priority == b.priority)
|
|
|
- {
|
|
|
- if (a.sortType == QueueSortType::None || a.sortType != b.sortType)
|
|
|
- return a.seqIdx < b.seqIdx;
|
|
|
+ const SortableElement& a = lookup[aIdx];
|
|
|
+ const SortableElement& b = lookup[bIdx];
|
|
|
|
|
|
- if (a.distFromCamera == b.distFromCamera)
|
|
|
- return a.seqIdx < b.seqIdx;
|
|
|
+ return (a.priority > b.priority) | (a.distFromCamera < b.distFromCamera) | (a.seqIdx < b.seqIdx);
|
|
|
+ }
|
|
|
|
|
|
- if (a.sortType == QueueSortType::FrontToBack)
|
|
|
- return a.distFromCamera < b.distFromCamera;
|
|
|
- else
|
|
|
- return a.distFromCamera > b.distFromCamera;
|
|
|
- }
|
|
|
+ bool RenderQueue::elementSorterPreferGroup(UINT32 aIdx, UINT32 bIdx, const Vector<SortableElement>& lookup)
|
|
|
+ {
|
|
|
+ const SortableElement& a = lookup[aIdx];
|
|
|
+ const SortableElement& b = lookup[bIdx];
|
|
|
+
|
|
|
+ return (a.priority > b.priority) | (a.shaderId < b.shaderId) | (a.passIdx < b.passIdx) |
|
|
|
+ (a.distFromCamera < b.distFromCamera) | (a.seqIdx < b.seqIdx);
|
|
|
+ }
|
|
|
+
|
|
|
+ bool RenderQueue::elementSorterPreferSort(UINT32 aIdx, UINT32 bIdx, const Vector<SortableElement>& lookup)
|
|
|
+ {
|
|
|
+ const SortableElement& a = lookup[aIdx];
|
|
|
+ const SortableElement& b = lookup[bIdx];
|
|
|
|
|
|
- return a.priority > b.priority;
|
|
|
+ return (a.priority > b.priority) | (a.distFromCamera < b.distFromCamera) | (a.shaderId < b.shaderId) |
|
|
|
+ (a.passIdx < b.passIdx) | (a.seqIdx < b.seqIdx);
|
|
|
}
|
|
|
|
|
|
const Vector<RenderQueueElement>& RenderQueue::getSortedElements() const
|