Commit 186fe990 by Shahbaz Youssefi Committed by Commit Bot

Vulkan: Redo RewriteAtomicCounters

With MonomorphizeUnsupportedFunctionsInVulkanGLSL and RewriteArrayOfArrayOfOpaqueUniforms transformations run, it is no longer possible to encounter array of array of atomic counters, or have any passed to functions. As a result, RewriteAtomicCounters is greatly simplified. Additionally, it is no longer necessary to pass binding/offset information for atomic counters around and they can use constants. This change removes dependency on the shaderStorageBufferArrayDynamicIndexing Vulkan feature. Bug: angleproject:3726 Bug: angleproject:3881 Change-Id: Ia43092a668f60d009eccbbceeed5deaf105a5895 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2633687Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarTim Van Patten <timvp@google.com> Commit-Queue: Shahbaz Youssefi <syoussefi@chromium.org>
parent 64c89120
...@@ -1379,9 +1379,6 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF ...@@ -1379,9 +1379,6 @@ angle::Result RendererVk::initializeDevice(DisplayVk *displayVk, uint32_t queueF
mPhysicalDeviceFeatures.shaderUniformBufferArrayDynamicIndexing; mPhysicalDeviceFeatures.shaderUniformBufferArrayDynamicIndexing;
enabledFeatures.features.shaderSampledImageArrayDynamicIndexing = enabledFeatures.features.shaderSampledImageArrayDynamicIndexing =
mPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing; mPhysicalDeviceFeatures.shaderSampledImageArrayDynamicIndexing;
// Used to support atomic counter emulation:
enabledFeatures.features.shaderStorageBufferArrayDynamicIndexing =
mPhysicalDeviceFeatures.shaderStorageBufferArrayDynamicIndexing;
// Used to support APPLE_clip_distance // Used to support APPLE_clip_distance
enabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance; enabledFeatures.features.shaderClipDistance = mPhysicalDeviceFeatures.shaderClipDistance;
// Used to support OES_sample_shading // Used to support OES_sample_shading
......
...@@ -1016,12 +1016,8 @@ bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features) ...@@ -1016,12 +1016,8 @@ bool CanSupportGPUShader5EXT(const VkPhysicalDeviceFeatures &features)
// textureGatherOffsets family of functions. // textureGatherOffsets family of functions.
// - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing: // - shaderSampledImageArrayDynamicIndexing and shaderUniformBufferArrayDynamicIndexing:
// dynamically uniform indices for samplers and uniform buffers. // dynamically uniform indices for samplers and uniform buffers.
// - shaderStorageBufferArrayDynamicIndexing: While EXT_gpu_shader5 doesn't require dynamically
// uniform indices on storage buffers, we need it as we emulate atomic counter buffers with
// storage buffers (and atomic counter buffers *can* be indexed in that way).
return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing && return features.shaderImageGatherExtended && features.shaderSampledImageArrayDynamicIndexing &&
features.shaderUniformBufferArrayDynamicIndexing && features.shaderUniformBufferArrayDynamicIndexing;
features.shaderStorageBufferArrayDynamicIndexing;
} }
} // namespace vk } // namespace vk
......
...@@ -46,7 +46,7 @@ the name. Examples: ...@@ -46,7 +46,7 @@ the name. Examples:
1442 OPENGL : dEQP-GLES31.functional.separate_shader.* = SKIP 1442 OPENGL : dEQP-GLES31.functional.separate_shader.* = SKIP
1442 D3D11 : dEQP-GLES31.functional.separate_shader.* = SKIP 1442 D3D11 : dEQP-GLES31.functional.separate_shader.* = SKIP
// Bug in older drivers: // Unsupported feature:
3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL 3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL
// Failing test in Nvidia's OpenGL implementation on windows: // Failing test in Nvidia's OpenGL implementation on windows:
......
...@@ -217,26 +217,9 @@ ...@@ -217,26 +217,9 @@
4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.points_8_samples = FAIL 4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.points_8_samples = FAIL
4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.triangles_max_samples = FAIL 4110 ANDROID VULKAN : dEQP-GLES31.functional.shaders.helper_invocation.value.triangles_max_samples = FAIL
// Passing on recent drivers:
3726 VULKAN ANDROID : dEQP-GLES31.functional.ssbo.layout.* = FAIL
3726 VULKAN ANDROID : dEQP-GLES31.functional.synchronization.inter_call.without_memory_barrier.*atomic_counter* = FAIL
3726 VULKAN ANDROID : dEQP-GLES31.functional.compute.basic.atomic_counter* = FAIL
// Seem to trigger LowMemoryKiller when run in a certain sequence // Seem to trigger LowMemoryKiller when run in a certain sequence
5185 VULKAN ANDROID : dEQP-GLES31.functional.atomic_counter.* = SKIP 5185 VULKAN ANDROID : dEQP-GLES31.functional.atomic_counter.* = SKIP
// Arrays of atomic counters not supported on Android (lacking Vulkan feature)
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_literal_compute = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.const_expression_compute = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_vertex = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_fragment = FAIL
3881 VULKAN ANDROID : dEQP-GLES31.functional.shaders.opaque_type_indexing.atomic_counter.*uniform_compute = FAIL
// SSBO synchronization: // SSBO synchronization:
4097 VULKAN PIXEL2ORXL : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL 4097 VULKAN PIXEL2ORXL : dEQP-GLES31.functional.synchronization.in_invocation.ssbo_alias_overwrite = FAIL
......
...@@ -32,7 +32,6 @@ ...@@ -32,7 +32,6 @@
3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP 3573 VULKAN : KHR-GLES31.core.texture_buffer.texture_buffer_texture_buffer_range = SKIP
// Dispatch indirect: // Dispatch indirect:
3726 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.pipeline-compute-chain = FAIL
4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.resource-ubo = FAIL 4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.resource-ubo = FAIL
4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.built-in-variables = FAIL 4194 VULKAN PIXEL2ORXL : KHR-GLES31.core.compute_shader.built-in-variables = FAIL
...@@ -88,10 +87,6 @@ ...@@ -88,10 +87,6 @@
// Crashes on Android // Crashes on Android
4107 VULKAN ANDROID : KHR-GLES31.core.shader_storage_buffer_object.advanced-unsizedArrayLength* = SKIP 4107 VULKAN ANDROID : KHR-GLES31.core.shader_storage_buffer_object.advanced-unsizedArrayLength* = SKIP
// Passing on recent drivers:
3726 VULKAN ANDROID : KHR-GLES31.core.shader_atomic_counters.* = FAIL
3726 VULKAN ANDROID : KHR-GLES31.core.shader_atomic_counters.advanced-usage-* = SKIP
// Explicit uniform locations: // Explicit uniform locations:
4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max = FAIL 4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max = FAIL
4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array = FAIL 4219 VULKAN PIXEL2ORXL : KHR-GLES31.core.explicit_uniform_location.uniform-loc-mix-with-implicit-max-array = FAIL
......
...@@ -55,7 +55,6 @@ ...@@ -55,7 +55,6 @@
// Android failures // Android failures
// Dynamic indexing features not supported on Qualcomm // Dynamic indexing features not supported on Qualcomm
5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.atomic_counters_array_indexing = FAIL
5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.images_array_indexing = FAIL 5435 VULKAN ANDROID : KHR-GLES32.core.gpu_shader5.images_array_indexing = FAIL
// Texture buffer failures // Texture buffer failures
......
...@@ -115,10 +115,6 @@ TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue) ...@@ -115,10 +115,6 @@ TEST_P(AtomicCounterBufferTest31, OffsetNotAllSpecifiedWithSameValue)
// Tests atomic counter reads using compute shaders. Used as a confidence check for the translator. // Tests atomic counter reads using compute shaders. Used as a confidence check for the translator.
TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute) TEST_P(AtomicCounterBufferTest31, AtomicCounterReadCompute)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping due to a bug on the Adreno OpenGLES Android driver. // Skipping due to a bug on the Adreno OpenGLES Android driver.
// http://anglebug.com/2925 // http://anglebug.com/2925
ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES()); ANGLE_SKIP_TEST_IF(IsAndroid() && IsAdreno() && IsOpenGLES());
...@@ -148,10 +144,6 @@ void main() ...@@ -148,10 +144,6 @@ void main()
// Test atomic counter read. // Test atomic counter read.
TEST_P(AtomicCounterBufferTest31, AtomicCounterRead) TEST_P(AtomicCounterBufferTest31, AtomicCounterRead)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
...@@ -191,11 +183,7 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead) ...@@ -191,11 +183,7 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
{ {
// Skipping due to a bug on the Qualcomm driver. // Skipping due to a bug on the Qualcomm driver.
// http://anglebug.com/3726 // http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsNexus5X()); ANGLE_SKIP_TEST_IF(IsNexus5X() && IsOpenGLES());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
...@@ -245,10 +233,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead) ...@@ -245,10 +233,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRangeRead)
// there are bugs in how we count valid bindings. // there are bugs in how we count valid bindings.
TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind) TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
...@@ -319,10 +303,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind) ...@@ -319,10 +303,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterBufferRepeatedBindUnbind)
// Test atomic counter increment and decrement. // Test atomic counter increment and decrement.
TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement) TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = constexpr char kCS[] =
"#version 310 es\n" "#version 310 es\n"
"layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n" "layout(local_size_x=1, local_size_y=1, local_size_z=1) in;\n"
...@@ -364,10 +344,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement) ...@@ -364,10 +344,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterIncrementAndDecrement)
// Tests multiple atomic counter buffers. // Tests multiple atomic counter buffers.
TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers) TEST_P(AtomicCounterBufferTest31, AtomicCounterMultipleBuffers)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
GLint maxAtomicCounterBuffers = 0; GLint maxAtomicCounterBuffers = 0;
glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers); glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &maxAtomicCounterBuffers);
constexpr unsigned int kBufferCount = 3; constexpr unsigned int kBufferCount = 3;
...@@ -430,10 +406,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray) ...@@ -430,10 +406,6 @@ TEST_P(AtomicCounterBufferTest31, AtomicCounterArrayOfArray)
// Intel's Windows OpenGL driver crashes in this test. http://anglebug.com/3791 // Intel's Windows OpenGL driver crashes in this test. http://anglebug.com/3791
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(binding = 0) uniform atomic_uint ac[7][5][3]; layout(binding = 0) uniform atomic_uint ac[7][5][3];
......
...@@ -401,10 +401,6 @@ TEST_P(ComputeShaderTest, BufferImageBuffer) ...@@ -401,10 +401,6 @@ TEST_P(ComputeShaderTest, BufferImageBuffer)
// See http://anglebug.com/3536 // See http://anglebug.com/3536
ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows()); ANGLE_SKIP_TEST_IF(IsOpenGL() && IsIntel() && IsWindows());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS0[] = R"(#version 310 es constexpr char kCS0[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(binding = 0, offset = 4) uniform atomic_uint ac[2]; layout(binding = 0, offset = 4) uniform atomic_uint ac[2];
...@@ -476,10 +472,6 @@ TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer) ...@@ -476,10 +472,6 @@ TEST_P(ComputeShaderTest, ImageAtomicCounterBuffer)
// Flaky hang. http://anglebug.com/3636 // Flaky hang. http://anglebug.com/3636
ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL()); ANGLE_SKIP_TEST_IF(IsWindows() && IsNVIDIA() && IsDesktopOpenGL());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS0[] = R"(#version 310 es constexpr char kCS0[] = R"(#version 310 es
layout(local_size_x=1, local_size_y=1, local_size_z=1) in; layout(local_size_x=1, local_size_y=1, local_size_z=1) in;
layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2]; layout(r32ui, binding = 0) writeonly uniform highp uimage2D uImage[2];
...@@ -3934,10 +3926,6 @@ TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch) ...@@ -3934,10 +3926,6 @@ TEST_P(ComputeShaderTest, DispatchConvertVertexDispatch)
{ {
ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2")); ANGLE_SKIP_TEST_IF(!IsGLExtensionEnabled("GL_OES_vertex_type_10_10_10_2"));
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr uint32_t kVertexCount = 6; constexpr uint32_t kVertexCount = 6;
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
......
...@@ -3265,10 +3265,6 @@ TEST_P(GLSLTest_ES31, AtomicCounterArrayLength) ...@@ -3265,10 +3265,6 @@ TEST_P(GLSLTest_ES31, AtomicCounterArrayLength)
// http://anglebug.com/3782 // http://anglebug.com/3782
ANGLE_SKIP_TEST_IF(IsOpenGL()); ANGLE_SKIP_TEST_IF(IsOpenGL());
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
constexpr char kCS[] = R"(#version 310 es constexpr char kCS[] = R"(#version 310 es
precision mediump float; precision mediump float;
layout(local_size_x=1) in; layout(local_size_x=1) in;
......
...@@ -890,8 +890,6 @@ TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader) ...@@ -890,8 +890,6 @@ TEST_P(ProgramBinaryES31Test, ProgramBinaryWithComputeShader)
// Tests that saving and loading a program attached with computer shader. // Tests that saving and loading a program attached with computer shader.
TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader) TEST_P(ProgramBinaryES31Test, ProgramBinaryWithAtomicCounterComputeShader)
{ {
// http://anglebug.com/4092
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// We can't run the test if no program binary formats are supported. // We can't run the test if no program binary formats are supported.
GLint binaryFormatCount = 0; GLint binaryFormatCount = 0;
glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount); glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &binaryFormatCount);
......
...@@ -58,10 +58,6 @@ class VulkanDescriptorSetTest : public ANGLETest ...@@ -58,10 +58,6 @@ class VulkanDescriptorSetTest : public ANGLETest
// Test atomic counter read. // Test atomic counter read.
TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool) TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool)
{ {
// Skipping due to a bug on the Qualcomm Vulkan Android driver.
// http://anglebug.com/3726
ANGLE_SKIP_TEST_IF(IsAndroid() && IsVulkan());
// Skipping test while we work on enabling atomic counter buffer support in th D3D renderer. // Skipping test while we work on enabling atomic counter buffer support in th D3D renderer.
// http://anglebug.com/1729 // http://anglebug.com/1729
ANGLE_SKIP_TEST_IF(IsD3D11()); ANGLE_SKIP_TEST_IF(IsD3D11());
...@@ -103,4 +99,4 @@ TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool) ...@@ -103,4 +99,4 @@ TEST_P(VulkanDescriptorSetTest, AtomicCounterReadLimitedDescriptorPool)
ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetTest, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER()); ANGLE_INSTANTIATE_TEST(VulkanDescriptorSetTest, ES31_VULKAN(), ES31_VULKAN_SWIFTSHADER());
} // namespace } // namespace
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment