[dxvk] Optimized resource binding

Fixes a few bottlenecks that were encountered in the Cascading Shadow
Maps demo from the Microsoft SDK. Performance is now slightly better
than wined3d with CSMT, MESA_NO_ERROR and mesa_glthread enabled.
This commit is contained in:
Philip Rebohle 2017-12-20 12:13:08 +01:00
parent f68655feff
commit 2ed2d892d6
15 changed files with 80 additions and 145 deletions

View File

@ -11,11 +11,13 @@ namespace dxvk {
// 14 - 29: Samplers
// 30 - 157: Shader resources
// 158 - 221: Uniform access views
const uint32_t stageOffset = 12 + 158 * 5;
switch (bindingType) {
case DxbcBindingType::ConstantBuffer: return bindingIndex + 0;
case DxbcBindingType::ImageSampler: return bindingIndex + 14;
case DxbcBindingType::ShaderResource: return bindingIndex + 30;
case DxbcBindingType::UnorderedAccessView:return bindingIndex + 158;
case DxbcBindingType::ConstantBuffer: return bindingIndex + stageOffset + 0;
case DxbcBindingType::ImageSampler: return bindingIndex + stageOffset + 14;
case DxbcBindingType::ShaderResource: return bindingIndex + stageOffset + 30;
case DxbcBindingType::UnorderedAccessView:return bindingIndex + stageOffset + 158;
default: Logger::err("computeResourceSlotId: Invalid resource type");
}
} else {

View File

@ -17,33 +17,4 @@ namespace dxvk {
DxvkBufferSlice bufferSlice;
};
/**
* \brief Shader resource slots
*/
class DxvkShaderResourceSlots {
public:
DxvkShaderResourceSlots() { }
DxvkShaderResourceSlots(size_t n) {
m_resources.resize(n);
}
const DxvkShaderResourceSlot& getShaderResource(uint32_t slot) const {
return m_resources.at(slot);
}
void bindShaderResource(
uint32_t slot,
const DxvkShaderResourceSlot& resource) {
m_resources.at(slot) = resource;
}
private:
std::vector<DxvkShaderResourceSlot> m_resources;
};
}

View File

