[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;
// 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.
PrimitiveType primitive_type_converted =
PrimitiveConverter::GetReplacementPrimitiveType(primitive_type);

View File

@ -145,8 +145,13 @@ void PrimitiveConverter::EndFrame() { buffer_pool_->EndFrame(); }
PrimitiveType PrimitiveConverter::GetReplacementPrimitiveType(
PrimitiveType type) {
if (type == PrimitiveType::kTriangleFan) {
switch (type) {
case PrimitiveType::kTriangleFan:
return PrimitiveType::kTriangleList;
case PrimitiveType::kLineLoop:
return PrimitiveType::kLineStrip;
default:
break;
}
return type;
}
@ -166,16 +171,21 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
// 16-bit and the latter for 32-bit indices), we can use the buffer directly.
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.
if (source_type != PrimitiveType::kTriangleFan) {
if (source_type == PrimitiveType::kTriangleStrip ||
source_type == PrimitiveType::kLineStrip) {
if (!reset || reset_index == reset_index_host) {
return ConversionResult::kConversionNotNeeded;
}
if (source_type != PrimitiveType::kTriangleStrip &&
source_type != PrimitiveType::kLineStrip) {
} else if (source_type != PrimitiveType::kTriangleFan &&
source_type != PrimitiveType::kLineLoop) {
return ConversionResult::kConversionNotNeeded;
}
}
#if FINE_GRAINED_DRAW_SCOPES
SCOPE_profile_cpu_f("gpu");
@ -253,14 +263,18 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
uint32_t converted_index_count = 0;
bool conversion_needed = 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) {
// Triangle fans are not supported by Direct3D 12 at all.
conversion_needed = true;
if (reset) {
uint32_t current_fan_index_count = 0;
if (index_format == IndexFormat::kInt32) {
for (uint32_t i = 0; i < index_count; ++i) {
if (source_32[i] == reset_index) {
uint32_t index =
index_format == IndexFormat::kInt32 ? source_32[i] : source_16[i];
if (index == reset_index) {
current_fan_index_count = 0;
continue;
}
@ -268,17 +282,6 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
converted_index_count += 3;
}
}
} else {
for (uint32_t i = 0; i < index_count; ++i) {
if (source_16[i] == reset_index) {
current_fan_index_count = 0;
continue;
}
if (++current_fan_index_count >= 3) {
converted_index_count += 3;
}
}
}
} else {
converted_index_count = 3 * (index_count - 2);
}
@ -371,6 +374,31 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
}
}
#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;
@ -506,9 +534,66 @@ PrimitiveConverter::ConversionResult PrimitiveConverter::ConvertPrimitives(
}
}
#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.
converted_indices.gpu_address = gpu_address;