[D3D12] Indexed line loops

This commit is contained in:
Triang3l 2018-10-23 13:36:03 +03:00
parent 096d78a2f9
commit 31e0581304
2 changed files with 118 additions and 27 deletions

View File

@ -1149,6 +1149,12 @@ bool D3D12CommandProcessor::IssueDraw(PrimitiveType primitive_type,
bool indexed = index_buffer_info != nullptr && index_buffer_info->guest_base; bool indexed = index_buffer_info != nullptr && index_buffer_info->guest_base;
// TODO(Triang3l): Non-indexed line loops (by movc'ing zero to the vertex
// index if it's one beyond the end).
if (primitive_type == PrimitiveType::kLineLoop && !indexed) {
return false;
}
// Set the primitive topology. // Set the primitive topology.
PrimitiveType primitive_type_converted = PrimitiveType primitive_type_converted =
PrimitiveConverter::GetReplacementPrimitiveType(primitive_type); PrimitiveConverter::GetReplacementPrimitiveType(primitive_type);

View File

@ -145,8 +145,13 @@ void PrimitiveConverter::EndFrame() { buffer_pool_->EndFrame(); }
PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType( PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
PrimitiveType type) { PrimitiveType type) {
if (type == PrimitiveType::kTriangleFan) { switch (type) {
return PrimitiveType::kTriangleList; case PrimitiveType::kTriangleFan:
return PrimitiveType::kTriangleList;
case PrimitiveType::kLineLoop:
return PrimitiveType::kLineStrip;
default:
break;
} }
return type; return type;
} }
@ -166,15 +171,20 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
// 16-bit and the latter for 32-bit indices), we can use the buffer directly. // 16-bit and the latter for 32-bit indices), we can use the buffer directly.
uint32_t reset_index_host = index_32bit ? 0xFFFFFFFFu : 0xFFFFu; uint32_t reset_index_host = index_32bit ? 0xFFFFFFFFu : 0xFFFFu;
// Degenerate line loops are just lines.
if (source_type == PrimitiveType::kLineLoop && index_count == 2) {
source_type = PrimitiveType::kLineStrip;
}
// Check if need to convert at all. // Check if need to convert at all.
if (source_type != PrimitiveType::kTriangleFan) { if (source_type == PrimitiveType::kTriangleStrip ||
source_type == PrimitiveType::kLineStrip) {
if (!reset || reset_index == reset_index_host) { if (!reset || reset_index == reset_index_host) {
return ConversionResult::kConversionNotNeeded; return ConversionResult::kConversionNotNeeded;
} }
if (source_type != PrimitiveType::kTriangleStrip && } else if (source_type != PrimitiveType::kTriangleFan &&
source_type != PrimitiveType::kLineStrip) { source_type != PrimitiveType::kLineLoop) {
return ConversionResult::kConversionNotNeeded; return ConversionResult::kConversionNotNeeded;
}
} }
#if FINE_GRAINED_DRAW_SCOPES #if FINE_GRAINED_DRAW_SCOPES
@ -253,30 +263,23 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
uint32_t converted_index_count = 0; uint32_t converted_index_count = 0;
bool conversion_needed = false; bool conversion_needed = false;
bool simd = false; bool simd = false;
// Optimization specific to primitive types - if reset index not found in the
// source index buffer, can set this to false and use a faster way of copying.
bool reset_actually_used = reset;
if (source_type == PrimitiveType::kTriangleFan) { if (source_type == PrimitiveType::kTriangleFan) {
// Triangle fans are not supported by Direct3D 12 at all. // Triangle fans are not supported by Direct3D 12 at all.
conversion_needed = true; conversion_needed = true;
if (reset) { if (reset) {
uint32_t current_fan_index_count = 0; uint32_t current_fan_index_count = 0;
if (index_format == IndexFormat::kInt32) { for (uint32_t i = 0; i < index_count; ++i) {
for (uint32_t i = 0; i < index_count; ++i) { uint32_t index =
if (source_32[i] == reset_index) { index_format == IndexFormat::kInt32 ? source_32[i] : source_16[i];
current_fan_index_count = 0; if (index == reset_index) {
continue; current_fan_index_count = 0;
} continue;
if (++current_fan_index_count >= 3) {
converted_index_count += 3;
}
} }
} else { if (++current_fan_index_count >= 3) {
for (uint32_t i = 0; i < index_count; ++i) { converted_index_count += 3;
if (source_16[i] == reset_index) {
current_fan_index_count = 0;
continue;
}
if (++current_fan_index_count >= 3) {
converted_index_count += 3;
}
} }
} }
} else { } else {
@ -371,6 +374,31 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
} }
} }
#endif // XE_ARCH_AMD64 #endif // XE_ARCH_AMD64
} else if (source_type == PrimitiveType::kLineLoop) {
conversion_needed = true;
if (reset) {
reset_actually_used = false;
uint32_t current_strip_index_count = 0;
for (uint32_t i = 0; i < index_count; ++i) {
uint32_t index =
index_format == IndexFormat::kInt32 ? source_32[i] : source_16[i];
if (index == reset_index) {
reset_actually_used = true;
// Loop strips with more than 2 vertices.
if (current_strip_index_count > 2) {
++converted_index_count;
}
current_strip_index_count = 0;
continue;
}
// Start a new strip if 2 vertices, add one vertex if more.
if (++current_strip_index_count >= 2) {
converted_index_count += current_strip_index_count == 2 ? 2 : 1;
}
}
} else {
converted_index_count = index_count + 1;
}
} }
converted_indices.converted_index_count = converted_index_count; converted_indices.converted_index_count = converted_index_count;
@ -506,10 +534,67 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
} }
} }
#endif // XE_ARCH_AMD64 #endif // XE_ARCH_AMD64
} else if (source_type == PrimitiveType::kLineLoop) {
if (reset_actually_used) {
uint32_t current_strip_index_count = 0;
uint32_t current_strip_first_index = 0;
if (index_format == IndexFormat::kInt32) {
uint32_t* target_32 = reinterpret_cast<uint32_t*>(target);
for (uint32_t i = 0; i < index_count; ++i) {
uint32_t index = source_32[i];
if (index == reset_index) {
if (current_strip_index_count > 2) {
*(target_32++) = current_strip_first_index;
}
current_strip_index_count = 0;
continue;
}
if (current_strip_index_count == 0) {
current_strip_first_index = index;
}
++current_strip_index_count;
if (current_strip_index_count >= 2) {
if (current_strip_index_count == 2) {
*(target_32++) = current_strip_first_index;
}
*(target_32++) = index;
}
}
} else {
uint16_t* target_16 = reinterpret_cast<uint16_t*>(target);
for (uint32_t i = 0; i < index_count; ++i) {
uint16_t index = source_16[i];
if (index == reset_index) {
if (current_strip_index_count > 2) {
*(target_16++) = uint16_t(current_strip_first_index);
}
current_strip_index_count = 0;
continue;
}
if (current_strip_index_count == 0) {
current_strip_first_index = index;
}
++current_strip_index_count;
if (current_strip_index_count >= 2) {
if (current_strip_index_count == 2) {
*(target_16++) = uint16_t(current_strip_first_index);
}
*(target_16++) = index;
}
}
}
} else {
std::memcpy(target, source, index_count * index_size);
if (converted_index_count > index_count) {
if (index_format == IndexFormat::kInt32) {
reinterpret_cast<uint32_t*>(target)[index_count] = source_32[0];
} else {
reinterpret_cast<uint16_t*>(target)[index_count] = source_16[0];
}
}
}
} }
// TODO(Triang3l): Line loops.
// Cache and return the indices. // Cache and return the indices.
converted_indices.gpu_address = gpu_address; converted_indices.gpu_address = gpu_address;
converted_indices_cache_.insert( converted_indices_cache_.insert(