@ -254,6 +254,10 @@ namespace dxvk {
return m_buffer;
}
Rc<DxvkResource> resource() const {
return m_buffer->resource();
}
VkBuffer handle() const {
return m_buffer != nullptr
? m_buffer->handle()

View File

@ -108,7 +108,7 @@ namespace dxvk {
std::array<VkWriteDescriptorSet, MaxNumResourceSlots> descriptorWrites;
for (uint32_t i = 0; i < descriptorCount; i++) {
auto& curr = descriptorWrites.at(i);
auto& curr = descriptorWrites[i];
auto& binding = descriptorSlots[i];
curr.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;

View File

@ -73,15 +73,9 @@ namespace dxvk {
VkPipelineBindPoint pipe,
uint32_t slot,
const DxvkBufferSlice& buffer) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).bufferSlice != buffer) {
if (m_rc[slot].bufferSlice != buffer) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.bufferSlice = buffer;
rc->bindShaderResource(slot, resource);
m_rc[slot].bufferSlice = buffer;
}
}
@ -90,15 +84,9 @@ namespace dxvk {
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkBufferView>& bufferView) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).bufferView != bufferView) {
if (m_rc[slot].bufferView != bufferView) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.bufferView = bufferView;
rc->bindShaderResource(slot, resource);
m_rc[slot].bufferView = bufferView;
}
}
@ -107,15 +95,9 @@ namespace dxvk {
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkImageView>& image) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).imageView != image) {
if (m_rc[slot].imageView != image) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.imageView = image;
rc->bindShaderResource(slot, resource);
m_rc[slot].imageView = image;
}
}
@ -124,15 +106,9 @@ namespace dxvk {
VkPipelineBindPoint pipe,
uint32_t slot,
const Rc<DxvkSampler>& sampler) {
auto rc = this->getShaderResourceSlots(pipe);
if (rc->getShaderResource(slot).sampler != sampler) {
if (m_rc[slot].sampler != sampler) {
m_flags.set(this->getResourceDirtyFlag(pipe));
DxvkShaderResourceSlot resource;
resource.sampler = sampler;
rc->bindShaderResource(slot, resource);
m_rc[slot].sampler = sampler;
}
}
@ -172,13 +148,13 @@ namespace dxvk {
uint32_t binding,
const DxvkBufferSlice& buffer,
uint32_t stride) {
if (m_state.vi.vertexBuffers.at(binding) != buffer) {
m_state.vi.vertexBuffers.at(binding) = buffer;
if (m_state.vi.vertexBuffers[binding] != buffer) {
m_state.vi.vertexBuffers[binding] = buffer;
m_flags.set(DxvkContextFlag::GpDirtyVertexBuffers);
}
if (m_state.vi.vertexStrides.at(binding) != stride) {
m_state.vi.vertexStrides.at(binding) = stride;
if (m_state.vi.vertexStrides[binding] != stride) {
m_state.vi.vertexStrides[binding] = stride;
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
}
}
@ -606,8 +582,8 @@ namespace dxvk {
}
for (uint32_t i = 0; i < viewportCount; i++) {
m_state.vp.viewports.at(i) = viewports[i];
m_state.vp.scissorRects.at(i) = scissorRects[i];
m_state.vp.viewports[i] = viewports[i];
m_state.vp.scissorRects[i] = scissorRects[i];
}
this->updateViewports();
@ -649,10 +625,10 @@ namespace dxvk {
m_state.il.numBindings = bindingCount;
for (uint32_t i = 0; i < attributeCount; i++)
m_state.il.attributes.at(i) = attributes[i];
m_state.il.attributes[i] = attributes[i];
for (uint32_t i = 0; i < bindingCount; i++)
m_state.il.bindings.at(i) = bindings[i];
m_state.il.bindings[i] = bindings[i];
}
@ -687,7 +663,7 @@ namespace dxvk {
void DxvkContext::setBlendMode(
uint32_t attachment,
const DxvkBlendMode& blendMode) {
m_state.om.blendModes.at(attachment) = blendMode;
m_state.om.blendModes[attachment] = blendMode;
m_flags.set(DxvkContextFlag::GpDirtyPipelineState);
}
@ -779,7 +755,7 @@ namespace dxvk {
for (uint32_t i = 0; i < m_state.il.numBindings; i++) {
gpState.ilBindings[i].binding = m_state.il.bindings[i].binding;
gpState.ilBindings[i].inputRate = m_state.il.bindings[i].inputRate;
gpState.ilBindings[i].stride = m_state.vi.vertexStrides.at(i);
gpState.ilBindings[i].stride = m_state.vi.vertexStrides[i];
}
gpState.rsEnableDepthClamp = m_state.rs.enableDepthClamp;
@ -818,7 +794,7 @@ namespace dxvk {
for (uint32_t i = 0; i < DxvkLimits::MaxNumRenderTargets; i++) {
if (rt.getColorTarget(i) != nullptr) {
const DxvkBlendMode& mode = m_state.om.blendModes.at(i);
const DxvkBlendMode& mode = m_state.om.blendModes[i];
gpState.omBlendAttachments[i].blendEnable = mode.enableBlending;
gpState.omBlendAttachments[i].srcColorBlendFactor = mode.colorSrcFactor;
@ -869,34 +845,30 @@ namespace dxvk {
// compute can use this code as well
for (uint32_t i = 0; i < layout->bindingCount(); i++) {
const uint32_t slot = layout->binding(i).slot;
const auto& res = m_gResources.getShaderResource(slot);
DxvkDescriptorInfo descriptor;
const auto& res = m_rc[slot];
if (res.sampler != nullptr) {
m_descriptors[i].image.sampler = res.sampler->handle();
m_descriptors[i].image.imageView = VK_NULL_HANDLE;
m_descriptors[i].image.imageLayout = VK_IMAGE_LAYOUT_UNDEFINED;
m_cmd->trackResource(res.sampler);
descriptor.image.sampler = res.sampler->handle();
}
if (res.imageView != nullptr) {
} else if (res.imageView != nullptr) {
m_descriptors[i].image.sampler = VK_NULL_HANDLE;
m_descriptors[i].image.imageView = res.imageView->handle();
m_descriptors[i].image.imageLayout = res.imageView->imageInfo().layout;
m_cmd->trackResource(res.imageView);
m_cmd->trackResource(res.imageView->image());
descriptor.image.imageView = res.imageView->handle();
descriptor.image.imageLayout = res.imageView->imageInfo().layout;
}
if (res.bufferView != nullptr) {
} else if (res.bufferView != nullptr) {
m_descriptors[i].texelBuffer = res.bufferView->handle();
m_cmd->trackResource(res.bufferView);
m_cmd->trackResource(res.bufferView->buffer()->resource());
descriptor.texelBuffer = res.bufferView->handle();
} else if (res.bufferSlice.handle() != VK_NULL_HANDLE) {
m_descriptors[i].buffer = res.bufferSlice.descriptorInfo();
m_cmd->trackResource(res.bufferSlice.resource());
}
if (res.bufferSlice.handle() != VK_NULL_HANDLE) {
m_cmd->trackResource(res.bufferSlice.buffer()->resource());
descriptor.buffer = res.bufferSlice.descriptorInfo();
}
descriptors.at(i) = descriptor;
}
m_cmd->bindResourceDescriptors(
@ -905,7 +877,7 @@ namespace dxvk {
layout->descriptorSetLayout(),
layout->bindingCount(),
layout->bindings(),
descriptors.data());
m_descriptors.data());
}
}
@ -949,7 +921,7 @@ namespace dxvk {
m_state.vi.indexBuffer.offset(),
m_state.vi.indexType);
m_cmd->trackResource(
m_state.vi.indexBuffer.buffer()->resource());
m_state.vi.indexBuffer.resource());
}
}
}
@ -959,15 +931,15 @@ namespace dxvk {
if (m_flags.test(DxvkContextFlag::GpDirtyVertexBuffers)) {
m_flags.clr(DxvkContextFlag::GpDirtyVertexBuffers);
for (uint32_t i = 0; i < m_state.vi.vertexBuffers.size(); i++) {
const DxvkBufferSlice vbo = m_state.vi.vertexBuffers.at(i);
for (uint32_t i = 0; i < m_state.il.numBindings; i++) {
const DxvkBufferSlice& vbo = m_state.vi.vertexBuffers[i];
VkBuffer handle = vbo.handle();
VkDeviceSize offset = vbo.offset();
const VkBuffer handle = vbo.handle();
const VkDeviceSize offset = vbo.offset();
if (handle != VK_NULL_HANDLE) {
m_cmd->cmdBindVertexBuffers(i, 1, &handle, &offset);
m_cmd->trackResource(vbo.buffer()->resource());
m_cmd->trackResource(vbo.resource());
}
}
}
@ -1089,15 +1061,6 @@ namespace dxvk {
}
DxvkShaderResourceSlots* DxvkContext::getShaderResourceSlots(VkPipelineBindPoint pipe) {
switch (pipe) {
case VK_PIPELINE_BIND_POINT_GRAPHICS: return &m_gResources;
case VK_PIPELINE_BIND_POINT_COMPUTE : return &m_cResources;
default: return nullptr;
}
}
DxvkContextFlag DxvkContext::getResourceDirtyFlag(VkPipelineBindPoint pipe) const {
switch (pipe) {
default:

View File

@ -415,10 +415,8 @@ namespace dxvk {
DxvkContextState m_state;
DxvkBarrierSet m_barriers;
DxvkShaderResourceSlots m_cResources = { 256 };
DxvkShaderResourceSlots m_gResources = { 1024 };
std::array<DxvkDescriptorInfo, MaxNumResourceSlots> descriptors;
std::array<DxvkShaderResourceSlot, MaxNumResourceSlots> m_rc;
std::array<DxvkDescriptorInfo, MaxNumResourceSlots> m_descriptors;
void renderPassBegin();
void renderPassEnd();
@ -448,9 +446,6 @@ namespace dxvk {
void transformLayoutsRenderPassEnd(
const DxvkRenderTargets& renderTargets);
DxvkShaderResourceSlots* getShaderResourceSlots(
VkPipelineBindPoint pipe);
DxvkContextFlag getResourceDirtyFlag(
VkPipelineBindPoint pipe) const;

View File

@ -21,13 +21,13 @@ namespace dxvk {
VkDescriptorSet DxvkDescriptorAlloc::alloc(VkDescriptorSetLayout layout) {
VkDescriptorSet set = allocFrom(m_pools.at(m_poolId), layout);
VkDescriptorSet set = allocFrom(m_pools[m_poolId], layout);
if (set == VK_NULL_HANDLE) {
if (++m_poolId >= m_pools.size())
m_pools.push_back(createDescriptorPool());
set = allocFrom(m_pools.at(m_poolId), layout);
set = allocFrom(m_pools[m_poolId], layout);
}
return set;

View File

@ -10,10 +10,10 @@ namespace dxvk {
* Stores information that is required to
* update a single resource descriptor.
*/
struct DxvkDescriptorInfo {
VkDescriptorImageInfo image = { VK_NULL_HANDLE, VK_NULL_HANDLE, VK_IMAGE_LAYOUT_UNDEFINED };
VkDescriptorBufferInfo buffer = { VK_NULL_HANDLE, 0, 0 };
VkBufferView texelBuffer = VK_NULL_HANDLE;
union DxvkDescriptorInfo {
VkDescriptorImageInfo image;
VkDescriptorBufferInfo buffer;
VkBufferView texelBuffer;
};

View File

@ -481,7 +481,7 @@ namespace dxvk {
const uint32_t formatId = static_cast<uint32_t>(format);
if (formatId < g_formatInfos.size())
return &g_formatInfos.at(formatId);
return &g_formatInfos[formatId];
return nullptr;
}

View File

@ -263,7 +263,7 @@ namespace dxvk {
const bool adequate = (m_memProps.memoryTypes[i].propertyFlags & flags) == flags;
if (supported && adequate) {
DxvkMemory memory = m_heaps.at(i)->alloc(req.size, req.alignment);
DxvkMemory memory = m_heaps[i]->alloc(req.size, req.alignment);
if (memory.memory() != VK_NULL_HANDLE)
return memory;

View File

@ -15,7 +15,7 @@ namespace dxvk {
uint32_t bindingId = this->getBindingId(slot);
if (bindingId != InvalidBinding) {
m_descriptorSlots.at(bindingId).stages |= stage;
m_descriptorSlots[bindingId].stages |= stage;
} else {
DxvkDescriptorSlot slotInfo;
slotInfo.slot = slot;
@ -31,7 +31,7 @@ namespace dxvk {
// of bindings used by a shader is usually much smaller than
// the number of resource slots available to the system.
for (uint32_t i = 0; i < m_descriptorSlots.size(); i++) {
if (m_descriptorSlots.at(i).slot == slot)
if (m_descriptorSlots[i].slot == slot)
return i;
}

View File

@ -115,7 +115,7 @@ namespace dxvk {
* \returns Resource binding info
*/
const DxvkDescriptorSlot& binding(uint32_t id) const {
return m_bindingSlots.at(id);
return m_bindingSlots[id];
}
/**

View File

@ -4,7 +4,7 @@ namespace dxvk {
DxvkRenderPassFormat::DxvkRenderPassFormat() {
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
m_color.at(i) = VK_FORMAT_UNDEFINED;
m_color[i] = VK_FORMAT_UNDEFINED;
m_depth = VK_FORMAT_UNDEFINED;
m_samples = VK_SAMPLE_COUNT_1_BIT;
}
@ -16,7 +16,7 @@ namespace dxvk {
std::hash<VkSampleCountFlagBits> shash;
for (uint32_t i = 0; i < MaxNumRenderTargets; i++)
result.add(fhash(m_color.at(i)));
result.add(fhash(m_color[i]));
result.add(fhash(m_depth));
result.add(shash(m_samples));
@ -28,7 +28,7 @@ namespace dxvk {
bool equal = m_depth == other.m_depth
&& m_samples == other.m_samples;
for (uint32_t i = 0; i < MaxNumRenderTargets && !equal; i++)
equal = m_color.at(i) == other.m_color.at(i);
equal = m_color[i] == other.m_color[i];
return equal;
}
@ -68,8 +68,8 @@ namespace dxvk {
}
for (uint32_t i = 0; i < MaxNumRenderTargets; i++) {
colorRef.at(i).attachment = VK_ATTACHMENT_UNUSED;
colorRef.at(i).layout = VK_IMAGE_LAYOUT_UNDEFINED;
colorRef[i].attachment = VK_ATTACHMENT_UNUSED;
colorRef[i].layout = VK_IMAGE_LAYOUT_UNDEFINED;
if (fmt.getColorFormat(i) != VK_FORMAT_UNDEFINED) {
VkAttachmentDescription desc;
@ -83,8 +83,8 @@ namespace dxvk {
desc.initialLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
desc.finalLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorRef.at(i).attachment = attachments.size();
colorRef.at(i).layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
colorRef[i].attachment = attachments.size();
colorRef[i].layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
attachments.push_back(desc);
}

View File

@ -8,13 +8,13 @@ namespace dxvk {
DxvkStatCounters::DxvkStatCounters(const DxvkStatCounters& other) {
for (size_t i = 0; i < m_counters.size(); i++)
m_counters.at(i) = other.m_counters.at(i).load();
m_counters[i] = other.m_counters[i].load();
}
DxvkStatCounters& DxvkStatCounters::operator = (const DxvkStatCounters& other) {
for (size_t i = 0; i < m_counters.size(); i++)
m_counters.at(i) = other.m_counters.at(i).load();
m_counters[i] = other.m_counters[i].load();
return *this;
}
@ -22,20 +22,20 @@ namespace dxvk {
DxvkStatCounters DxvkStatCounters::delta(const DxvkStatCounters& oldState) const {
DxvkStatCounters result;
for (size_t i = 0; i < m_counters.size(); i++)
result.m_counters.at(i) = m_counters.at(i) - oldState.m_counters.at(i);;
result.m_counters[i] = m_counters[i] - oldState.m_counters[i];;
return result;
}
void DxvkStatCounters::addCounters(const DxvkStatCounters& counters) {
for (size_t i = 0; i < m_counters.size(); i++)
m_counters.at(i) += counters.m_counters.at(i);
m_counters[i] += counters.m_counters[i];
}
void DxvkStatCounters::clear() {
for (size_t i = 0; i < m_counters.size(); i++)
m_counters.at(i) = 0;
m_counters[i] = 0;
}
}

View File

@ -53,7 +53,7 @@ namespace dxvk {
* \param [in] amount Number to add to the counter
*/
void increment(DxvkStat counter, uint32_t amount) {
m_counters.at(counterId(counter)) += amount;
m_counters[counterId(counter)] += amount;
}
/**
@ -63,7 +63,7 @@ namespace dxvk {
* \returns Current value of the counter
*/
uint32_t get(DxvkStat counter) const {
return m_counters.at(counterId(counter));
return m_counters[counterId(counter)];
}
/**