Share code between Record and Merge Transitions

This commit is contained in:
baldurk
2015-11-08 14:40:08 +01:00
parent 12843544e2
commit 437d350725
2 changed files with 144 additions and 271 deletions
+140 -271
View File
@@ -49,6 +49,144 @@ bool VulkanResourceManager::SerialisableResource(ResourceId id, VkResourceRecord
#define TRDBG(...)
#endif
template<typename SrcTransType>
void VulkanResourceManager::RecordSingleTransition(vector< pair<ResourceId, ImageRegionState> > &dsttrans, ResourceId id, const SrcTransType &t, uint32_t nummips, uint32_t numslices)
{
bool done = false;
auto it = dsttrans.begin();
for(; it != dsttrans.end(); ++it)
{
// image transitions are handled by initially inserting one subresource range for each aspect,
// and whenever we need more fine-grained detail we split it immediately for one range for
// each subresource in that aspect. Thereafter if a transition comes in that covers multiple
// subresources, we transition all matching ranges.
// find the transitions matching this id
if(it->first < id) continue;
if(it->first != id) break;
if(it->second.subresourceRange.aspectMask & t.subresourceRange.aspectMask)
{
// we've found a range that completely matches our region, doesn't matter if that's
// a whole image and the transition is the whole image, or it's one subresource.
// note that for images with only one array/mip slice (e.g. render targets) we'll never
// really have to worry about the else{} branch
if(it->second.subresourceRange.baseMipLevel == t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.mipLevels == nummips &&
it->second.subresourceRange.baseArrayLayer == t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.arraySize == numslices)
{
// verify
//RDCASSERT(it->second.state == t.oldLayout);
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
done = true;
break;
}
else
{
// this handles the case where the transition covers a number of subresources and we need
// to transition each matching subresource. If the transition was only one mip & array slice
// it would have hit the case above. Find each subresource within the range, transition it,
// and continue (marking as done so whenever we stop finding matching ranges, we are
// satisfied.
//
// note that regardless of how we lay out our subresources (slice-major or mip-major) the new
// range could be sparse, but that's OK as we only break out of the loop once we go past the whole
// aspect. Any subresources that don't match the range, after the split, will fail to meet any
// of the handled cases, so we'll just continue processing.
if(it->second.subresourceRange.mipLevels == 1 &&
it->second.subresourceRange.arraySize == 1 &&
it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
continue;
}
// finally handle the case where we have a range that covers a whole image but we need to
// split it. If the transition covered the whole image too it would have hit the very first
// case, so we know that the transition doesn't cover the whole range.
// Also, if we've already done the split this case won't be hit and we'll either fall into
// the case above, or we'll finish as we've covered the whole transition.
else if(it->second.subresourceRange.mipLevels > 1 || it->second.subresourceRange.arraySize > 1)
{
pair<ResourceId, ImageRegionState> existing = *it;
// remember where we were in the array, as after this iterators will be
// invalidated.
size_t offs = it - dsttrans.begin();
size_t count = it->second.subresourceRange.mipLevels * it->second.subresourceRange.arraySize;
// only insert count-1 as we want count entries total - one per subresource
dsttrans.insert(it, count-1, existing);
// it now points at the first subresource, but we need to modify the ranges
// to be valid
it = dsttrans.begin()+offs;
for(size_t i=0; i < count; i++)
{
it->second.subresourceRange.mipLevels = 1;
it->second.subresourceRange.arraySize = 1;
// slice-major
it->second.subresourceRange.baseArrayLayer = uint32_t(i / existing.second.subresourceRange.mipLevels);
it->second.subresourceRange.baseMipLevel = uint32_t(i % existing.second.subresourceRange.mipLevels);
it++;
}
// reset the iterator to point to the first subresource
it = dsttrans.begin()+offs;
// the loop will continue after this point and look at the next subresources
// so we need to check to see if the first subresource lies in the range here
if(it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
}
// continue processing from here
continue;
}
}
}
// if we've gone past where the new subresource range would sit
if(it->second.subresourceRange.aspectMask > t.subresourceRange.aspectMask)
break;
// otherwise continue to try and find the subresource range
}
if(done) return;
// we don't have an existing transition for this memory region, insert into place. it points to
// where it should be inserted
dsttrans.insert(it, std::make_pair(id, ImageRegionState(t.subresourceRange, t.oldLayout, t.newLayout)));
}
void VulkanResourceManager::RecordTransitions(vector< pair<ResourceId, ImageRegionState> > &trans, map<ResourceId, ImageLayouts> &states,
uint32_t numTransitions, const VkImageMemoryBarrier *transitions)
{
@@ -65,139 +203,7 @@ void VulkanResourceManager::RecordTransitions(vector< pair<ResourceId, ImageRegi
if(nummips == VK_REMAINING_MIP_LEVELS) nummips = states[id].mipLevels - t.subresourceRange.baseMipLevel;
if(numslices == VK_REMAINING_ARRAY_LAYERS) numslices = states[id].arraySize - t.subresourceRange.baseArrayLayer;
bool done = false;
auto it = trans.begin();
for(; it != trans.end(); ++it)
{
// image transitions are handled by initially inserting one subresource range for each aspect,
// and whenever we need more fine-grained detail we split it immediately for one range for
// each subresource in that aspect. Thereafter if a transition comes in that covers multiple
// subresources, we transition all matching ranges.
// find the transitions matching this id
if(it->first < id) continue;
if(it->first != id) break;
if(it->second.subresourceRange.aspectMask & t.subresourceRange.aspectMask)
{
// we've found a range that completely matches our region, doesn't matter if that's
// a whole image and the transition is the whole image, or it's one subresource.
// note that for images with only one array/mip slice (e.g. render targets) we'll never
// really have to worry about the else{} branch
if(it->second.subresourceRange.baseMipLevel == t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.mipLevels == nummips &&
it->second.subresourceRange.baseArrayLayer == t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.arraySize == numslices)
{
// verify
//RDCASSERT(it->second.state == t.oldLayout);
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
done = true;
break;
}
else
{
// this handles the case where the transition covers a number of subresources and we need
// to transition each matching subresource. If the transition was only one mip & array slice
// it would have hit the case above. Find each subresource within the range, transition it,
// and continue (marking as done so whenever we stop finding matching ranges, we are
// satisfied.
//
// note that regardless of how we lay out our subresources (slice-major or mip-major) the new
// range could be sparse, but that's OK as we only break out of the loop once we go past the whole
// aspect. Any subresources that don't match the range, after the split, will fail to meet any
// of the handled cases, so we'll just continue processing.
if(it->second.subresourceRange.mipLevels == 1 &&
it->second.subresourceRange.arraySize == 1 &&
it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
continue;
}
// finally handle the case where we have a range that covers a whole image but we need to
// split it. If the transition covered the whole image too it would have hit the very first
// case, so we know that the transition doesn't cover the whole range.
// Also, if we've already done the split this case won't be hit and we'll either fall into
// the case above, or we'll finish as we've covered the whole transition.
else if(it->second.subresourceRange.mipLevels > 1 || it->second.subresourceRange.arraySize > 1)
{
pair<ResourceId, ImageRegionState> existing = *it;
// remember where we were in the array, as after this iterators will be
// invalidated.
size_t offs = it - trans.begin();
size_t count = it->second.subresourceRange.mipLevels * it->second.subresourceRange.arraySize;
// only insert count-1 as we want count entries total - one per subresource
trans.insert(it, count-1, existing);
// it now points at the first subresource, but we need to modify the ranges
// to be valid
it = trans.begin()+offs;
for(size_t i=0; i < count; i++)
{
it->second.subresourceRange.mipLevels = 1;
it->second.subresourceRange.arraySize = 1;
// slice-major
it->second.subresourceRange.baseArrayLayer = uint32_t(i / existing.second.subresourceRange.mipLevels);
it->second.subresourceRange.baseMipLevel = uint32_t(i % existing.second.subresourceRange.mipLevels);
it++;
}
// reset the iterator to point to the first subresource
it = trans.begin()+offs;
// the loop will continue after this point and look at the next subresources
// so we need to check to see if the first subresource lies in the range here
if(it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
}
// continue processing from here
continue;
}
}
}
// if we've gone past where the new subresource range would sit
if(it->second.subresourceRange.aspectMask > t.subresourceRange.aspectMask)
break;
// otherwise continue to try and find the subresource range
}
if(done) continue;
// we don't have an existing transition for this memory region, insert into place. it points to
// where it should be inserted
trans.insert(it, std::make_pair(id, ImageRegionState(t.subresourceRange, t.oldLayout, t.newLayout)));
RecordSingleTransition(trans, id, t, nummips, numslices);
}
TRDBG("Post-record, there are %u transitions", (uint32_t)trans.size());
@@ -210,145 +216,8 @@ void VulkanResourceManager::MergeTransitions(vector< pair<ResourceId, ImageRegio
for(size_t ti=0; ti < srctrans.size(); ti++)
{
ResourceId id = srctrans[ti].first;
const ImageRegionState &t = srctrans[ti].second;
uint32_t nummips = t.subresourceRange.mipLevels;
uint32_t numslices = t.subresourceRange.arraySize;
bool done = false;
auto it = dsttrans.begin();
for(; it != dsttrans.end(); ++it)
{
// image transitions are handled by initially inserting one subresource range for each aspect,
// and whenever we need more fine-grained detail we split it immediately for one range for
// each subresource in that aspect. Thereafter if a transition comes in that covers multiple
// subresources, we transition all matching ranges.
// find the transitions matching this id
if(it->first < id) continue;
if(it->first != id) break;
if(it->second.subresourceRange.aspectMask & t.subresourceRange.aspectMask)
{
// we've found a range that completely matches our region, doesn't matter if that's
// a whole image and the transition is the whole image, or it's one subresource.
// note that for images with only one array/mip slice (e.g. render targets) we'll never
// really have to worry about the else{} branch
if(it->second.subresourceRange.baseMipLevel == t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.mipLevels == nummips &&
it->second.subresourceRange.baseArrayLayer == t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.arraySize == numslices)
{
// verify
//RDCASSERT(it->second.state == t.prevstate);
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
done = true;
break;
}
else
{
// this handles the case where the transition covers a number of subresources and we need
// to transition each matching subresource. If the transition was only one mip & array slice
// it would have hit the case above. Find each subresource within the range, transition it,
// and continue (marking as done so whenever we stop finding matching ranges, we are
// satisfied.
//
// note that regardless of how we lay out our subresources (slice-major or mip-major) the new
// range could be sparse, but that's OK as we only break out of the loop once we go past the whole
// aspect. Any subresources that don't match the range, after the split, will fail to meet any
// of the handled cases, so we'll just continue processing.
if(it->second.subresourceRange.mipLevels == 1 &&
it->second.subresourceRange.arraySize == 1 &&
it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
continue;
}
// finally handle the case where we have a range that covers a whole image but we need to
// split it. If the transition covered the whole image too it would have hit the very first
// case, so we know that the transition doesn't cover the whole range.
// Also, if we've already done the split this case won't be hit and we'll either fall into
// the case above, or we'll finish as we've covered the whole transition.
else if(it->second.subresourceRange.mipLevels > 1 || it->second.subresourceRange.arraySize > 1)
{
pair<ResourceId, ImageRegionState> existing = *it;
// remember where we were in the array, as after this iterators will be
// invalidated.
size_t offs = it - dsttrans.begin();
size_t count = it->second.subresourceRange.mipLevels * it->second.subresourceRange.arraySize;
// only insert count-1 as we want count entries total - one per subresource
dsttrans.insert(it, count-1, existing);
// it now points at the first subresource, but we need to modify the ranges
// to be valid
it = dsttrans.begin()+offs;
for(size_t i=0; i < count; i++)
{
it->second.subresourceRange.mipLevels = 1;
it->second.subresourceRange.arraySize = 1;
// slice-major
it->second.subresourceRange.baseArrayLayer = uint32_t(i / existing.second.subresourceRange.mipLevels);
it->second.subresourceRange.baseMipLevel = uint32_t(i % existing.second.subresourceRange.mipLevels);
it++;
}
// reset the iterator to point to the first subresource
it = dsttrans.begin()+offs;
// the loop will continue after this point and look at the next subresources
// so we need to check to see if the first subresource lies in the range here
if(it->second.subresourceRange.baseMipLevel >= t.subresourceRange.baseMipLevel &&
it->second.subresourceRange.baseMipLevel < t.subresourceRange.baseMipLevel+nummips &&
it->second.subresourceRange.baseArrayLayer >= t.subresourceRange.baseArrayLayer &&
it->second.subresourceRange.baseArrayLayer < t.subresourceRange.baseArrayLayer+numslices)
{
// apply it (prevstate is from the start of all transitions, so only set once)
if(it->second.oldLayout == UNTRANSITIONED_IMG_STATE)
it->second.oldLayout = t.oldLayout;
it->second.newLayout = t.newLayout;
// continue as there might be more, but we're done
done = true;
}
// continue processing from here
continue;
}
}
}
// if we've gone past where the new subresource range would sit
if(it->second.subresourceRange.aspectMask > t.subresourceRange.aspectMask)
break;
// otherwise continue to try and find the subresource range
}
if(done) continue;
// we don't have an existing transition for this memory region, insert into place. it points to
// where it should be inserted
dsttrans.insert(it, std::make_pair(id, ImageRegionState(t.subresourceRange, t.oldLayout, t.newLayout)));
RecordSingleTransition(dsttrans, srctrans[ti].first, t, t.subresourceRange.mipLevels, t.subresourceRange.arraySize);
}
TRDBG("Post-merge, there are %u transitions", (uint32_t)dsttrans.size());
+4
View File
@@ -99,8 +99,12 @@ class VulkanResourceManager : public ResourceManager<WrappedVkRes*, TypedRealHan
}
// handling memory & image transitions
template<typename SrcTransType>
void RecordSingleTransition(vector< pair<ResourceId, ImageRegionState> > &trans, ResourceId id, const SrcTransType &t, uint32_t nummips, uint32_t numslices);
void RecordTransitions(vector< pair<ResourceId, ImageRegionState> > &trans, map<ResourceId, ImageLayouts> &states,
uint32_t numTransitions, const VkImageMemoryBarrier *transitions);
void MergeTransitions(vector< pair<ResourceId, ImageRegionState> > &dsttrans,
vector< pair<ResourceId, ImageRegionState> > &srctrans);