mirror of
https://github.com/EduApps-CDG/OpenDX
synced 2024-12-30 09:45:37 +01:00
[d3d11] Fix vertex attribute offset with D3D11_APPEND_ALIGNED_ELEMENT
Computes the correct offset even if some vertex attributes are not used by the vertex shader. Fixes a crash in Sleeping Dogs: Definitive Edition (#407).
This commit is contained in:
parent
3b70e23e2c
commit
fc8573891e
@ -942,9 +942,12 @@ namespace dxvk {
|
|||||||
DxbcModule dxbcModule(dxbcReader);
|
DxbcModule dxbcModule(dxbcReader);
|
||||||
|
|
||||||
const Rc<DxbcIsgn> inputSignature = dxbcModule.isgn();
|
const Rc<DxbcIsgn> inputSignature = dxbcModule.isgn();
|
||||||
|
|
||||||
|
uint32_t attrMask = 0;
|
||||||
|
uint32_t bindMask = 0;
|
||||||
|
|
||||||
std::vector<DxvkVertexAttribute> attributes;
|
std::array<DxvkVertexAttribute, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> attrList;
|
||||||
std::vector<DxvkVertexBinding> bindings;
|
std::array<DxvkVertexBinding, D3D11_IA_VERTEX_INPUT_RESOURCE_SLOT_COUNT> bindList;
|
||||||
|
|
||||||
for (uint32_t i = 0; i < NumElements; i++) {
|
for (uint32_t i = 0; i < NumElements; i++) {
|
||||||
const DxbcSgnEntry* entry = inputSignature->find(
|
const DxbcSgnEntry* entry = inputSignature->find(
|
||||||
@ -956,12 +959,11 @@ namespace dxvk {
|
|||||||
"D3D11Device: No such vertex shader semantic: ",
|
"D3D11Device: No such vertex shader semantic: ",
|
||||||
pInputElementDescs[i].SemanticName,
|
pInputElementDescs[i].SemanticName,
|
||||||
pInputElementDescs[i].SemanticIndex));
|
pInputElementDescs[i].SemanticIndex));
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create vertex input attribute description
|
// Create vertex input attribute description
|
||||||
DxvkVertexAttribute attrib;
|
DxvkVertexAttribute attrib;
|
||||||
attrib.location = entry->registerId;
|
attrib.location = entry != nullptr ? entry->registerId : 0;
|
||||||
attrib.binding = pInputElementDescs[i].InputSlot;
|
attrib.binding = pInputElementDescs[i].InputSlot;
|
||||||
attrib.format = m_dxgiAdapter->LookupFormat(
|
attrib.format = m_dxgiAdapter->LookupFormat(
|
||||||
pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
|
pInputElementDescs[i].Format, DXGI_VK_FORMAT_MODE_COLOR).Format;
|
||||||
@ -975,7 +977,7 @@ namespace dxvk {
|
|||||||
attrib.offset = 0;
|
attrib.offset = 0;
|
||||||
|
|
||||||
for (uint32_t j = 1; j <= i; j++) {
|
for (uint32_t j = 1; j <= i; j++) {
|
||||||
const DxvkVertexAttribute& prev = attributes.at(i - j);
|
const DxvkVertexAttribute& prev = attrList.at(i - j);
|
||||||
|
|
||||||
if (prev.binding == attrib.binding) {
|
if (prev.binding == attrib.binding) {
|
||||||
const DxvkFormatInfo* formatInfo = imageFormatInfo(prev.format);
|
const DxvkFormatInfo* formatInfo = imageFormatInfo(prev.format);
|
||||||
@ -984,8 +986,8 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
attributes.push_back(attrib);
|
attrList.at(i) = attrib;
|
||||||
|
|
||||||
// Create vertex input binding description. The
|
// Create vertex input binding description. The
|
||||||
// stride is dynamic state in D3D11 and will be
|
// stride is dynamic state in D3D11 and will be
|
||||||
@ -994,18 +996,19 @@ namespace dxvk {
|
|||||||
binding.binding = pInputElementDescs[i].InputSlot;
|
binding.binding = pInputElementDescs[i].InputSlot;
|
||||||
binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate;
|
binding.fetchRate = pInputElementDescs[i].InstanceDataStepRate;
|
||||||
binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA
|
binding.inputRate = pInputElementDescs[i].InputSlotClass == D3D11_INPUT_PER_INSTANCE_DATA
|
||||||
? VK_VERTEX_INPUT_RATE_INSTANCE
|
? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
: VK_VERTEX_INPUT_RATE_VERTEX;
|
|
||||||
|
|
||||||
// Check if the binding was already defined. If so, the
|
// Check if the binding was already defined. If so, the
|
||||||
// parameters must be identical (namely, the input rate).
|
// parameters must be identical (namely, the input rate).
|
||||||
bool bindingDefined = false;
|
bool bindingDefined = false;
|
||||||
|
|
||||||
for (const auto& existingBinding : bindings) {
|
for (uint32_t j = 0; j < i; j++) {
|
||||||
if (binding.binding == existingBinding.binding) {
|
uint32_t bindingId = attrList.at(j).binding;
|
||||||
|
|
||||||
|
if (binding.binding == bindingId) {
|
||||||
bindingDefined = true;
|
bindingDefined = true;
|
||||||
|
|
||||||
if (binding.inputRate != existingBinding.inputRate) {
|
if (binding.inputRate != bindList.at(bindingId).inputRate) {
|
||||||
Logger::err(str::format(
|
Logger::err(str::format(
|
||||||
"D3D11Device: Conflicting input rate for binding ",
|
"D3D11Device: Conflicting input rate for binding ",
|
||||||
binding.binding));
|
binding.binding));
|
||||||
@ -1013,19 +1016,29 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!bindingDefined)
|
if (!bindingDefined)
|
||||||
bindings.push_back(binding);
|
bindList.at(binding.binding) = binding;
|
||||||
|
|
||||||
|
if (entry != nullptr) {
|
||||||
|
attrMask |= 1u << i;
|
||||||
|
bindMask |= 1u << binding.binding;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Compact the attribute and binding lists to filter
|
||||||
|
// out attributes and bindings not used by the shader
|
||||||
|
uint32_t attrCount = CompactSparseList(attrList.data(), attrMask);
|
||||||
|
uint32_t bindCount = CompactSparseList(bindList.data(), bindMask);
|
||||||
|
|
||||||
// Check if there are any semantics defined in the
|
// Check if there are any semantics defined in the
|
||||||
// shader that are not included in the current input
|
// shader that are not included in the current input
|
||||||
// layout.
|
// layout.
|
||||||
for (auto i = inputSignature->begin(); i != inputSignature->end(); i++) {
|
for (auto i = inputSignature->begin(); i != inputSignature->end(); i++) {
|
||||||
bool found = i->systemValue != DxbcSystemValue::None;
|
bool found = i->systemValue != DxbcSystemValue::None;
|
||||||
|
|
||||||
for (uint32_t j = 0; j < attributes.size() && !found; j++)
|
for (uint32_t j = 0; j < attrCount && !found; j++)
|
||||||
found = attributes.at(j).location == i->registerId;
|
found = attrList.at(j).location == i->registerId;
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
Logger::warn(str::format(
|
Logger::warn(str::format(
|
||||||
@ -1035,20 +1048,13 @@ namespace dxvk {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::sort(bindings.begin(), bindings.end(),
|
|
||||||
[] (const DxvkVertexBinding& a, const DxvkVertexBinding& b) {
|
|
||||||
return a.binding < b.binding;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create the actual input layout object
|
// Create the actual input layout object
|
||||||
// if the application requests it.
|
// if the application requests it.
|
||||||
if (ppInputLayout != nullptr) {
|
if (ppInputLayout != nullptr) {
|
||||||
*ppInputLayout = ref(
|
*ppInputLayout = ref(
|
||||||
new D3D11InputLayout(this,
|
new D3D11InputLayout(this,
|
||||||
attributes.size(),
|
attrCount, attrList.data(),
|
||||||
attributes.data(),
|
bindCount, bindList.data()));
|
||||||
bindings.size(),
|
|
||||||
bindings.data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return S_OK;
|
return S_OK;
|
||||||
|
@ -8,6 +8,19 @@
|
|||||||
|
|
||||||
namespace dxvk {
|
namespace dxvk {
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
UINT CompactSparseList(T* pData, UINT Mask) {
|
||||||
|
uint32_t count = 0;
|
||||||
|
|
||||||
|
while (Mask != 0) {
|
||||||
|
uint32_t id = bit::tzcnt(Mask);
|
||||||
|
pData[count++] = pData[id];
|
||||||
|
Mask &= Mask - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT DecodeSampleCount(
|
HRESULT DecodeSampleCount(
|
||||||
UINT Count,
|
UINT Count,
|
||||||
VkSampleCountFlagBits* pCount);
|
VkSampleCountFlagBits* pCount);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user