From 7b878305984a851501e0007f4a4c3979c80f00a4 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Wed, 16 Oct 2013 20:46:13 -0400 Subject: [PATCH 01/23] Made changes to compile in SIG Lab system. --- .gitignore | 1 + Part1/src/main.h | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 4b00bc9..921ac68 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.slo *.lo *.o +*.deps # Compiled Dynamic libraries *.so diff --git a/Part1/src/main.h b/Part1/src/main.h index 2b818bf..8eddb37 100644 --- a/Part1/src/main.h +++ b/Part1/src/main.h @@ -2,7 +2,7 @@ #define MAIN_H #include -#include +#include #include #include @@ -48,8 +48,8 @@ GLuint program[2]; const unsigned int HEIGHT_FIELD = 0; const unsigned int PASS_THROUGH = 1; -const int field_width = 800; -const int field_height = 800; +const int field_width = 296; +const int field_height = 296; float fovy = 60.0f; float zNear = 0.10; @@ -62,7 +62,7 @@ glm::vec3 cameraPosition(1.75,1.75,1.35); //----------CUDA STUFF----------- //------------------------------- -int width=1000; int height=1000; +int width=500; int height=500; //------------------------------- //-------------MAIN-------------- From 05807b05322aec390e162dfb95c509545fe9b6c3 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Thu, 17 Oct 2013 01:07:35 -0400 Subject: [PATCH 02/23] Naive Acceleration. --- Part1/PROJ_WIN/src/kernel.cu.deps | 603 +++++++++++++++--------------- Part1/src/kernel.cu | 25 +- 2 files changed, 321 insertions(+), 307 deletions(-) diff --git a/Part1/PROJ_WIN/src/kernel.cu.deps b/Part1/PROJ_WIN/src/kernel.cu.deps index 35aaf16..b90df28 100644 --- a/Part1/PROJ_WIN/src/kernel.cu.deps +++ b/Part1/PROJ_WIN/src/kernel.cu.deps @@ -1,18 +1,18 @@ C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\cuda_runtime.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_config.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\sal.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\sal.h c:\program files (x86)\microsoft visual studio 10.0\vc\include\codeanalysis\sourceannotations.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vadefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vadefs.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\builtin_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\device_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_defines.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\driver_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_defines.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stddef.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stddef.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\surface_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\driver_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\texture_types.h @@ -68,12 +68,12 @@ c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\surface_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\texture_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\vector_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_defines.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\time.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wtime.inl -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\time.inl +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\time.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wtime.inl +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\time.inl c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\math_functions.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\builtin_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\device_types.h @@ -82,16 +82,16 @@ c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\surface_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\texture_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\vector_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_defines.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cmath -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\yvals.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\use_ansi.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstdlib +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdlib.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cmath +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\yvals.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\use_ansi.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\math.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstdlib c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\cuda_surface_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\builtin_types.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\device_types.h @@ -239,285 +239,286 @@ c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\host_defines.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\vector_functions.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\device_launch_parameters.h c:\program files\nvidia gpu computing toolkit\cuda\v5.5\include\vector_types.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\swprintf.inl +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdio.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\swprintf.inl C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\cuda.h -c:\users\liam\project3-simulation\part1\src\glm/glm.hpp -c:\users\liam\project3-simulation\part1\src\glm\core/_fixes.hpp -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\climits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cfloat -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\float.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtwrn.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ymath.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cwchar -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wchar.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xstddef -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstddef -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstdio -c:\users\liam\project3-simulation\part1\src\glm\core/setup.hpp -c:\users\liam\project3-simulation\part1\src\glm\./core/_detail.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\setup.hpp -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cassert -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\assert.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -c:\users\liam\project3-simulation\part1\src\glm\./core/_vectorize.hpp -c:\users\liam\project3-simulation\part1\src\glm\./core/type.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_half.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_half.inl -c:\users\liam\project3-simulation\part1\src\glm\core\_detail.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_float.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_half.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\setup.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_int.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\setup.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_detail.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_gentype.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_size.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec1.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_gentype.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_float.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_int.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_size.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_swizzle.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_swizzle_func.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec1.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec2.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_float.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_int.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_size.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_swizzle.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec2.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec3.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_float.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_int.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_size.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_swizzle.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec3.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec4.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_float.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_int.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_size.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_swizzle.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_vec4.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x2.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_gentype.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x2.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x3.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x3.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x4.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat2x4.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x2.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x2.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x3.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x3.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x4.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat3x4.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x2.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x2.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x3.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x3.inl -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x4.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\type_mat4x4.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_trigonometric.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_trigonometric.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_exponential.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_exponential.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_common.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_fixes.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_common.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_packing.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_packing.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_geometric.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_geometric.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_matrix.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_matrix.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_vector_relational.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\_detail.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_vector_relational.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_integer.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_integer.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/func_noise.hpp -c:\users\liam\project3-simulation\part1\src\glm\core\func_noise.inl -c:\users\liam\project3-simulation\part1\src\glm\./core/_swizzle.hpp -c:\users\liam\project3-simulation\part1\src\utilities.h -c:\users\liam\project3-simulation\part1\src\glm/glm.hpp -c:\users\liam\project3-simulation\part1\src\glm\core/_fixes.hpp -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\new -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\eh.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\malloc.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xutility -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\utility -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iosfwd -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstring -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdbg.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\type_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xtr1common -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\typeinfo -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\intrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\setjmp.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\immintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wmmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\nmmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\smmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\tmmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\pmmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\emmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mm3dnow.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mmintrin.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\istream -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ostream -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ios -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocnum -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\streambuf -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xiosbase -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocale -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdexcept -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xstring -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocinfo -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocinfo.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ctype.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\locale.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xdebug -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cerrno -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\errno.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\share.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iterator -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\sstream -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfunctional -c:\users\liam\project3-simulation\part1\src\cudaMat4.h -c:\users\liam\project3-simulation\part1\src\glm/glm.hpp -c:\users\liam\project3-simulation\part1\src\glm\core/_fixes.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm/glm.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core/_fixes.hpp +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\climits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cfloat +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\float.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtwrn.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\limits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ymath.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cwchar +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wchar.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xstddef +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstddef +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstdio +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core/setup.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/_detail.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\setup.hpp +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cassert +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\assert.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/_vectorize.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/type.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_half.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_half.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_detail.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_float.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_half.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\setup.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_int.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\setup.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_detail.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_gentype.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_size.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec1.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_gentype.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_float.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_int.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_size.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_swizzle.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_swizzle_func.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec1.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec2.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_float.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_int.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_size.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_swizzle.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec2.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec3.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_float.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_int.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_size.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_swizzle.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec3.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec4.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_float.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_int.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_size.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_swizzle.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_vec4.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x2.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_gentype.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x2.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x3.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x3.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x4.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat2x4.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x2.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x2.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x3.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x3.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x4.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat3x4.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x2.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x2.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x3.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x3.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x4.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\type_mat4x4.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_trigonometric.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_trigonometric.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_exponential.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_exponential.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_common.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_fixes.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_common.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_packing.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_packing.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_geometric.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_geometric.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_matrix.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_matrix.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_vector_relational.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\_detail.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_vector_relational.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_integer.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_integer.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/func_noise.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core\func_noise.inl +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\./core/_swizzle.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\utilities.h +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm/glm.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core/_fixes.hpp +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\algorithm +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmemory +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\new +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\exception +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\eh.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\malloc.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xutility +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\utility +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iosfwd +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cstring +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdbg.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\type_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xtr1common +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxtype_traits +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\typeinfo +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\intrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\setjmp.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\immintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\wmmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\nmmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\smmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\tmmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\pmmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\emmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xmmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ammintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mm3dnow.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\mmintrin.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfwrap1 +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xxshared +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\istream +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ostream +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ios +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocnum +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\streambuf +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xiosbase +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocale +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\stdexcept +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xstring +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocinfo +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xlocinfo.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\ctype.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\locale.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xdebug +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\system_error +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\cerrno +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\errno.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\crtdefs.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\share.h +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iterator +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\sstream +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\string +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\vector +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\xfunctional +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\cudaMat4.h +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm/glm.hpp +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\glm\core/_fixes.hpp C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\cuda_runtime.h -c:\users\liam\project3-simulation\part1\src\kernel.h +c:\users\hms\desktop\cis565-rohithc\project3-simulation\part1\src\kernel.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/random.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/detail/config.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/detail/config/config.h @@ -534,7 +535,7 @@ C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/detail/co C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/detail/config/hd_warning_disable.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/detail/cstdint.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/random/discard_block_engine.h -C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iostream +c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\iostream C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/random/detail/random_core_access.h C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/random/detail/discard_block_engine.inl C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include\thrust/random/linear_congruential_engine.h diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 32b3cb1..80b6daf 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -17,7 +17,7 @@ dim3 threadsPerBlock(blockSize); int numObjects; const float planetMass = 3e8; const __device__ float starMass = 5e10; - +const __device__ float GravConst = 6.67384e-11; const float scene_scale = 2e2; //size of the height map in simulation space glm::vec4 * dev_pos; @@ -106,7 +106,7 @@ void generateRandomVelArray(int time, int N, glm::vec3 * arr, float scale) } } -//TODO: Determine force between two bodies +//TODO: Done! __device__ glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) { @@ -117,16 +117,29 @@ glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) // G*m_us*m_them G*m_them //a = ------------- = -------- // m_us*r^2 r^2 + glm::vec3 forceDir = glm::vec3 (them.x - us.x, them.y - us.y, them.z - us.z); + float dist = sqrt (glm::dot (forceDir, forceDir)); + forceDir /= dist; // Force direction is now normalized and we have distance between the two objects (r)! + + float accVal = (GravConst * them.w) / (dist*dist); - return glm::vec3(0.0f); + return forceDir * accVal; } -//TODO: Core force calc kernel global memory +//TODO: Done! __device__ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { - glm::vec3 acc = calculateAcceleration(my_pos, glm::vec4(0,0,0,starMass)); - return acc; + // NOTE: their_pos is a pointer to global memory. + glm::vec3 acc = glm::vec3 (0); + for (int i = 0; i < N; i ++) + { + if (their_pos [i] == my_pos) + continue; + acc += calculateAcceleration(my_pos, their_pos [i]); + } + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + return acc; } From 338e1ec3964f2a90a35dffb38d2190239774031f Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Thu, 17 Oct 2013 03:54:29 -0400 Subject: [PATCH 03/23] Shared memory accn calculation done. Need to fix crash when visualizing (no. of threads < 128). --- Part1/src/kernel.cu | 40 +++++++++++++++++++++++++++++++++++----- Part1/src/kernel.h | 2 +- Part1/src/main.cpp | 2 +- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 80b6daf..54faa8e 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -143,12 +143,42 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) } -//TODO: Core force calc kernel shared memory +//TODO: Done. NEED TO FIX CRASH WHEN VISUALIZING. __device__ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { - glm::vec3 acc = calculateAcceleration(my_pos, glm::vec4(0,0,0,starMass)); - return acc; + extern __shared__ glm::vec4 shared_pos []; + + glm::vec3 acc = glm::vec3 (0); + + // Loop over each block. + // This ensures that the whole global memory is loaded into the shared memory, one block at a time. + for (int j = 0; j < gridDim.x; j ++) + { + int blockIndex = blockIdx.x + j; + + // If trying to load a block beyond the grid boundary, wrap around. + if (blockIndex >= gridDim.x) + blockIndex -= gridDim.x; + + // Calculate global memory index that should be accessed by the thread. + int index = blockDim.x * blockIndex + threadIdx.x; + // Load the value from global to shared. + if (index < N) + shared_pos [threadIdx.x] = their_pos [index]; + __syncthreads (); + + // Loop over each object, and calculate acceleration. + for (int i = 0; i < blockDim.x; i ++) + { + if (shared_pos [i] == my_pos) + continue; + acc += calculateAcceleration(my_pos, shared_pos [i]); + } + } + + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + return acc; } @@ -235,14 +265,14 @@ void initCuda(int N) void cudaNBodyUpdateWrapper(float dt) { dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); - update<<>>(numObjects, dt, dev_pos, dev_vel); + update<<>>(numObjects, dt, dev_pos, dev_vel); checkCUDAErrorWithLine("Kernel failed!"); } void cudaUpdateVBO(float * vbodptr, int width, int height) { dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); - sendToVBO<<>>(numObjects, dev_pos, vbodptr, width, height, scene_scale); + sendToVBO<<>>(numObjects, dev_pos, vbodptr, width, height, scene_scale); checkCUDAErrorWithLine("Kernel failed!"); } diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 1f8b37a..3b35ace 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -14,7 +14,7 @@ #define blockSize 128 #define checkCUDAErrorWithLine(msg) checkCUDAError(msg, __LINE__) -#define SHARED 0 +#define SHARED 1 void checkCUDAError(const char *msg, int line); void cudaNBodyUpdateWrapper(float dt); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index d4c9c5b..2fc4594 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -6,7 +6,7 @@ #define N_FOR_VIS 25 #define DT 0.2 -#define VISUALIZE 1 +#define VISUALIZE 0 //------------------------------- //-------------MAIN-------------- //------------------------------- From 0b3e710c50c650166d4a2f41246727f5af3d6a40 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Fri, 18 Oct 2013 20:04:14 -0400 Subject: [PATCH 04/23] Hacky fix for the shared memory crash. --- Part1/src/kernel.cu | 48 ++++++++++++++++++++++++++++++++++----------- Part1/src/main.cpp | 4 ++-- 2 files changed, 39 insertions(+), 13 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 54faa8e..dd1f491 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -142,6 +142,13 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) return acc; } +// For float comparisons. +__device__ bool isApproximately (const float &a, const float &b) +{ + if ((a >= (b - 0.001)) && (a <= (b + 0.001))) + return true; + return false; +} //TODO: Done. NEED TO FIX CRASH WHEN VISUALIZING. __device__ @@ -151,32 +158,51 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); - // Loop over each block. - // This ensures that the whole global memory is loaded into the shared memory, one block at a time. - for (int j = 0; j < gridDim.x; j ++) + int loopMax = ceil (N / (float)blockDim.x); + + // Loop over each block (assuming parallelization of objects) and load objects from global to shared memory. + // The first block of threads will load the first blockDim.x no. of objects from global memory to shared memory; + // The next block will load the next blockDim.x no. of objects from global and so on. Thus, we load the entire + // set of positions in global memory into shared memory iteratively, one block at a time. + for (int j = 0; j < loopMax; j ++) { - int blockIndex = blockIdx.x + j; + // refBlockIndex is the block index of the block of memory locations we're trying to copy into shared. + int refblockIndex = blockIdx.x + j; // If trying to load a block beyond the grid boundary, wrap around. - if (blockIndex >= gridDim.x) - blockIndex -= gridDim.x; + if (refblockIndex >= loopMax) + refblockIndex -= loopMax; // Calculate global memory index that should be accessed by the thread. - int index = blockDim.x * blockIndex + threadIdx.x; + int index = blockDim.x * refblockIndex + threadIdx.x; // Load the value from global to shared. if (index < N) shared_pos [threadIdx.x] = their_pos [index]; - __syncthreads (); + +// Some threads are clearly not hitting this syncthreads call, causing the kernel to hang. +// Taken out. Hacky fix; results are not guaranteed to be correct. +// __syncthreads(); // Loop over each object, and calculate acceleration. for (int i = 0; i < blockDim.x; i ++) { - if (shared_pos [i] == my_pos) + // If the block we're loading into shared is the last block in the grid, it can contain less than blockDim.x + // threads. In such a situation, break out of the loop, once we pass the final thread in that block. + if (refblockIndex == (loopMax-1)) + if (i >= (N%blockDim.x)) + break; + + // A body cannot exert a force on itself, so skip.. + if (isApproximately (shared_pos [i].x, my_pos.x) && + isApproximately (shared_pos [i].y, my_pos.y) && + isApproximately (shared_pos [i].z, my_pos.z)) continue; + acc += calculateAcceleration(my_pos, shared_pos [i]); } } + // Calculate acceleration due to star. acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); return acc; } @@ -272,13 +298,13 @@ void cudaNBodyUpdateWrapper(float dt) void cudaUpdateVBO(float * vbodptr, int width, int height) { dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); - sendToVBO<<>>(numObjects, dev_pos, vbodptr, width, height, scene_scale); + sendToVBO<<>>(numObjects, dev_pos, vbodptr, width, height, scene_scale); checkCUDAErrorWithLine("Kernel failed!"); } void cudaUpdatePBO(float4 * pbodptr, int width, int height) { dim3 fullBlocksPerGrid((int)ceil(float(width*height)/float(blockSize))); - sendToPBO<<>>(numObjects, dev_pos, pbodptr, width, height, scene_scale); + sendToPBO<<>>(numObjects, dev_pos, pbodptr, width, height, scene_scale); checkCUDAErrorWithLine("Kernel failed!"); } diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 2fc4594..841263d 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -6,7 +6,7 @@ #define N_FOR_VIS 25 #define DT 0.2 -#define VISUALIZE 0 +#define VISUALIZE 1 //------------------------------- //-------------MAIN-------------- //------------------------------- @@ -24,7 +24,7 @@ int main(int argc, char** argv) #if VISUALIZE == 1 initCuda(N_FOR_VIS); #else - initCuda(2*128); + initCuda(2*120); #endif projection = glm::perspective(fovy, float(width)/float(height), zNear, zFar); From 32feb422429cd2ad5e145a9d23dd43c78f18f2d4 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Fri, 18 Oct 2013 21:19:32 -0400 Subject: [PATCH 05/23] Shared memory done! --- Part1/src/kernel.cu | 90 +++++++++++++++++++++++++++------------------ 1 file changed, 55 insertions(+), 35 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index dd1f491..d494854 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -132,13 +132,18 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { // NOTE: their_pos is a pointer to global memory. glm::vec3 acc = glm::vec3 (0); - for (int i = 0; i < N; i ++) + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < N) { - if (their_pos [i] == my_pos) - continue; - acc += calculateAcceleration(my_pos, their_pos [i]); + for (int i = 0; i < N; i ++) + { + if (their_pos [i] == my_pos) + continue; + acc += calculateAcceleration(my_pos, their_pos [i]); + } + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); } - acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); return acc; } @@ -150,12 +155,13 @@ __device__ bool isApproximately (const float &a, const float &b) return false; } -//TODO: Done. NEED TO FIX CRASH WHEN VISUALIZING. +//TODO: Done! __device__ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { extern __shared__ glm::vec4 shared_pos []; - + int threadNo = blockDim.x * blockIdx.x + threadIdx.x; + glm::vec3 acc = glm::vec3 (0); int loopMax = ceil (N / (float)blockDim.x); @@ -173,37 +179,42 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) if (refblockIndex >= loopMax) refblockIndex -= loopMax; - // Calculate global memory index that should be accessed by the thread. + // Calculate global memory index that should be accessed by this thread. int index = blockDim.x * refblockIndex + threadIdx.x; // Load the value from global to shared. if (index < N) shared_pos [threadIdx.x] = their_pos [index]; -// Some threads are clearly not hitting this syncthreads call, causing the kernel to hang. -// Taken out. Hacky fix; results are not guaranteed to be correct. -// __syncthreads(); - - // Loop over each object, and calculate acceleration. - for (int i = 0; i < blockDim.x; i ++) - { - // If the block we're loading into shared is the last block in the grid, it can contain less than blockDim.x - // threads. In such a situation, break out of the loop, once we pass the final thread in that block. - if (refblockIndex == (loopMax-1)) - if (i >= (N%blockDim.x)) - break; - - // A body cannot exert a force on itself, so skip.. - if (isApproximately (shared_pos [i].x, my_pos.x) && - isApproximately (shared_pos [i].y, my_pos.y) && - isApproximately (shared_pos [i].z, my_pos.z)) - continue; - - acc += calculateAcceleration(my_pos, shared_pos [i]); +// Synchronize here. + __syncthreads(); + + // Compute acceleration only for valid threads. + if (threadNo < N) + { + // Loop over each object, and calculate acceleration. + for (int i = 0; i < blockDim.x; i ++) + { + // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, + // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass + // the last element in that "block". + if (refblockIndex == (loopMax-1)) + if (i >= (N%blockDim.x)) + break; + + // A body cannot exert a force on itself, so skip.. + if (isApproximately (shared_pos [i].x, my_pos.x) && + isApproximately (shared_pos [i].y, my_pos.y) && + isApproximately (shared_pos [i].z, my_pos.z)) + continue; + + acc += calculateAcceleration(my_pos, shared_pos [i]); + } } } // Calculate acceleration due to star. - acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + if (threadNo < N) // Only for valid threads. + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); return acc; } @@ -213,10 +224,16 @@ __global__ void update(int N, float dt, glm::vec4 * pos, glm::vec3 * vel) { int index = threadIdx.x + (blockIdx.x * blockDim.x); - if( index < N ) - { - glm::vec4 my_pos = pos[index]; - glm::vec3 acc = ACC(N, my_pos, pos); + glm::vec4 my_pos = glm::vec4 (0); + if( index < N ) + my_pos = pos[index]; + + // For invalid threads, we still compute dummy acceleration. + // This is because sharedMemAcc will cause a deadlocked kernel if there is a divergence here. + glm::vec3 acc = ACC(N, my_pos, pos); + + if( index < N ) + { vel[index] += acc * dt; pos[index].x += vel[index].x * dt; pos[index].y += vel[index].y * dt; @@ -258,9 +275,12 @@ void sendToPBO(int N, glm::vec4 * pos, float4 * pbo, int width, int height, floa float c_scale_h = height / s_scale; if(x Date: Sat, 19 Oct 2013 02:55:04 -0400 Subject: [PATCH 06/23] Merge branch 'upstream/master' Conflicts: Part1/src/kernel.cu --- Part1/src/kernel.cu | 48 +++-- Part1/src/kernel.cu.orig | 374 +++++++++++++++++++++++++++++++++++++++ Part1/src/kernel.h | 2 +- Part1/src/main.cpp | 2 +- 4 files changed, 396 insertions(+), 30 deletions(-) create mode 100644 Part1/src/kernel.cu.orig diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 8f312eb..b799249 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -189,33 +189,30 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) // Synchronize here. __syncthreads(); - // Compute acceleration only for valid threads. - if (threadNo < N) - { - // Loop over each object, and calculate acceleration. - for (int i = 0; i < blockDim.x; i ++) - { - // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, - // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass - // the last element in that "block". - if (refblockIndex == (loopMax-1)) - if (i >= (N%blockDim.x)) - break; - - // A body cannot exert a force on itself, so skip.. - if (isApproximately (shared_pos [i].x, my_pos.x) && - isApproximately (shared_pos [i].y, my_pos.y) && - isApproximately (shared_pos [i].z, my_pos.z)) - continue; - - acc += calculateAcceleration(my_pos, shared_pos [i]); - } + // Compute acceleration only for all threads. + // Loop over each object, and calculate acceleration. + for (int i = 0; i < blockDim.x; i ++) + { + // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, + // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass + // the last element in that "block". + if (refblockIndex == (loopMax-1)) + if (i >= (N%blockDim.x)) + break; + + // A body cannot exert a force on itself, so skip.. + if (isApproximately (shared_pos [i].x, my_pos.x) && + isApproximately (shared_pos [i].y, my_pos.y) && + isApproximately (shared_pos [i].z, my_pos.z)) + continue; + + acc += calculateAcceleration(my_pos, shared_pos [i]); } } // Calculate acceleration due to star. - if (threadNo < N) // Only for valid threads. - acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + return acc; } @@ -283,11 +280,6 @@ void sendToPBO(int N, glm::vec4 * pos, float4 * pbo, int width, int height, floa glm::vec3 color(0.05, 0.15, 0.3); glm::vec3 acc = ACC(N, glm::vec4((x-w2)/c_scale_w,(y-h2)/c_scale_h,0,1), pos); - if(x +#include +#include +#include "glm/glm.hpp" +#include "utilities.h" +#include "kernel.h" + +#if SHARED == 1 + #define ACC(x,y,z) sharedMemAcc(x,y,z) +#else + #define ACC(x,y,z) naiveAcc(x,y,z) +#endif + +//GLOBALS +dim3 threadsPerBlock(blockSize); + +int numObjects; +const float planetMass = 3e8; +const __device__ float starMass = 5e10; +const __device__ float GravConst = 6.67384e-11; +const float scene_scale = 2e2; //size of the height map in simulation space + +glm::vec4 * dev_pos; +glm::vec3 * dev_vel; +glm::vec3 * dev_acc; + +void checkCUDAError(const char *msg, int line = -1) +{ + cudaError_t err = cudaGetLastError(); + if( cudaSuccess != err) + { + if( line >= 0 ) + { + fprintf(stderr, "Line %d: ", line); + } + fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString( err) ); + exit(EXIT_FAILURE); + } +} + +__host__ __device__ +unsigned int hash(unsigned int a){ + a = (a+0x7ed55d16) + (a<<12); + a = (a^0xc761c23c) ^ (a>>19); + a = (a+0x165667b1) + (a<<5); + a = (a+0xd3a2646c) ^ (a<<9); + a = (a+0xfd7046c5) + (a<<3); + a = (a^0xb55a4f09) ^ (a>>16); + return a; +} + +//Function that generates static. +__host__ __device__ +glm::vec3 generateRandomNumberFromThread(float time, int index) +{ + thrust::default_random_engine rng(hash(index*time)); + thrust::uniform_real_distribution u01(0,1); + + return glm::vec3((float) u01(rng), (float) u01(rng), (float) u01(rng)); +} + +//Generate randomized starting positions for the planets in the XY plane +//Also initialized the masses +__global__ +void generateRandomPosArray(int time, int N, glm::vec4 * arr, float scale, float mass) +{ + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if(index < N) + { + glm::vec3 rand = scale*(generateRandomNumberFromThread(time, index)-0.5f); + arr[index].x = rand.x; + arr[index].y = rand.y; + arr[index].z = 0.0f;//rand.z; + arr[index].w = mass; + } +} + +//Determine velocity from the distance from the center star. Not super physically accurate because +//the mass ratio is too close, but it makes for an interesting looking scene +__global__ +void generateCircularVelArray(int time, int N, glm::vec3 * arr, glm::vec4 * pos) +{ + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if(index < N) + { + glm::vec3 R = glm::vec3(pos[index].x, pos[index].y, pos[index].z); + float r = glm::length(R) + EPSILON; + float s = sqrt(G*starMass/r); + glm::vec3 D = glm::normalize(glm::cross(R/r,glm::vec3(0,0,1))); + arr[index].x = s*D.x; + arr[index].y = s*D.y; + arr[index].z = s*D.z; + } +} + +//Generate randomized starting velocities in the XY plane +__global__ +void generateRandomVelArray(int time, int N, glm::vec3 * arr, float scale) +{ + int index = (blockIdx.x * blockDim.x) + threadIdx.x; + if(index < N) + { + glm::vec3 rand = scale*(generateRandomNumberFromThread(time, index) - 0.5f); + arr[index].x = rand.x; + arr[index].y = rand.y; + arr[index].z = 0.0;//rand.z; + } +} + +//TODO: Done! +__device__ +glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) +{ + // G*m_us*m_them + //F = ------------- + // r^2 + // + // G*m_us*m_them G*m_them + //a = ------------- = -------- + // m_us*r^2 r^2 + glm::vec3 forceDir = glm::vec3 (them.x - us.x, them.y - us.y, them.z - us.z); + float dist = sqrt (glm::dot (forceDir, forceDir)); + forceDir /= dist; // Force direction is now normalized and we have distance between the two objects (r)! + + float accVal = (GravConst * them.w) / (dist*dist); + + return forceDir * accVal; +} + +//TODO: Done! +__device__ +glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) +{ + // NOTE: their_pos is a pointer to global memory. + glm::vec3 acc = glm::vec3 (0); + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < N) + { + for (int i = 0; i < N; i ++) + { + if (their_pos [i] == my_pos) + continue; + acc += calculateAcceleration(my_pos, their_pos [i]); + } + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + } + return acc; +} + +// For float comparisons. +__device__ bool isApproximately (const float &a, const float &b) +{ + if ((a >= (b - 0.001)) && (a <= (b + 0.001))) + return true; + return false; +} + +//TODO: Done! +__device__ +glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) +{ + extern __shared__ glm::vec4 shared_pos []; + int threadNo = blockDim.x * blockIdx.x + threadIdx.x; + + glm::vec3 acc = glm::vec3 (0); + + int loopMax = ceil (N / (float)blockDim.x); + + // Loop over each block (assuming parallelization of objects) and load objects from global to shared memory. + // The first block of threads will load the first blockDim.x no. of objects from global memory to shared memory; + // The next block will load the next blockDim.x no. of objects from global and so on. Thus, we load the entire + // set of positions in global memory into shared memory iteratively, one block at a time. + for (int j = 0; j < loopMax; j ++) + { + // refBlockIndex is the block index of the block of memory locations we're trying to copy into shared. + int refblockIndex = blockIdx.x + j; + + // If trying to load a block beyond the grid boundary, wrap around. + if (refblockIndex >= loopMax) + refblockIndex -= loopMax; + + // Calculate global memory index that should be accessed by this thread. + int index = blockDim.x * refblockIndex + threadIdx.x; + // Load the value from global to shared. + if (index < N) + shared_pos [threadIdx.x] = their_pos [index]; + +// Synchronize here. + __syncthreads(); + + // Compute acceleration only for valid threads. + if (threadNo < N) + { + // Loop over each object, and calculate acceleration. + for (int i = 0; i < blockDim.x; i ++) + { + // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, + // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass + // the last element in that "block". + if (refblockIndex == (loopMax-1)) + if (i >= (N%blockDim.x)) + break; + + // A body cannot exert a force on itself, so skip.. + if (isApproximately (shared_pos [i].x, my_pos.x) && + isApproximately (shared_pos [i].y, my_pos.y) && + isApproximately (shared_pos [i].z, my_pos.z)) + continue; + + acc += calculateAcceleration(my_pos, shared_pos [i]); + } + } + } + + // Calculate acceleration due to star. + if (threadNo < N) // Only for valid threads. + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + return acc; +} + +//Simple Euler integration scheme +__global__ +void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + glm::vec4 my_pos; + glm::vec3 accel; + + if(index < N) my_pos = pos[index]; + + accel = ACC(N, my_pos, pos); + + if(index < N) acc[index] = accel; +} + +__global__ +void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); +<<<<<<< HEAD + glm::vec4 my_pos = glm::vec4 (0); + if( index < N ) + my_pos = pos[index]; + + // For invalid threads, we still compute dummy acceleration. + // This is because sharedMemAcc will cause a deadlocked kernel if there is a divergence here. + glm::vec3 acc = ACC(N, my_pos, pos); + + if( index < N ) + { + vel[index] += acc * dt; +======= + if( index < N ) + { + vel[index] += acc[index] * dt; +>>>>>>> upstream/master + pos[index].x += vel[index].x * dt; + pos[index].y += vel[index].y * dt; + pos[index].z += vel[index].z * dt; + } +} + +//Update the vertex buffer object +//(The VBO is where OpenGL looks for the positions for the planets) +__global__ +void sendToVBO(int N, glm::vec4 * pos, float * vbo, int width, int height, float s_scale) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + float c_scale_w = -2.0f / s_scale; + float c_scale_h = -2.0f / s_scale; + + if(index>>>>>> upstream/master + float mag = sqrt(sqrt(acc.x*acc.x + acc.y*acc.y + acc.z*acc.z)); + // Each thread writes one pixel location in the texture (textel) + pbo[index].w = (mag < 1.0f) ? mag : 1.0f; + } +} + +/************************************* + * Wrappers for the __global__ calls * + *************************************/ + +//Initialize memory, update some globals +void initCuda(int N) +{ + numObjects = N; + dim3 fullBlocksPerGrid((int)ceil(float(N)/float(blockSize))); + + cudaMalloc((void**)&dev_pos, N*sizeof(glm::vec4)); + checkCUDAErrorWithLine("Kernel failed!"); + cudaMalloc((void**)&dev_vel, N*sizeof(glm::vec3)); + checkCUDAErrorWithLine("Kernel failed!"); + cudaMalloc((void**)&dev_acc, N*sizeof(glm::vec3)); + checkCUDAErrorWithLine("Kernel failed!"); + + generateRandomPosArray<<>>(1, numObjects, dev_pos, scene_scale, planetMass); + checkCUDAErrorWithLine("Kernel failed!"); + generateCircularVelArray<<>>(2, numObjects, dev_vel, dev_pos); + checkCUDAErrorWithLine("Kernel failed!"); + cudaThreadSynchronize(); +} + +void cudaNBodyUpdateWrapper(float dt) +{ + dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); +<<<<<<< HEAD + update<<>>(numObjects, dt, dev_pos, dev_vel); +======= + updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + checkCUDAErrorWithLine("Kernel failed!"); + updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); +>>>>>>> upstream/master + checkCUDAErrorWithLine("Kernel failed!"); + cudaThreadSynchronize(); +} + +void cudaUpdateVBO(float * vbodptr, int width, int height) +{ + dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); + sendToVBO<<>>(numObjects, dev_pos, vbodptr, width, height, scene_scale); + cudaThreadSynchronize(); +} + +void cudaUpdatePBO(float4 * pbodptr, int width, int height) +{ + dim3 fullBlocksPerGrid((int)ceil(float(width*height)/float(blockSize))); +<<<<<<< HEAD + sendToPBO<<>>(numObjects, dev_pos, pbodptr, width, height, scene_scale); + checkCUDAErrorWithLine("Kernel failed!"); +======= + sendToPBO<<>>(numObjects, dev_pos, pbodptr, width, height, scene_scale); + cudaThreadSynchronize(); +>>>>>>> upstream/master +} + + diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 3b35ace..1f8b37a 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -14,7 +14,7 @@ #define blockSize 128 #define checkCUDAErrorWithLine(msg) checkCUDAError(msg, __LINE__) -#define SHARED 1 +#define SHARED 0 void checkCUDAError(const char *msg, int line); void cudaNBodyUpdateWrapper(float dt); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 841263d..009358b 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -24,7 +24,7 @@ int main(int argc, char** argv) #if VISUALIZE == 1 initCuda(N_FOR_VIS); #else - initCuda(2*120); + initCuda(20*120); #endif projection = glm::perspective(fovy, float(width)/float(height), zNear, zFar); From fb3b67f307fd404847b02399af26fa584261ebb7 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Sat, 19 Oct 2013 03:08:03 -0400 Subject: [PATCH 07/23] Part1 complete. --- Part1/PROJ_WIN/Project3/shaders/heightFS.glsl | 11 ++++- Part1/PROJ_WIN/Project3/shaders/heightVS.glsl | 15 +++++-- Part1/PROJ_WIN/Project3/shaders/planetFS.glsl | 30 +++++++++++-- Part1/PROJ_WIN/Project3/shaders/planetGS.glsl | 42 +++++++++++++++++-- Part1/src/kernel.cu | 6 +-- 5 files changed, 89 insertions(+), 15 deletions(-) diff --git a/Part1/PROJ_WIN/Project3/shaders/heightFS.glsl b/Part1/PROJ_WIN/Project3/shaders/heightFS.glsl index e36d53e..ae926e7 100644 --- a/Part1/PROJ_WIN/Project3/shaders/heightFS.glsl +++ b/Part1/PROJ_WIN/Project3/shaders/heightFS.glsl @@ -1,4 +1,11 @@ +varying float f_height; +varying vec2 v_Texcoords; + void main(void) { - gl_FragColor = vec4(0.05,0.15,0.3,1.0); -} + float shade = (1.0-2.0*sqrt(f_height)); + float alpha = float(mod(v_Texcoords.x+0.025, 0.05) > 0.046 || + mod(v_Texcoords.y+0.025, 0.05) > 0.046); + vec4 color = mix(vec4(0.75,0.55,0.3,1.0), vec4(0.05, 0.3, 0.4, 1.0), alpha); + gl_FragColor = shade*color; +} \ No newline at end of file diff --git a/Part1/PROJ_WIN/Project3/shaders/heightVS.glsl b/Part1/PROJ_WIN/Project3/shaders/heightVS.glsl index eda1b93..7e86950 100644 --- a/Part1/PROJ_WIN/Project3/shaders/heightVS.glsl +++ b/Part1/PROJ_WIN/Project3/shaders/heightVS.glsl @@ -1,9 +1,18 @@ uniform mat4 u_projMatrix; +uniform sampler2D u_height; + attribute vec4 Position; +attribute vec2 Texcoords; + +varying vec2 v_Texcoords; +varying float f_height; void main(void) { - vec4 pos = u_projMatrix * Position; - pos.z += 0.01; - gl_Position = pos; + v_Texcoords = Texcoords; + vec4 pos = Position; + f_height = texture2D(u_height, Texcoords).w; + pos.z = -0.01-clamp(f_height,0.0,2.0); + pos = u_projMatrix * pos; + gl_Position = pos; } diff --git a/Part1/PROJ_WIN/Project3/shaders/planetFS.glsl b/Part1/PROJ_WIN/Project3/shaders/planetFS.glsl index e2c1350..9d281ca 100644 --- a/Part1/PROJ_WIN/Project3/shaders/planetFS.glsl +++ b/Part1/PROJ_WIN/Project3/shaders/planetFS.glsl @@ -1,4 +1,28 @@ -void main(void) +#version 330 + +in vec3 WorldCoord; +in vec3 ToCam; +in vec3 Up; +in vec3 Right; +in vec2 TexCoord; +out vec4 FragColor; + +void main() { - gl_FragColor = vec4(1.0); -} + vec2 coord = 2.01 * (TexCoord - vec2(0.5)); + float r = length(coord); + if (r >= 1.0) { discard; } + + float dist = length(WorldCoord); + if(dist <= 0.01) + { + FragColor = vec4(1.0); + return; + } + + vec3 N = Right*-coord.x + Up*coord.y + ToCam*sqrt(1-r*r); + vec3 L = normalize(-WorldCoord); + float light = 0.1 + 0.9*clamp(dot(N,L),0.0, 1.0)*exp(-dist); + vec3 color = vec3(0.4, 0.1, 0.6); + FragColor = vec4(color*light,1.0); +} diff --git a/Part1/PROJ_WIN/Project3/shaders/planetGS.glsl b/Part1/PROJ_WIN/Project3/shaders/planetGS.glsl index 88027d3..b6f4143 100644 --- a/Part1/PROJ_WIN/Project3/shaders/planetGS.glsl +++ b/Part1/PROJ_WIN/Project3/shaders/planetGS.glsl @@ -1,15 +1,49 @@ #version 330 uniform mat4 u_projMatrix; +uniform vec3 u_cameraPos; layout (points) in; -layout (points) out; -layout (max_vertices = 1) out; +layout (triangle_strip) out; +layout (max_vertices = 4) out; + +out vec3 WorldCoord; +out vec3 ToCam; +out vec3 Up; +out vec3 Right; +out vec2 TexCoord; + +const float scale = 0.03; void main() { vec3 Position = gl_in[0].gl_Position.xyz; - gl_Position = u_projMatrix * vec4(Position, 1.0); + WorldCoord = Position; + + ToCam = normalize(u_cameraPos - Position); + Up = vec3(0.0, 0.0, 1.0); + Right = cross(ToCam, Up); + Up = cross(Right, ToCam); + + vec3 Pos = Position + scale*Right - scale*Up; + gl_Position = u_projMatrix * vec4(Pos, 1.0); + TexCoord = vec2(0.0, 0.0); + EmitVertex(); + + Pos = Position + scale*Right + scale*Up; + gl_Position = u_projMatrix * vec4(Pos, 1.0); + TexCoord = vec2(0.0, 1.0); EmitVertex(); + + Pos = Position - scale*Right - scale*Up; + gl_Position = u_projMatrix * vec4(Pos, 1.0); + TexCoord = vec2(1.0, 0.0); + EmitVertex(); + + Pos = Position - scale*Right + scale*Up; + gl_Position = u_projMatrix * vec4(Pos, 1.0); + TexCoord = vec2(1.0, 1.0); + EmitVertex(); + EndPrimitive(); -} +} \ No newline at end of file diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index b799249..a369e87 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -135,8 +135,8 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); int index = threadIdx.x + (blockIdx.x * blockDim.x); - if (index < N) - { +// if (index < N) +// { for (int i = 0; i < N; i ++) { if (their_pos [i] == my_pos) @@ -144,7 +144,7 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) acc += calculateAcceleration(my_pos, their_pos [i]); } acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); - } +// } return acc; } From d60d86ac448df7b82287d6fabdcff1fcc223ad4f Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Sat, 19 Oct 2013 05:15:37 -0400 Subject: [PATCH 08/23] Added flocking code. --- Part1/src/kernel.cu | 74 +++++++++++++++++++++++++++++++++++++++++++-- Part1/src/kernel.h | 2 +- Part1/src/main.cpp | 15 +++++++-- Part1/src/main.h | 2 +- 4 files changed, 86 insertions(+), 7 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index a369e87..94a2ce9 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -216,6 +216,58 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) return acc; } +__device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec4 *vel) +{ + glm::vec3 acc = glm::vec3 (0); + glm::vec4 my_vel; + + glm::vec3 sumVelocities = glm::vec3 (0); + glm::vec3 sumPositions = glm::vec3 (0); + glm::vec3 sumSepVelocities = glm::vec3 (0); + + int neighbours = 0; + + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + if (index < N) + { + for (int i = 0; i < N; i ++) + { + glm::vec4 curPos = pos [i]; + glm::vec4 curVel = vel [i]; + + if (curPos == my_pos) + my_vel = curVel; + + float distance = glm::length (curPos - my_pos); + if (/*(distance > 0 ) &&*/ (distance <= 5.0)) + { + sumVelocities += curVel; + sumPositions += curPos; + + sumSepVelocities += (my_pos - curPos); + neighbours ++; + } + } + + if (neighbours > 0) + { + sumVelocities /= neighbours; + sumSepVelocities /= neighbours; + sumPositions /= neighbours; // Centre of mass. + } + + // Calculate total velocity: + glm::vec3 totalVel = (glm::normalize (sumVelocities) * glm::length (my_vel)) // Align component + + (glm::normalize (sumPositions - glm::vec3 (my_pos)) * glm::length (my_vel)) // Cohesion component + + (glm::normalize (sumSepVelocities) * glm::length (my_vel)); // Separation component + + + acc = (totalVel - glm::vec3 (my_vel))/DT; + } + return acc; +} + //Simple Euler integration scheme __global__ void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) @@ -231,6 +283,21 @@ void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) if(index < N) acc[index] = accel; } +// Calculate acceleration for Custom Simulation. +__global__ +void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + glm::vec4 my_pos; + glm::vec3 accel; + + if(index < N) my_pos = pos[index]; + + accel = Flock (N, dt, my_pos, pos, vel); + + if(index < N) acc[index] = accel; +} + __global__ void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { @@ -312,10 +379,13 @@ void initCuda(int N) cudaThreadSynchronize(); } -void cudaNBodyUpdateWrapper(float dt) +void cudaNBodyUpdateWrapper(float dt, bool customSimulation) { dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); - updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + if (customSimulation) + updateFCustom<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + else + updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 1f8b37a..04b773d 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -17,7 +17,7 @@ #define SHARED 0 void checkCUDAError(const char *msg, int line); -void cudaNBodyUpdateWrapper(float dt); +void cudaNBodyUpdateWrapper(float dt, bool customSimulation); void initCuda(int N); void cudaUpdatePBO(float4 * pbodptr, int width, int height); void cudaUpdateVBO(float * vbodptr, int width, int height); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 009358b..d59b274 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -7,6 +7,9 @@ #define N_FOR_VIS 25 #define DT 0.2 #define VISUALIZE 1 + +bool customSimulation = false; + //------------------------------- //-------------MAIN-------------- //------------------------------- @@ -53,7 +56,7 @@ int main(int argc, char** argv) //---------RUNTIME STUFF--------- //------------------------------- -void runCuda() +void runCuda(bool customSimulation) { // Map OpenGL buffer object for writing from CUDA on a single GPU // No data is moved (Win & Linux). When mapped to CUDA, OpenGL should not use this buffer @@ -64,7 +67,7 @@ void runCuda() cudaGLMapBufferObject((void**)&dptrvert, planetVBO); // execute the kernel - cudaNBodyUpdateWrapper(DT); + cudaNBodyUpdateWrapper(DT, customSimulation); #if VISUALIZE == 1 cudaUpdatePBO(dptr, field_width, field_height); cudaUpdateVBO(dptrvert, field_width, field_height); @@ -88,7 +91,7 @@ void display() timebase = time; frame = 0; } - runCuda(); + runCuda(customSimulation); char title[100]; sprintf( title, "565 NBody sim [%0.2f fps]", fps ); @@ -178,6 +181,12 @@ void init(int argc, char* argv[]) exit (1); } + if (argc > 1) + { + if (!strcmp (argv [1], "true")) + customSimulation = true; + } + initVAO(); initTextures(); } diff --git a/Part1/src/main.h b/Part1/src/main.h index 8eddb37..d0b26c9 100644 --- a/Part1/src/main.h +++ b/Part1/src/main.h @@ -74,7 +74,7 @@ int main(int argc, char** argv); //---------RUNTIME STUFF--------- //------------------------------- -void runCuda(); +void runCuda(bool customSimulation); void display(); void keyboard(unsigned char key, int x, int y); From b367be82be8ddd905b0e7048d49ab7bf17f5daa2 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Sun, 20 Oct 2013 00:06:13 -0400 Subject: [PATCH 09/23] Flocking! --- Part1/src/kernel.cu | 54 ++++++++++++++++++++++++++++++--------------- Part1/src/kernel.h | 2 ++ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 94a2ce9..b963011 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -216,10 +216,11 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) return acc; } -__device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec4 *vel) +__device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel) { +// int my_index = 0; glm::vec3 acc = glm::vec3 (0); - glm::vec4 my_vel; + glm::vec3 my_vel; glm::vec3 sumVelocities = glm::vec3 (0); glm::vec3 sumPositions = glm::vec3 (0); @@ -231,21 +232,24 @@ __device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, g if (index < N) { + my_vel = vel [index]; + for (int i = 0; i < N; i ++) { glm::vec4 curPos = pos [i]; - glm::vec4 curVel = vel [i]; - - if (curPos == my_pos) - my_vel = curVel; + glm::vec3 curVel = vel [i]; float distance = glm::length (curPos - my_pos); - if (/*(distance > 0 ) &&*/ (distance <= 5.0)) + if (/*(distance > 0 ) &&*/ (distance <= 2.0)) { sumVelocities += curVel; - sumPositions += curPos; + sumPositions.x += curPos.x; + sumPositions.y += curPos.y; + sumPositions.z += curPos.z; - sumSepVelocities += (my_pos - curPos); + sumSepVelocities.x += (my_pos.x - curPos.x); + sumSepVelocities.y += (my_pos.y - curPos.y); + sumSepVelocities.z += (my_pos.z - curPos.z); neighbours ++; } } @@ -258,17 +262,25 @@ __device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, g } // Calculate total velocity: - glm::vec3 totalVel = (glm::normalize (sumVelocities) * glm::length (my_vel)) // Align component - + (glm::normalize (sumPositions - glm::vec3 (my_pos)) * glm::length (my_vel)) // Cohesion component - + (glm::normalize (sumSepVelocities) * glm::length (my_vel)); // Separation component + glm::vec3 flockVel = (safeNormalize (sumVelocities) * glm::length (my_vel))// * 0.4f // Align component + + (safeNormalize (sumPositions - glm::vec3 (my_pos)) * glm::length (my_vel))// * 0.2f // Cohesion component + + (safeNormalize (sumSepVelocities) * glm::length (my_vel));// * 0.4f; // Separation component - - acc = (totalVel - glm::vec3 (my_vel))/DT; + acc = ((glm::length (flockVel) - glm::length (my_vel))/DT) * safeNormalize (flockVel); } return acc; } -//Simple Euler integration scheme +// normalize only if length > 0 +inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized) +{ + float len = glm::length (vectorToBeNormalized); + if (len > 0.001) + return vectorToBeNormalized / len; + return vectorToBeNormalized; +} + +// Calculate gravitational acceleration. __global__ void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { @@ -293,11 +305,12 @@ void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 if(index < N) my_pos = pos[index]; - accel = Flock (N, dt, my_pos, pos, vel); + accel = 0.3f*Flock (N, dt, my_pos, pos, vel) + 0.7f*calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); if(index < N) acc[index] = accel; } +//Simple Euler integration scheme __global__ void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { @@ -383,11 +396,16 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation) { dim3 fullBlocksPerGrid((int)ceil(float(numObjects)/float(blockSize))); if (customSimulation) - updateFCustom<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + updateFCustom<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); else updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); - updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + glm::vec3 *accn = new glm::vec3 [numObjects]; + for (int i= 0; i < numObjects; i ++) + accn [i] = glm::vec3 (0); + cudaMemcpy (accn, dev_acc, sizeof(glm::vec3)*numObjects, cudaMemcpyDeviceToHost); + int breakHere = -1; + updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); } diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 04b773d..7e528e2 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -21,4 +21,6 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation); void initCuda(int N); void cudaUpdatePBO(float4 * pbodptr, int width, int height); void cudaUpdateVBO(float * vbodptr, int width, int height); + +inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized); // normalize only if length > 0 #endif From 00565b2f2a43d3aab258316b3cd7808b59851adb Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Sun, 20 Oct 2013 05:29:56 -0400 Subject: [PATCH 10/23] Flock neighbourhood distance increased. Plus, flocks now rotate around star. --- Part1/src/kernel.cu | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index b963011..7254c56 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -7,8 +7,10 @@ #if SHARED == 1 #define ACC(x,y,z) sharedMemAcc(x,y,z) + #define FLOCK(p,q,r,s,t) FlockShared(p,q,r,s,t) #else #define ACC(x,y,z) naiveAcc(x,y,z) + #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) #endif //GLOBALS @@ -120,11 +122,15 @@ glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) // m_us*r^2 r^2 glm::vec3 forceDir = glm::vec3 (them.x - us.x, them.y - us.y, them.z - us.z); float dist = sqrt (glm::dot (forceDir, forceDir)); - forceDir /= dist; // Force direction is now normalized and we have distance between the two objects (r)! + + if (dist > 0) + { + forceDir /= dist; // Force direction is now normalized and we have distance between the two objects (r)! + float accVal = (GravConst * them.w) / (dist*dist); + return forceDir * accVal; + } - float accVal = (GravConst * them.w) / (dist*dist); - - return forceDir * accVal; + return glm::vec3 (0); } //TODO: Done! @@ -216,9 +222,8 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) return acc; } -__device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel) +__device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel) { -// int my_index = 0; glm::vec3 acc = glm::vec3 (0); glm::vec3 my_vel; @@ -240,7 +245,7 @@ __device__ glm::vec3 Flock (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, g glm::vec3 curVel = vel [i]; float distance = glm::length (curPos - my_pos); - if (/*(distance > 0 ) &&*/ (distance <= 2.0)) + if (distance <= 5.0) { sumVelocities += curVel; sumPositions.x += curPos.x; @@ -305,7 +310,7 @@ void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 if(index < N) my_pos = pos[index]; - accel = 0.3f*Flock (N, dt, my_pos, pos, vel) + 0.7f*calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + accel = FLOCK (N, dt, my_pos, pos, vel) + calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); if(index < N) acc[index] = accel; } From 214e6f1fccc435766894f7e9a12e4fb94fb52d6e Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Sun, 20 Oct 2013 18:46:49 -0400 Subject: [PATCH 11/23] Prefetching. --- Part1/PROJ_WIN/Project3/Project3.vcxproj | 9 +- Part1/src/kernel.cu | 118 ++++++++++++++++++----- Part1/src/kernel.h | 1 + Part1/src/main.cpp | 8 +- 4 files changed, 109 insertions(+), 27 deletions(-) diff --git a/Part1/PROJ_WIN/Project3/Project3.vcxproj b/Part1/PROJ_WIN/Project3/Project3.vcxproj index 20ddcbc..0702d5b 100644 --- a/Part1/PROJ_WIN/Project3/Project3.vcxproj +++ b/Part1/PROJ_WIN/Project3/Project3.vcxproj @@ -26,7 +26,7 @@ false true MultiByte - v110 + v100 @@ -71,12 +71,19 @@ MaxSpeed true true + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes;%(AdditionalIncludeDirectories);$(CudaToolkitIncludeDir) true true true + ../shared/glew/lib;../shared/freeglut/lib;%(AdditionalLibraryDirectories);$(CudaToolkitLibDir) + cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies); + + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes + $(ProjectDir)$(Platform)/$(Configuration)/%(Filename)%(Extension).obj + diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 7254c56..f8a676d 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -5,13 +5,13 @@ #include "utilities.h" #include "kernel.h" -#if SHARED == 1 - #define ACC(x,y,z) sharedMemAcc(x,y,z) - #define FLOCK(p,q,r,s,t) FlockShared(p,q,r,s,t) -#else - #define ACC(x,y,z) naiveAcc(x,y,z) - #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) -#endif +//#if SHARED == 1 +// #define ACC(x,y,z) pfSharedMemAcc(x,y,z) +// #define FLOCK(p,q,r,s,t) FlockShared(p,q,r,s,t) +//#else +// #define ACC(x,y,z) naiveAcc(x,y,z) +// #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) +//#endif //GLOBALS dim3 threadsPerBlock(blockSize); @@ -20,8 +20,20 @@ int numObjects; const float planetMass = 3e8; const __device__ float starMass = 5e10; const __device__ float GravConst = 6.67384e-11; +__device__ bool prefetch; const float scene_scale = 2e2; //size of the height map in simulation space +#if SHARED == 1 +// if (prefetch) + #define ACC(x,y,z) pfSharedMemAcc(x,y,z) +// else +// #define ACC(x,y,z) sharedMemAcc(x,y,z) + #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) +#else + #define ACC(x,y,z) naiveAcc(x,y,z) + #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) +#endif + glm::vec4 * dev_pos; glm::vec3 * dev_vel; glm::vec3 * dev_acc; @@ -36,6 +48,7 @@ void checkCUDAError(const char *msg, int line = -1) fprintf(stderr, "Line %d: ", line); } fprintf(stderr, "Cuda error: %s: %s.\n", msg, cudaGetErrorString( err) ); + std::cin.get (); exit(EXIT_FAILURE); } } @@ -171,20 +184,20 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); - int loopMax = ceil (N / (float)blockDim.x); - +// int loopMax = ceil (N / (float)blockDim.x); + // Loop over each block (assuming parallelization of objects) and load objects from global to shared memory. // The first block of threads will load the first blockDim.x no. of objects from global memory to shared memory; // The next block will load the next blockDim.x no. of objects from global and so on. Thus, we load the entire // set of positions in global memory into shared memory iteratively, one block at a time. - for (int j = 0; j < loopMax; j ++) + for (int j = 0; j < ceil (N / (float)blockDim.x); j ++) { // refBlockIndex is the block index of the block of memory locations we're trying to copy into shared. int refblockIndex = blockIdx.x + j; // If trying to load a block beyond the grid boundary, wrap around. - if (refblockIndex >= loopMax) - refblockIndex -= loopMax; + if (refblockIndex >= ceil (N / (float)blockDim.x)) + refblockIndex -= ceil (N / (float)blockDim.x); // Calculate global memory index that should be accessed by this thread. int index = blockDim.x * refblockIndex + threadIdx.x; @@ -202,7 +215,7 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass // the last element in that "block". - if (refblockIndex == (loopMax-1)) + if (refblockIndex == (floor (N / (float)blockDim.x))) if (i >= (N%blockDim.x)) break; @@ -222,6 +235,59 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) return acc; } +// Shared memory acceleration calculation with prefetching. +// Written as a separate function to compare performance. +__device__ +glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) +{ + extern __shared__ glm::vec4 shared_pos []; + int threadNo = blockDim.x * blockIdx.x + threadIdx.x; + + glm::vec3 acc = glm::vec3 (0); + glm::vec4 prefetcher = glm::vec4 (0); + + int index = blockDim.x * blockIdx.x + threadIdx.x; + if (index < N) + prefetcher = their_pos [index]; // Prefetch first element into register. + + for (int j = 0; j < ceil (N / (float)blockDim.x); j ++) + { + int refblockIndex = blockIdx.x + j + 1; + if (refblockIndex >= ceil (N / (float)blockDim.x)) + refblockIndex -= ceil (N / (float)blockDim.x); + + index = blockDim.x * refblockIndex + threadIdx.x; + + shared_pos [threadIdx.x] = prefetcher; // Copy prefetched element into shared memory. + prefetcher = glm::vec4 (0); + __syncthreads(); + + if (index < N) + if (j < floor (N / (float)blockDim.x)) // Prefetching to stop at the penultimate block, after the final + prefetcher = their_pos [index]; // block has been loaded. + + for (int i = 0; i < blockDim.x; i ++) + { + if (refblockIndex == (floor (N / (float)blockDim.x))) + if (i >= (N%blockDim.x)) + break; + + if (isApproximately (shared_pos [i].x, my_pos.x) && + isApproximately (shared_pos [i].y, my_pos.y) && + isApproximately (shared_pos [i].z, my_pos.z)) + continue; + + acc += calculateAcceleration(my_pos, shared_pos [i]); + } + } + + // Calculate acceleration due to star. + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + + return acc; +} + +// Calculate flocking velocity. __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel) { glm::vec3 acc = glm::vec3 (0); @@ -242,12 +308,12 @@ __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 * for (int i = 0; i < N; i ++) { glm::vec4 curPos = pos [i]; - glm::vec3 curVel = vel [i]; - float distance = glm::length (curPos - my_pos); + if (distance <= 5.0) { - sumVelocities += curVel; + sumVelocities += vel [i]; + sumPositions.x += curPos.x; sumPositions.y += curPos.y; sumPositions.z += curPos.z; @@ -255,15 +321,16 @@ __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 * sumSepVelocities.x += (my_pos.x - curPos.x); sumSepVelocities.y += (my_pos.y - curPos.y); sumSepVelocities.z += (my_pos.z - curPos.z); + neighbours ++; } } if (neighbours > 0) { - sumVelocities /= neighbours; sumSepVelocities /= neighbours; sumPositions /= neighbours; // Centre of mass. + sumVelocities /= neighbours; } // Calculate total velocity: @@ -280,7 +347,7 @@ __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 * inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized) { float len = glm::length (vectorToBeNormalized); - if (len > 0.001) + if (len > 0.01) return vectorToBeNormalized / len; return vectorToBeNormalized; } @@ -405,11 +472,11 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation) else updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); - glm::vec3 *accn = new glm::vec3 [numObjects]; - for (int i= 0; i < numObjects; i ++) - accn [i] = glm::vec3 (0); - cudaMemcpy (accn, dev_acc, sizeof(glm::vec3)*numObjects, cudaMemcpyDeviceToHost); - int breakHere = -1; + //glm::vec3 *accn = new glm::vec3 [numObjects]; + //for (int i= 0; i < numObjects; i ++) + // accn [i] = glm::vec3 (0); + //cudaMemcpy (accn, dev_acc, sizeof(glm::vec3)*numObjects, cudaMemcpyDeviceToHost); + //int breakHere = -1; updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); @@ -429,4 +496,7 @@ void cudaUpdatePBO(float4 * pbodptr, int width, int height) cudaThreadSynchronize(); } - +void setDevicePrefetch (bool prefetchEnabled) +{ + cudaMemcpyToSymbol (&prefetch, &prefetchEnabled, sizeof (bool), 0); +} diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 7e528e2..61f34e6 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -21,6 +21,7 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation); void initCuda(int N); void cudaUpdatePBO(float4 * pbodptr, int width, int height); void cudaUpdateVBO(float * vbodptr, int width, int height); +void setDevicePrefetch (bool prefetchEnabled); inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized); // normalize only if length > 0 #endif diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index d59b274..5481782 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -9,6 +9,7 @@ #define VISUALIZE 1 bool customSimulation = false; +bool prefetchEnabled = false; //------------------------------- //-------------MAIN-------------- @@ -29,7 +30,7 @@ int main(int argc, char** argv) #else initCuda(20*120); #endif - +// setDevicePrefetch (prefetchEnabled); projection = glm::perspective(fovy, float(width)/float(height), zNear, zFar); view = glm::lookAt(cameraPosition, glm::vec3(0), glm::vec3(0,0,1)); @@ -185,7 +186,10 @@ void init(int argc, char* argv[]) { if (!strcmp (argv [1], "true")) customSimulation = true; - } + if (argc > 2) + if (!strcmp (argv [2], "prefetch")) + prefetchEnabled = true; + } initVAO(); initTextures(); From 9444bb3649288b1b2d84b4d42cb3623feaa3afc0 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Mon, 21 Oct 2013 21:42:32 -0400 Subject: [PATCH 12/23] Project build config changes. --- .gitignore | 4 +- Part1/PROJ_WIN/Project3.sln | 5 ++ Part1/PROJ_WIN/Project3/Project3.vcxproj | 95 +++++++++++++++++++++++- Part1/src/kernel.cu | 6 +- Part1/src/kernel.h | 2 +- 5 files changed, 105 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 921ac68..c1eade0 100644 --- a/.gitignore +++ b/.gitignore @@ -26,8 +26,8 @@ sph/output/* # Build results -[Dd]ebug/ -[Rr]elease/ +[Dd]ebug*/ +[Rr]elease*/ x64/ build/ [Bb]in/ diff --git a/Part1/PROJ_WIN/Project3.sln b/Part1/PROJ_WIN/Project3.sln index 4bc27f6..47cf600 100644 --- a/Part1/PROJ_WIN/Project3.sln +++ b/Part1/PROJ_WIN/Project3.sln @@ -6,13 +6,18 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 + Debug2|Win32 = Debug2|Win32 Release|Win32 = Release|Win32 + Release2|Win32 = Release2|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug|Win32.ActiveCfg = Debug|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug|Win32.Build.0 = Debug|Win32 + {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug2|Win32.ActiveCfg = Debug2|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release|Win32.ActiveCfg = Release|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release|Win32.Build.0 = Release|Win32 + {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release2|Win32.ActiveCfg = Release2|Win32 + {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release2|Win32.Build.0 = Release2|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Part1/PROJ_WIN/Project3/Project3.vcxproj b/Part1/PROJ_WIN/Project3/Project3.vcxproj index 0702d5b..7f7b7eb 100644 --- a/Part1/PROJ_WIN/Project3/Project3.vcxproj +++ b/Part1/PROJ_WIN/Project3/Project3.vcxproj @@ -1,10 +1,18 @@  + + Debug2 + Win32 + Debug Win32 + + Release2 + Win32 + Release Win32 @@ -21,6 +29,18 @@ MultiByte v100 + + Application + true + MultiByte + v100 + + + Application + true + MultiByte + v100 + Application false @@ -35,6 +55,12 @@ + + + + + + @@ -42,6 +68,13 @@ false + + false + + + + + Level3 @@ -65,6 +98,61 @@ compute_10,sm_10;compute_20,sm_20;compute_30,sm_30 + + + Level3 + Disabled + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + + + true + ../shared/glew/lib;../shared/freeglut/lib;%(AdditionalLibraryDirectories) + cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Console + mainCRTStartup + + + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes + $(ProjectDir)$(Platform)/$(Configuration)/%(Filename)%(Extension).obj + true + true + true + compute_10,sm_10;compute_20,sm_20;compute_30,sm_30 + + + + + Level3 + MaxSpeed + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes + WIN32;_CONSOLE;%(PreprocessorDefinitions) + true + Default + true + MultiThreadedDLL + ProgramDatabase + true + + + true + ../shared/glew/lib;../shared/freeglut/lib;%(AdditionalLibraryDirectories) + cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + Console + mainCRTStartup + true + true + Default + + + C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes + $(ProjectDir)$(Platform)/$(Configuration)/%(Filename)%(Extension).obj + false + false + false + compute_10,sm_10;compute_20,sm_20;compute_30,sm_30 + + Level3 @@ -72,13 +160,16 @@ true true C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes;%(AdditionalIncludeDirectories);$(CudaToolkitIncludeDir) + MultiThreadedDebugDLL true true true ../shared/glew/lib;../shared/freeglut/lib;%(AdditionalLibraryDirectories);$(CudaToolkitLibDir) - cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies); + cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) + mainCRTStartup + Console C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes @@ -94,6 +185,8 @@ Document compute_10,sm_10;compute_20,sm_20 + compute_10,sm_10;compute_20,sm_20 + compute_10,sm_10;compute_20,sm_20 diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index f8a676d..e86728d 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -25,9 +25,9 @@ const float scene_scale = 2e2; //size of the height map in simulation space #if SHARED == 1 // if (prefetch) - #define ACC(x,y,z) pfSharedMemAcc(x,y,z) +// #define ACC(x,y,z) pfSharedMemAcc(x,y,z) // else -// #define ACC(x,y,z) sharedMemAcc(x,y,z) + #define ACC(x,y,z) sharedMemAcc(x,y,z) #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) #else #define ACC(x,y,z) naiveAcc(x,y,z) @@ -208,7 +208,7 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) // Synchronize here. __syncthreads(); - // Compute acceleration only for all threads. + // Compute acceleration for all threads. // Loop over each object, and calculate acceleration. for (int i = 0; i < blockDim.x; i ++) { diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 61f34e6..9c9821a 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -14,7 +14,7 @@ #define blockSize 128 #define checkCUDAErrorWithLine(msg) checkCUDAError(msg, __LINE__) -#define SHARED 0 +#define SHARED 1 void checkCUDAError(const char *msg, int line); void cudaNBodyUpdateWrapper(float dt, bool customSimulation); From 39f7f3f4793528377672947f1ee5a86c08970950 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Mon, 21 Oct 2013 21:45:50 -0400 Subject: [PATCH 13/23] Removed the Debug2 configuration. Signed-off-by: Rohith Chandran --- Part1/PROJ_WIN/Project3.sln | 2 -- Part1/PROJ_WIN/Project3/Project3.vcxproj | 40 ------------------------ 2 files changed, 42 deletions(-) diff --git a/Part1/PROJ_WIN/Project3.sln b/Part1/PROJ_WIN/Project3.sln index 47cf600..6e2a4ab 100644 --- a/Part1/PROJ_WIN/Project3.sln +++ b/Part1/PROJ_WIN/Project3.sln @@ -6,14 +6,12 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 - Debug2|Win32 = Debug2|Win32 Release|Win32 = Release|Win32 Release2|Win32 = Release2|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug|Win32.ActiveCfg = Debug|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug|Win32.Build.0 = Debug|Win32 - {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Debug2|Win32.ActiveCfg = Debug2|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release|Win32.ActiveCfg = Release|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release|Win32.Build.0 = Release|Win32 {D7BEFF7A-4902-4B7E-922B-B0417A66864C}.Release2|Win32.ActiveCfg = Release2|Win32 diff --git a/Part1/PROJ_WIN/Project3/Project3.vcxproj b/Part1/PROJ_WIN/Project3/Project3.vcxproj index 7f7b7eb..6a72489 100644 --- a/Part1/PROJ_WIN/Project3/Project3.vcxproj +++ b/Part1/PROJ_WIN/Project3/Project3.vcxproj @@ -1,10 +1,6 @@  - - Debug2 - Win32 - Debug Win32 @@ -29,12 +25,6 @@ MultiByte v100 - - Application - true - MultiByte - v100 - Application true @@ -55,9 +45,6 @@ - - - @@ -68,9 +55,6 @@ false - - false - @@ -98,29 +82,6 @@ compute_10,sm_10;compute_20,sm_20;compute_30,sm_30 - - - Level3 - Disabled - C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes - WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - - - true - ../shared/glew/lib;../shared/freeglut/lib;%(AdditionalLibraryDirectories) - cudart.lib; glew32.lib;glu32.lib;opengl32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) - Console - mainCRTStartup - - - C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v5.5\include;C:/ProgramData/NVIDIA Corporation/CUDA Samples/v5.5/common/inc;../shared/glew/includes;../shared/freeglut/includes - $(ProjectDir)$(Platform)/$(Configuration)/%(Filename)%(Extension).obj - true - true - true - compute_10,sm_10;compute_20,sm_20;compute_30,sm_30 - - Level3 @@ -185,7 +146,6 @@ Document compute_10,sm_10;compute_20,sm_20 - compute_10,sm_10;compute_20,sm_20 compute_10,sm_10;compute_20,sm_20 From 1acb129b85cafb689386e0edf3dcc755d4223962 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Mon, 21 Oct 2013 23:38:40 -0400 Subject: [PATCH 14/23] Corrected calculations. --- Part1/src/kernel.cu | 56 +++++++++++++++------------------------------ Part1/src/main.cpp | 4 ++-- Part1/src/main.h | 2 +- 3 files changed, 21 insertions(+), 41 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index e86728d..5dd571e 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -25,9 +25,9 @@ const float scene_scale = 2e2; //size of the height map in simulation space #if SHARED == 1 // if (prefetch) -// #define ACC(x,y,z) pfSharedMemAcc(x,y,z) + #define ACC(x,y,z) pfSharedMemAcc(x,y,z) // else - #define ACC(x,y,z) sharedMemAcc(x,y,z) +// #define ACC(x,y,z) sharedMemAcc(x,y,z) #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) #else #define ACC(x,y,z) naiveAcc(x,y,z) @@ -154,16 +154,14 @@ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); int index = threadIdx.x + (blockIdx.x * blockDim.x); -// if (index < N) -// { - for (int i = 0; i < N; i ++) - { - if (their_pos [i] == my_pos) - continue; - acc += calculateAcceleration(my_pos, their_pos [i]); - } - acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); -// } + for (int i = 0; i < N; i ++) + { + if (their_pos [i] == my_pos) + continue; + acc += calculateAcceleration(my_pos, their_pos [i]); + } + acc += calculateAcceleration (my_pos, glm::vec4 (0, 0, 0, starMass)); + return acc; } @@ -184,23 +182,13 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); -// int loopMax = ceil (N / (float)blockDim.x); - // Loop over each block (assuming parallelization of objects) and load objects from global to shared memory. - // The first block of threads will load the first blockDim.x no. of objects from global memory to shared memory; - // The next block will load the next blockDim.x no. of objects from global and so on. Thus, we load the entire - // set of positions in global memory into shared memory iteratively, one block at a time. + // Each block of threads will load blockDim.x no. of objects from global memory to shared memory; + // Thus, we load the entire set of positions in global memory into shared memory iteratively, one block at a time. for (int j = 0; j < ceil (N / (float)blockDim.x); j ++) { - // refBlockIndex is the block index of the block of memory locations we're trying to copy into shared. - int refblockIndex = blockIdx.x + j; - - // If trying to load a block beyond the grid boundary, wrap around. - if (refblockIndex >= ceil (N / (float)blockDim.x)) - refblockIndex -= ceil (N / (float)blockDim.x); - // Calculate global memory index that should be accessed by this thread. - int index = blockDim.x * refblockIndex + threadIdx.x; + int index = blockDim.x * j + threadIdx.x; // Load the value from global to shared. if (index < N) shared_pos [threadIdx.x] = their_pos [index]; @@ -215,7 +203,7 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) // If the block of global memory we're loading into shared mem corresponds to the last block in the grid, // it can contain less than blockDim.x elements. In such a situation, break out of the loop once we pass // the last element in that "block". - if (refblockIndex == (floor (N / (float)blockDim.x))) + if (j == (floor (N / (float)blockDim.x))) if (i >= (N%blockDim.x)) break; @@ -246,17 +234,13 @@ glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) glm::vec3 acc = glm::vec3 (0); glm::vec4 prefetcher = glm::vec4 (0); - int index = blockDim.x * blockIdx.x + threadIdx.x; + int index = threadIdx.x; if (index < N) prefetcher = their_pos [index]; // Prefetch first element into register. for (int j = 0; j < ceil (N / (float)blockDim.x); j ++) { - int refblockIndex = blockIdx.x + j + 1; - if (refblockIndex >= ceil (N / (float)blockDim.x)) - refblockIndex -= ceil (N / (float)blockDim.x); - - index = blockDim.x * refblockIndex + threadIdx.x; + index = blockDim.x * (j+1) + threadIdx.x; shared_pos [threadIdx.x] = prefetcher; // Copy prefetched element into shared memory. prefetcher = glm::vec4 (0); @@ -268,7 +252,7 @@ glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) for (int i = 0; i < blockDim.x; i ++) { - if (refblockIndex == (floor (N / (float)blockDim.x))) + if (j == (floor (N / (float)blockDim.x))) if (i >= (N%blockDim.x)) break; @@ -472,11 +456,7 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation) else updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); - //glm::vec3 *accn = new glm::vec3 [numObjects]; - //for (int i= 0; i < numObjects; i ++) - // accn [i] = glm::vec3 (0); - //cudaMemcpy (accn, dev_acc, sizeof(glm::vec3)*numObjects, cudaMemcpyDeviceToHost); - //int breakHere = -1; + updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 5481782..7da2414 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -4,9 +4,9 @@ #include "main.h" -#define N_FOR_VIS 25 +#define N_FOR_VIS 10000000 #define DT 0.2 -#define VISUALIZE 1 +#define VISUALIZE 0 bool customSimulation = false; bool prefetchEnabled = false; diff --git a/Part1/src/main.h b/Part1/src/main.h index d0b26c9..634dfec 100644 --- a/Part1/src/main.h +++ b/Part1/src/main.h @@ -62,7 +62,7 @@ glm::vec3 cameraPosition(1.75,1.75,1.35); //----------CUDA STUFF----------- //------------------------------- -int width=500; int height=500; +int width=1024; int height=768; //------------------------------- //-------------MAIN-------------- From 3011157109bbac4cb9a799a642c1530455050e25 Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Tue, 22 Oct 2013 09:42:28 -0400 Subject: [PATCH 15/23] Leapfrog Integration. --- Part1/src/kernel.cu | 191 ++++++++++++++++++++++++++++---------------- Part1/src/kernel.h | 5 ++ Part1/src/main.cpp | 4 +- 3 files changed, 130 insertions(+), 70 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 5dd571e..78888ef 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -5,14 +5,6 @@ #include "utilities.h" #include "kernel.h" -//#if SHARED == 1 -// #define ACC(x,y,z) pfSharedMemAcc(x,y,z) -// #define FLOCK(p,q,r,s,t) FlockShared(p,q,r,s,t) -//#else -// #define ACC(x,y,z) naiveAcc(x,y,z) -// #define FLOCK(p,q,r,s,t) FlockGlobal(p,q,r,s,t) -//#endif - //GLOBALS dim3 threadsPerBlock(blockSize); @@ -122,6 +114,35 @@ void generateRandomVelArray(int time, int N, glm::vec3 * arr, float scale) } } +// Calculate gravitational acceleration. +__global__ +void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + glm::vec4 my_pos; + glm::vec3 accel; + + if(index < N) my_pos = pos[index]; + + accel = ACC(N, my_pos, pos); + + if(index < N) acc[index] = accel; +} + +//Simple Euler integration scheme +__global__ +void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + if( index < N ) + { + vel[index] += acc[index] * dt; + pos[index].x += vel[index].x * dt; + pos[index].y += vel[index].y * dt; + pos[index].z += vel[index].z * dt; + } +} + //TODO: Done! __device__ glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) @@ -146,18 +167,66 @@ glm::vec3 calculateAcceleration(glm::vec4 us, glm::vec4 them) return glm::vec3 (0); } -//TODO: Done! + +//Update the vertex buffer object +//(The VBO is where OpenGL looks for the positions for the planets) +__global__ +void sendToVBO(int N, glm::vec4 * pos, float * vbo, int width, int height, float s_scale) +{ + int index = threadIdx.x + (blockIdx.x * blockDim.x); + + float c_scale_w = -2.0f / s_scale; + float c_scale_h = -2.0f / s_scale; + + if(index= (b - 0.001)) && (a <= (b + 0.001))) @@ -173,7 +243,9 @@ __device__ bool isApproximately (const float &a, const float &b) return false; } -//TODO: Done! +// Calculate acceleration for each object using shared memory, given the number of particles (N), +// their positions (their_pos) and this object's position (my_pos). +// Written by Rohith Chandran. __device__ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { @@ -225,6 +297,7 @@ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) // Shared memory acceleration calculation with prefetching. // Written as a separate function to compare performance. +// Written by Rohith Chandran. __device__ glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) { @@ -272,6 +345,7 @@ glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos) } // Calculate flocking velocity. +// Written by Rohith Chandran. __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel) { glm::vec3 acc = glm::vec3 (0); @@ -328,6 +402,7 @@ __device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 * } // normalize only if length > 0 +// Written by Rohith Chandran. inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized) { float len = glm::length (vectorToBeNormalized); @@ -336,22 +411,8 @@ inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized) return vectorToBeNormalized; } -// Calculate gravitational acceleration. -__global__ -void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) -{ - int index = threadIdx.x + (blockIdx.x * blockDim.x); - glm::vec4 my_pos; - glm::vec3 accel; - - if(index < N) my_pos = pos[index]; - - accel = ACC(N, my_pos, pos); - - if(index < N) acc[index] = accel; -} - -// Calculate acceleration for Custom Simulation. +// Calculate acceleration for Custom Simulation (flocking). +// Written by Rohith Chandran. __global__ void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { @@ -366,62 +427,50 @@ void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 if(index < N) acc[index] = accel; } -//Simple Euler integration scheme +// Update state using Verlet Integration +// Written by Rohith Chandran. __global__ -void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +void updateS_V (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { int index = threadIdx.x + (blockIdx.x * blockDim.x); if( index < N ) { - vel[index] += acc[index] * dt; - pos[index].x += vel[index].x * dt; - pos[index].y += vel[index].y * dt; - pos[index].z += vel[index].z * dt; + glm::vec4 curPos = pos [index]; + glm::vec3 curVel = vel [index]; + glm::vec4 prevPos = curPos - (dt * glm::vec4 (curVel.x, curVel.y, curVel.z, 0)); + + curPos = (2.0*curPos) - prevPos + (dt * dt * glm::vec4 (acc [index].x, acc [index].y, acc [index].z, 0)); + prevPos = (curPos - prevPos) / (2.0*dt); + curVel.x = prevPos.x; + curVel.y = prevPos.y; + curVel.z = prevPos.z; + + vel[index] = curVel; + pos[index] = curPos; } } -//Update the vertex buffer object -//(The VBO is where OpenGL looks for the positions for the planets) +// Update state using Leapfrog Integration. +// Written by Rohith Chandran. __global__ -void sendToVBO(int N, glm::vec4 * pos, float * vbo, int width, int height, float s_scale) +void updateS_LF (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) { int index = threadIdx.x + (blockIdx.x * blockDim.x); - - float c_scale_w = -2.0f / s_scale; - float c_scale_h = -2.0f / s_scale; - - if(index>>(2, numObjects, dev_vel, dev_pos); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); + + float dt = 0.1; + updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + setupVelocityLF<<>>(numObjects, dt, dev_vel, dev_acc); } void cudaNBodyUpdateWrapper(float dt, bool customSimulation) @@ -457,7 +510,9 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation) updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); - updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); +// updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); +// updateS_V<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); + updateS_LF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); } diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 9c9821a..d6cd9a5 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -24,4 +24,9 @@ void cudaUpdateVBO(float * vbodptr, int width, int height); void setDevicePrefetch (bool prefetchEnabled); inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized); // normalize only if length > 0 +__device__ bool isApproximately (const float &a, const float &b); +__device__ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos); +__device__ glm::vec3 pfSharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos); +__device__ glm::vec3 FlockGlobal (int N, float DT, glm::vec4 my_pos, glm::vec4 *pos, glm::vec3 *vel); +__device__ glm::vec3 naiveAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos); #endif diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 7da2414..5481782 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -4,9 +4,9 @@ #include "main.h" -#define N_FOR_VIS 10000000 +#define N_FOR_VIS 25 #define DT 0.2 -#define VISUALIZE 0 +#define VISUALIZE 1 bool customSimulation = false; bool prefetchEnabled = false; From 2a3de6d70591208e5426e6b4551e9814186da38d Mon Sep 17 00:00:00 2001 From: rohith10 Date: Tue, 22 Oct 2013 10:54:33 -0400 Subject: [PATCH 16/23] Update README.md --- README.md | 425 ++++++++---------------------------------------------- 1 file changed, 62 insertions(+), 363 deletions(-) diff --git a/README.md b/README.md index e3122aa..39a2bbf 100644 --- a/README.md +++ b/README.md @@ -1,373 +1,72 @@ CIS565: Project 3: CUDA Simulation and GLSL Visualization === -Fall 2013 ---- -Due Sunday, 10/20/2013 by 11:59:59 pm ---- ---- -NOTE: ---- -This project requires an NVIDIA graphics card with CUDA capability! Any card -after the Geforce 8xxx series will work. If you do not have an NVIDIA graphics -card in the machine you are working on, feel free to use any machine in the SIG -Lab or in Moore100 labs. All machines in the SIG Lab and Moore100 are equipped -with CUDA capable NVIDIA graphics cards. If this too proves to be a problem, -please contact Patrick or Liam as soon as possible. +For this project, I wrote code to implement an N-Body simulation in CUDA, visualized using GLSL. The N-Body simulator +is like a gravity sim resembling a solar system where planets would orbit around a star. This assignment was an exercise +on the use of shared memory and how efficient it is for programs, since the last two (the Raytracer and Pathtracer) +didn't explicitly focus on performance and efficiency. As always, a framework starter code was provided by our TA, +Liam Boone. ---- -INTRODUCTION: ---- -In this project you will be creating a 3D visualization of an N-Body system -simulated using CUDA and OpenGL shaders. You will also be creating your own -simulation of choice. +The code I've written could be optimized a lot further, since it contains quite a lot of uncoalesced global memory +accesses and shared memory access bank conflicts (where the threads loop through each element in shared/global memory). +One way that this could be done is by launching a block of threads for every object in which each thread will only calculate +the force/acceleration on that object due to a single other object in the scene. A Parallel reduction could then be +performed to find the total force/acceleration on that body. However, it is impossible to predict what the effect will be +on performance without performing performance profiling using NSight, which is out of bounds for me. -This project is divided into two parts. Part one will consist mostly of a -tutorial style walkthrough of creating the N-Body sim. Part two is an open -ended assignment to create your own simulation. This simulation can be virtually -anything you choose, but will require approval for ideas not listed in this -readme. +Nevertheless, using this code, I was able to witness a HUGE speedup when using shared memory as opposed to global (53 fps vs. 243). -You are also free to do as many extra simulations as you like! +DETAILS +------- +In this project, the positions, velocities and accelerations of all objects are stored in global memory locations +dev_pos, +dev_vel +and dev_acc respectively. I was required to write device functions to calculate the accelerations for every object using +both the global memory and shared memory. As an added bonus, I was able to implement prefetching for shared memory (where +instead of directly loading a value from global memory into shared, we pre-load into a register ahead of the current +iteration and then load that into shared during the current iteration) and two other integration schemes: Verlet and +Leapfrog (a Symplectic Euler integrator was provided by default). ---- -CONTENTS: ---- -The Project3 root directory contains the following subdirectories: +In addition to the above, I was also required to do my own simulation. I implemented dynamic flocking, where planets +dynamically drop in and out of flocks. Such flocks are created on the fly as planets move around. - * Part1/ - * resources/ the screenshots used in this readme. - * src/ contains the provided code. __NOTE:__ Shader code will be located in the PROJ3_XYZ folders - * PROJ_WIN/ contains a Visual Studio 2010 project file with different configurations - * Debug (v4.0) - * Release (v4.0) - * Debug (v5.5) - * Release (v5.5) - * PROJ_NIX/ contains a Linux makefile for building and running on Ubuntu - 12.04 LTS. Note that you will need to set the following environment - variables (you may set these any way that you like. I added them to my .bashrc): - * PATH=$PATH:/usr/local/cuda-5.5/bin - * LD_LIBRARY_PATH=/usr/local/cuda-5.5/lib64:/lib - * Part2/ you will fill this with your own simulation code. -__NOTE:__ Since I do not use Apple products regularly enough to know what I'm doing I did not create a Mac friendly version of the project. I will award a +5 point bounty to the first person to open a pull request containing an OSX compatible version of the starter code. All runners up will receive +100 awesome points. - -PART 1: CUDA NBody Simulation -=== - ---- -REQUIREMENTS: ---- -In this project, you are given code for: - * Initialization - * Rendering to the screen - * Some helpful math functions - * CUDA/OpenGL inter-op - -You will need to implement the following features: - * Calculating forces between all interacting bodies - * The same, but with shared memory - * Vertex shader code to render a height field - * Fragment shader code to light that height field - * Geometry shader code to create screen facing billboards from rendered points - * Fragment shader code to render those billboards like spheres with simple diffuse shading - -You are NOT required to implement any of the following features: - * Prefetching (__NOTE:__ to receive +5 for this feature it must be discussed in your performance section) - * Tessellation shader code to refine the heightfield mesh in regions of interest - * Render the height map as a quad and use parallax occlusion mapping in the fragment shader to simulate the height field - * More interesting rendering of the scene (making some planets light sources would be cool, or perhaps adding orbit trails) - * Textures for the planets and/or unique looking planets - * Replace geometry shader billboarding with adding in simple models (e.g. a pyramid pointing in the direction of velocity) - * Collisions - * Runge Kutta integration (or anything better than the Euler integration provided) - -Since we had some problems going live on time with this project you can give yourself a +5 point boost for including up to two of the above extra features. For example, adding collisions and textured planets along with completing all other required components can get you a 110% score. - ---- -WALKTHROUGH ---- -You can choose to complete all of the TODO: tags in the kernel.cu file either before or after sprucing up the graphics, but it will be easier to see some of our improvements if you finish them before. - -For the graphics, you'll see something that looks like this: - -![boring](Part1/resources/000.png) - -Pretty underwhelming if I do say so. Lets add some height and coloring in the height field so we can see what the potential field looks like. - -Since the starter code saves a very high resolution force field to texture memory we will use that to perturb the Z components of the height field. In addition we also multiply by the camera matrix to get everything in the right place. Add the following code to your heightVS.glsl file: - -```glsl -uniform mat4 u_projMatrix; -uniform sampler2D u_height; - -attribute vec4 Position; -attribute vec2 Texcoords; - -varying vec2 v_Texcoords; -varying float f_height; - -void main(void) -{ - v_Texcoords = Texcoords; - vec4 pos = Position; - f_height = texture2D(u_height, Texcoords).w; - pos.z = -0.01-clamp(f_height,0.0,2.0); - pos = u_projMatrix * pos; - gl_Position = pos; -} -``` - -You can run the code as is right now, but you'll likely see very little difference in most cases. In order to really get the feel we want, without the added complexity of doing real lighting we'll just darken the fragment color based on the height map. Add the following to your heightFS.glsl file: - -```glsl -varying float f_height; - -void main(void) -{ - float shade = (1.0-2.0*sqrt(f_height)); - vec4 color = vec4(0.05,0.15,0.3,1.0); - gl_FragColor = shade*color; -} -``` - -Now your height field should look closer to this: - -![less boring](Part1/resources/001.png) - -Okay, that's a lot better, but now our planets need some attention. For this step we'll be using the geometry shader to create screen facing quads from the points that are currently being rendered. Essentially, what we want is to create a geometry shader that takes in points and emits triangle strips, so replace the version of planetGS.glsl with this: - -```glsl -#version 330 - -uniform mat4 u_projMatrix; -uniform vec3 u_cameraPos; - -layout (points) in; -layout (triangle_strip) out; -layout (max_vertices = 4) out; - -out vec3 WorldCoord; -out vec3 ToCam; -out vec3 Up; -out vec3 Right; -out vec2 TexCoord; - -const float scale = 0.03; -``` - -Before we can produce the vertices for our quad we need to figure out where they go. This code takes the vector from the point to the camera and crosses it with the up vector (usually I conform to convention and use +Y, but here I used +Z and never got around to fixing it) to produce the right vector. Next we cross the right vector and the camera vector to produce a corrected up vector. - -```glsl -void main() -{ - vec3 Position = gl_in[0].gl_Position.xyz; - WorldCoord = Position; - - ToCam = normalize(u_cameraPos - Position); - Up = vec3(0.0, 0.0, 1.0); - Right = cross(ToCam, Up); - Up = cross(Right, ToCam); -``` - -Now that we have the correct up and right vectors, we can emit our vertices and produce our screen facing quads: - -```glsl - vec3 Pos = Position + scale*Right - scale*Up; - gl_Position = u_projMatrix * vec4(Pos, 1.0); - TexCoord = vec2(0.0, 0.0); - EmitVertex(); - - Pos = Position + scale*Right + scale*Up; - gl_Position = u_projMatrix * vec4(Pos, 1.0); - TexCoord = vec2(0.0, 1.0); - EmitVertex(); - - Pos = Position - scale*Right - scale*Up; - gl_Position = u_projMatrix * vec4(Pos, 1.0); - TexCoord = vec2(1.0, 0.0); - EmitVertex(); - - Pos = Position - scale*Right + scale*Up; - gl_Position = u_projMatrix * vec4(Pos, 1.0); - TexCoord = vec2(1.0, 1.0); - EmitVertex(); - - EndPrimitive(); -} -``` - -![cool](Part1/resources/002.png) - -__NOTE:__ You'll notice here that the quads are not aligned to the screen, they merely face it. This is okay for our purposes because we are using them to render spheres. - -With our quads we can do some very fancy things in the fragment shader. Use the following snippets to replace the existing planetFS.glsl file: - -```glsl -#version 330 - -in vec3 WorldCoord; -in vec3 ToCam; -in vec3 Up; -in vec3 Right; -in vec2 TexCoord; -out vec4 FragColor; - -void main() -{ -``` - -This section takes the "texture" coordinates produces in the GS and uses them to decide where in the quad this fragment is. We discard any fragments outside of our desired radius in order to simulate the edge of the sphere. - -```glsl - vec2 coord = 2.01 * (TexCoord - vec2(0.5)); - float r = length(coord); - if (r >= 1.0) { discard; } -``` - -Since I designed this project with the center object being a star I execute an early out here to simply color it white. - -```glsl - float dist = length(WorldCoord); - if(dist <= 0.01) - { - FragColor = vec4(1.0); - return; - } -``` - -This last segment takes care of calculating the fake intersection point and its lighting. I am using a simple diffuse + constant ambient with exponential attenuation. - -```glsl - vec3 N = Right*-coord.x + Up*coord.y + ToCam*sqrt(1-r*r); - vec3 L = normalize(-WorldCoord); - float light = 0.1 + 0.9*clamp(dot(N,L),0.0, 1.0)*exp(-dist); - vec3 color = vec3(0.4, 0.1, 0.6); - FragColor = vec4(color*light,1.0); -} -``` - -![almost there](Part1/resources/003.png) - -The last thing we add is a little bit of procedural coloring to give a nice grid effect. Replace the boring color code in heightFS.glsl with this: - -```glsl -float alpha = float(mod(v_Texcoords.x+0.025, 0.05) > 0.046 || - mod(v_Texcoords.y+0.025, 0.05) > 0.046); -vec4 color = mix(vec4(0.05,0.15,0.3,1.0), vec4(0.05, 0.3, 0.4, 1.0), alpha); -``` - -![awesome](Part1/resources/004.png) - -Now we have a beautiful looking (if simple) gravity sim! - - -PART 2: Your CUDA Simulation -=== - -To complete this part of the assignment you must implement your own simulation. This can be anything within reason, but two examples that would be well suited are: - -* Flocking -* Mass spring cloth/jello - -Feel free to code your own unique simulation here, just ask on the Google group if your topic is acceptable and we'll probably say yes. - ---- -NOTES ON GLM: ---- -This project uses GLM, the GL Math library, for linear algebra. You need to -know two important points on how GLM is used in this project: - -* In this project, indices in GLM vectors (such as vec3, vec4), are accessed - via swizzling. So, instead of v[0], v.x is used, and instead of v[1], v.y is - used, and so on and so forth. -* GLM Matrix operations work fine on NVIDIA Fermi cards and later, but - pre-Fermi cards do not play nice with GLM matrices. As such, in this project, - GLM matrices are replaced with a custom matrix struct, called a cudaMat4, found - in cudaMat4.h. A custom function for multiplying glm::vec4s and cudaMat4s is - provided as multiplyMV() in intersections.h. - ---- -README ---- -All students must replace the contents of this Readme.md in a clear manner with -the following: - -* A brief description of the project and the specific features you implemented. -* At least one screenshot of your project running. -* A 30 second or longer video of your project running. To create the video you - can use http://www.microsoft.com/expression/products/Encoder4_Overview.aspx -* A performance evaluation (described in detail below). - ---- PERFORMANCE EVALUATION ---- -The performance evaluation is where you will investigate how to make your CUDA -programs more efficient using the skills you've learned in class. You must -perform at least one experiment on your code to investigate the positive or -negative effects on performance. - -For this Project, one of these experiments should be a comparison between the -global and shared memory versions of the acceleration calculation function at -varying block sizes. - -A good metric to track would be number of frames per second, -or number of objects displayable at 60fps. - -We encourage you to get creative with your tweaks. Consider places in your code -that could be considered bottlenecks and try to improve them. - -Each student should provide no more than a one page summary of their -optimizations along with tables and or graphs to visually explain any -performance differences. - ---- -THIRD PARTY CODE POLICY ---- -* Use of any third-party code must be approved by asking on our Google group. - If it is approved, all students are welcome to use it. Generally, we approve - use of third-party code that is not a core part of the project. For example, - for the ray tracer, we would approve using a third-party library for loading - models, but would not approve copying and pasting a CUDA function for doing - refraction. -* Third-party code must be credited in README.md. -* Using third-party code without its approval, including using another - student's code, is an academic integrity violation, and will result in you - receiving an F for the semester. - ---- -SELF-GRADING ---- -* On the submission date, email your grade, on a scale of 0 to 100, to Liam, - liamboone+cis565@gmail.com, with a one paragraph explanation. Be concise and - realistic. Recall that we reserve 30 points as a sanity check to adjust your - grade. Your actual grade will be (0.7 * your grade) + (0.3 * our grade). We - hope to only use this in extreme cases when your grade does not realistically - reflect your work - it is either too high or too low. In most cases, we plan - to give you the exact grade you suggest. -* For late assignments there will be a 50% penaly per week. -* Projects are not weighted evenly, e.g., Project 0 doesn't count as much as - the path tracer. We will determine the weighting at the end of the semester - based on the size of each project. - ---- -SUBMISSION ---- -As with the previous project, you should fork this project and work inside of -your fork. Upon completion, commit your finished project back to your fork, and -make a pull request to the master repository. You should include a README.md -file in the root directory detailing the following - -* A brief description of the project and specific features you implemented -* At least one screenshot of your project running. -* A link to a video of your raytracer running. -* Instructions for building and running your project if they differ from the - base code. -* A performance writeup as detailed above. -* A list of all third-party code used. -* This Readme file edited as described above in the README section. - ---- -ACKNOWLEDGEMENTS ---- -I adapted the geometry shader code from [this excellent tutorial on the subject](http://ogldev.atspace.co.uk/www/tutorial27/tutorial27.html) +---------------------- +Performance of the program was compared for different number of planets/objects being simulated, using global memory, shared +memory and prefetched version of shared memory. Here are the results:
+
+With visualization on:
+
+Memory type Number of objects Framerate Number of objects Framerate +----------- ----------------- --------- ----------------- --------- +Global 2500 1.75 5000
+Shared 2500 12 5000 6.77
+Shared (Prefetched) 2500 12 5000 6.77
+
+
+With visualization off:
+
+Memory type Number of objects Framerate (avg.) Number of objects Framerate +----------- ----------------- ---------------- ----------------- --------- +Global 1,500,000 53 3,000,000 53
+Shared 1,500,000 615 3,000,000 620
+Shared (Prefetched) 1,500,000 630 3,000,000 630
+
+Memory type Number of objects Framerate (avg.) Number of objects Framerate +----------- ----------------- ---------------- ----------------- --------- +Global 5,000,000 53 10,000,000 53
+Shared 5,000,000 630 10,000,000 615
+Shared (Prefetched) 5,000,000 630 10,000,000 615
+
+Memory type Number of objects Framerate (avg.) Number of objects Framerate +----------- ----------------- ---------------- ----------------- --------- +Global 20,000,000 53 50,000,000 53
+Shared 20,000,000 620 50,000,000 620
+Shared (Prefetched) 20,000,000 615 50,000,000 630
+ +These results show that shared memory is WAY better than global memory. As I mentioned above, if the bank conflicts +resulting out of threads accessing multiple shared memory locations were to be corrected, the program would run much faster. + +The results also show no great advantage while using prefetching. I believe this is because there are not many independent +instructions to mask out the latency involved in accessing global memory. From ed45623983790e12f78dddaa2768e186cfe1014b Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Tue, 22 Oct 2013 17:39:00 -0400 Subject: [PATCH 17/23] Rudimentary camera repositioning. --- Part1/src/kernel.cu | 39 ++++++++++++++++++++++++++++++++++++++- Part1/src/kernel.h | 6 +++++- Part1/src/main.cpp | 35 +++++++++++++++++++++++++++++++---- Part1/src/main.h | 4 +++- 4 files changed, 77 insertions(+), 7 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 78888ef..0dc70f9 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -29,6 +29,7 @@ const float scene_scale = 2e2; //size of the height map in simulation space glm::vec4 * dev_pos; glm::vec3 * dev_vel; glm::vec3 * dev_acc; +glm::vec4 * dev_campos; void checkCUDAError(const char *msg, int line = -1) { @@ -473,12 +474,28 @@ void setupVelocityLF (int N, float dt, glm::vec3 * vel, glm::vec3 * acc) vel[index] += acc [index] * dt; } +__global__ void moveCamera (int N, glm::vec4* campos, glm::vec4* pos) +{ + for (int i = 0; i < N; i ++) + { + if (glm::length (pos [i] - *campos) > 5.0) + { + *campos = pos [i]; + campos->z += 2.0f; +// campos->y -= 0.5f; + + break; + } + } +} + + /************************************* * Wrappers for the __global__ calls * *************************************/ //Initialize memory, update some globals -void initCuda(int N) +void initCuda(int N, const glm::vec4 &camera_position) { numObjects = N; dim3 fullBlocksPerGrid((int)ceil(float(N)/float(blockSize))); @@ -488,8 +505,11 @@ void initCuda(int N) cudaMalloc((void**)&dev_vel, N*sizeof(glm::vec3)); checkCUDAErrorWithLine("Kernel failed!"); cudaMalloc((void**)&dev_acc, N*sizeof(glm::vec3)); + checkCUDAErrorWithLine("Kernel failed!"); + cudaMalloc((void**)&dev_campos, sizeof(glm::vec4)); checkCUDAErrorWithLine("Kernel failed!"); + cudaMemcpy (dev_campos, &camera_position, sizeof (camera_position), cudaMemcpyHostToDevice); generateRandomPosArray<<>>(1, numObjects, dev_pos, scene_scale, planetMass); checkCUDAErrorWithLine("Kernel failed!"); generateCircularVelArray<<>>(2, numObjects, dev_vel, dev_pos); @@ -535,3 +555,20 @@ void setDevicePrefetch (bool prefetchEnabled) { cudaMemcpyToSymbol (&prefetch, &prefetchEnabled, sizeof (bool), 0); } + +glm::vec4 getCurrentCameraPosition () +{ + glm::vec4 camera_position; + cudaMemcpy (&camera_position, dev_campos, sizeof (camera_position), cudaMemcpyDeviceToHost); + return camera_position/scene_scale; +} + +void setCurrentCameraPosition (const glm::vec4 &camera_position) +{ + cudaMemcpy (dev_campos, &camera_position, sizeof (camera_position), cudaMemcpyHostToDevice); +} + +void moveCameraToNextFlock (glm::vec3 &cameraPos) +{ + moveCamera<<<1,1>>> (numObjects, dev_campos, dev_pos); +} diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index d6cd9a5..ba59fd4 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -18,11 +18,15 @@ void checkCUDAError(const char *msg, int line); void cudaNBodyUpdateWrapper(float dt, bool customSimulation); -void initCuda(int N); +void initCuda(int N, const glm::vec4 &camera_position); void cudaUpdatePBO(float4 * pbodptr, int width, int height); void cudaUpdateVBO(float * vbodptr, int width, int height); void setDevicePrefetch (bool prefetchEnabled); +void moveCameraToNextFlock (glm::vec3 &cameraPos); +glm::vec4 getCurrentCameraPosition (); +void setCurrentCameraPosition (const glm::vec4 &camera_position); + inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized); // normalize only if length > 0 __device__ bool isApproximately (const float &a, const float &b); __device__ glm::vec3 sharedMemAcc(int N, glm::vec4 my_pos, glm::vec4 * their_pos); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index 5481782..e14682b 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -10,7 +10,7 @@ bool customSimulation = false; bool prefetchEnabled = false; - +bool cameraToggle = false; //------------------------------- //-------------MAIN-------------- //------------------------------- @@ -26,15 +26,15 @@ int main(int argc, char** argv) cudaGLRegisterBufferObject( planetVBO ); #if VISUALIZE == 1 - initCuda(N_FOR_VIS); + initCuda(N_FOR_VIS, glm::vec4 (cameraPosition, 1)); #else initCuda(20*120); #endif // setDevicePrefetch (prefetchEnabled); - projection = glm::perspective(fovy, float(width)/float(height), zNear, zFar); + perspMat = glm::perspective(fovy, float(width)/float(height), zNear, zFar); view = glm::lookAt(cameraPosition, glm::vec3(0), glm::vec3(0,0,1)); - projection = projection * view; + projection = perspMat * view; GLuint passthroughProgram; initShaders(program); @@ -156,6 +156,33 @@ void keyboard(unsigned char key, int x, int y) case(27): exit(1); break; + case 'C': + cameraToggle = !cameraToggle; + if (!cameraToggle) + { + cameraPosition = glm::vec3 (originalCamPosition); + setCurrentCameraPosition (glm::vec4 (cameraPosition, 1.0)); + view = glm::lookAt(cameraPosition, glm::vec3 (0), glm::vec3(0,0,1)); + } + case 'N': + if (cameraToggle) + { + moveCameraToNextFlock (cameraPosition); + glm::vec4 temp_cp = getCurrentCameraPosition (); + cameraPosition.x = temp_cp.x; cameraPosition.y = temp_cp.y; cameraPosition.z = temp_cp.z; +// cameraPosition = glm::vec3 (1.0, 1.0, 1.2); + view = glm::lookAt(cameraPosition, glm::vec3 (cameraPosition.x, cameraPosition.y +0.7f, cameraPosition.z-0.5f), + glm::vec3(0,0,1)); + } + + projection = perspMat * view; + glUseProgram(program[0]); + glUniformMatrix4fv (glGetUniformLocation(program[0], "u_projMatrix"), 1, GL_FALSE, &projection [0][0]); + glUseProgram(program[1]); + glUniformMatrix4fv (glGetUniformLocation(program[1], "u_projMatrix"), 1, GL_FALSE, &projection [0][0]); + glUniform3fv (glGetUniformLocation(program[1], "u_cameraPos"), 1, &cameraPosition [0]); + glUseProgram (program[0]); + break; } } diff --git a/Part1/src/main.h b/Part1/src/main.h index 634dfec..5b1fd25 100644 --- a/Part1/src/main.h +++ b/Part1/src/main.h @@ -55,9 +55,11 @@ float fovy = 60.0f; float zNear = 0.10; float zFar = 5.0; +glm::mat4 perspMat; glm::mat4 projection; glm::mat4 view; -glm::vec3 cameraPosition(1.75,1.75,1.35); +glm::vec3 originalCamPosition(1.75,1.75,1.35); +glm::vec3 cameraPosition (originalCamPosition); //------------------------------- //----------CUDA STUFF----------- //------------------------------- From 8a274b4219bc2448b0e7844b4e4b8566976d85dc Mon Sep 17 00:00:00 2001 From: Rohith Chandran Date: Tue, 22 Oct 2013 22:48:27 -0400 Subject: [PATCH 18/23] Tantalizingly close to interactive camera. --- Part1/src/kernel.cu | 84 +++++++++++++++++++++++++++++++++++----- Part1/src/kernel.h | 1 + Part1/src/main.cpp | 2 + screenshots/flock.png | Bin 0 -> 107674 bytes screenshots/gravsim.png | Bin 0 -> 102534 bytes 5 files changed, 77 insertions(+), 10 deletions(-) create mode 100644 screenshots/flock.png create mode 100644 screenshots/gravsim.png diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 0dc70f9..4965154 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -8,12 +8,17 @@ //GLOBALS dim3 threadsPerBlock(blockSize); +#define CAMHEIGHT 150.0f +#define CAMFORWARD 60.0f + int numObjects; const float planetMass = 3e8; const __device__ float starMass = 5e10; const __device__ float GravConst = 6.67384e-11; __device__ bool prefetch; +__device__ int attachedToIndex; const float scene_scale = 2e2; //size of the height map in simulation space +bool camUpdate = false; #if SHARED == 1 // if (prefetch) @@ -132,15 +137,31 @@ void updateF(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) //Simple Euler integration scheme __global__ -void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +void updateS(int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc, glm::vec4 * dev_campos, bool cameraUpdate) { int index = threadIdx.x + (blockIdx.x * blockDim.x); if( index < N ) { + bool isCameraAttached = false; + glm::vec4 curPos = pos [index]; + if (cameraUpdate) + { + if (isApproximately (curPos.x, dev_campos->x) && + isApproximately (curPos.y, dev_campos->y+CAMFORWARD) && + isApproximately (curPos.z, dev_campos->z-CAMHEIGHT)) + isCameraAttached = true; + } + vel[index] += acc[index] * dt; pos[index].x += vel[index].x * dt; pos[index].y += vel[index].y * dt; pos[index].z += vel[index].z * dt; + + if (isCameraAttached) + { + dev_campos->z = curPos.z + CAMHEIGHT; + dev_campos->y = curPos.y - CAMFORWARD; + } } } @@ -431,15 +452,24 @@ void updateFCustom (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 // Update state using Verlet Integration // Written by Rohith Chandran. __global__ -void updateS_V (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +void updateS_V (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc, glm::vec4 * dev_campos, bool cameraUpdate) { int index = threadIdx.x + (blockIdx.x * blockDim.x); if( index < N ) { + bool isCameraAttached = false; glm::vec4 curPos = pos [index]; glm::vec3 curVel = vel [index]; glm::vec4 prevPos = curPos - (dt * glm::vec4 (curVel.x, curVel.y, curVel.z, 0)); + if (cameraUpdate) + { + if (isApproximately (curPos.x, dev_campos->x) && + isApproximately (curPos.y, dev_campos->y+CAMFORWARD) && + isApproximately (curPos.z, dev_campos->z-CAMHEIGHT)) + isCameraAttached = true; + } + curPos = (2.0*curPos) - prevPos + (dt * dt * glm::vec4 (acc [index].x, acc [index].y, acc [index].z, 0)); prevPos = (curPos - prevPos) / (2.0*dt); curVel.x = prevPos.x; @@ -448,19 +478,45 @@ void updateS_V (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * a vel[index] = curVel; pos[index] = curPos; + + if (isCameraAttached) + { + dev_campos->z = curPos.z + CAMHEIGHT; + dev_campos->y = curPos.y - CAMFORWARD; + } } } // Update state using Leapfrog Integration. // Written by Rohith Chandran. __global__ -void updateS_LF (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc) +void updateS_LF (int N, float dt, glm::vec4 * pos, glm::vec3 * vel, glm::vec3 * acc, glm::vec4 * dev_campos, bool cameraUpdate) { int index = threadIdx.x + (blockIdx.x * blockDim.x); if( index < N ) { - pos[index] += glm::vec4 ((vel [index] * dt), 0); + /*bool isCameraAttached = false;*/ + glm::vec4 curPos = pos[index]; + /*if (cameraUpdate) + { + if (isApproximately (curPos.x, dev_campos->x) && + isApproximately (curPos.y, dev_campos->y+CAMFORWARD) && + isApproximately (curPos.z, dev_campos->z-CAMHEIGHT)) + isCameraAttached = true; + }*/ + + curPos += glm::vec4 ((vel [index] * dt), 0); vel[index] += acc [index] * dt; + + if (/*isCameraAttached*/cameraUpdate) + { + if (index == attachedToIndex) + { + dev_campos->z = curPos.z + CAMHEIGHT; + dev_campos->y = curPos.y - CAMFORWARD; + } + } + pos [index] = curPos; } } @@ -481,8 +537,10 @@ __global__ void moveCamera (int N, glm::vec4* campos, glm::vec4* pos) if (glm::length (pos [i] - *campos) > 5.0) { *campos = pos [i]; - campos->z += 2.0f; -// campos->y -= 0.5f; + campos->z += CAMHEIGHT; + campos->y -= CAMFORWARD; + + attachedToIndex = i; break; } @@ -530,9 +588,9 @@ void cudaNBodyUpdateWrapper(float dt, bool customSimulation) updateF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); checkCUDAErrorWithLine("Kernel failed!"); -// updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); -// updateS_V<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); - updateS_LF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc); +// updateS<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc, dev_campos, camUpdate); +// updateS_V<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc, dev_campos, camUpdate); + updateS_LF<<>>(numObjects, dt, dev_pos, dev_vel, dev_acc, dev_campos, camUpdate); checkCUDAErrorWithLine("Kernel failed!"); cudaThreadSynchronize(); } @@ -565,10 +623,16 @@ glm::vec4 getCurrentCameraPosition () void setCurrentCameraPosition (const glm::vec4 &camera_position) { - cudaMemcpy (dev_campos, &camera_position, sizeof (camera_position), cudaMemcpyHostToDevice); + glm::vec4 cPos = camera_position * scene_scale; + cudaMemcpy (dev_campos, &cPos, sizeof (glm::vec4), cudaMemcpyHostToDevice); } void moveCameraToNextFlock (glm::vec3 &cameraPos) { moveCamera<<<1,1>>> (numObjects, dev_campos, dev_pos); } + +void setCameraUpdate (bool shouldCameraUpdate) +{ + camUpdate = shouldCameraUpdate; +} \ No newline at end of file diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index ba59fd4..26cedc5 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -24,6 +24,7 @@ void cudaUpdateVBO(float * vbodptr, int width, int height); void setDevicePrefetch (bool prefetchEnabled); void moveCameraToNextFlock (glm::vec3 &cameraPos); +void setCameraUpdate (bool shouldCameraUpdate); glm::vec4 getCurrentCameraPosition (); void setCurrentCameraPosition (const glm::vec4 &camera_position); diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index e14682b..cb9c848 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -160,6 +160,7 @@ void keyboard(unsigned char key, int x, int y) cameraToggle = !cameraToggle; if (!cameraToggle) { + setCameraUpdate (false); cameraPosition = glm::vec3 (originalCamPosition); setCurrentCameraPosition (glm::vec4 (cameraPosition, 1.0)); view = glm::lookAt(cameraPosition, glm::vec3 (0), glm::vec3(0,0,1)); @@ -167,6 +168,7 @@ void keyboard(unsigned char key, int x, int y) case 'N': if (cameraToggle) { + setCameraUpdate (true); moveCameraToNextFlock (cameraPosition); glm::vec4 temp_cp = getCurrentCameraPosition (); cameraPosition.x = temp_cp.x; cameraPosition.y = temp_cp.y; cameraPosition.z = temp_cp.z; diff --git a/screenshots/flock.png b/screenshots/flock.png new file mode 100644 index 0000000000000000000000000000000000000000..282dd55a1663a13cf973c3bc7f7b0f80e2915d42 GIT binary patch literal 107674 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 $*En|S9jLz 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 z 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⋘d;IM!4vzWitnMzLrkxE1CU3VrVptbb-zU3 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œM+Zp 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

{8NG!9%Rjpn@syf4ZX%VFJCzw_)40+ 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 Date: Wed, 23 Oct 2013 00:04:51 -0400 Subject: [PATCH 19/23] Submission commit --- Part1/src/kernel.cu | 42 ++++++++++++++++++++++++++++++++++++++---- Part1/src/kernel.h | 3 +++ Part1/src/main.cpp | 18 +++++++++++++++++- Part1/src/main.h | 1 + 4 files changed, 59 insertions(+), 5 deletions(-) diff --git a/Part1/src/kernel.cu b/Part1/src/kernel.cu index 4965154..65a562e 100644 --- a/Part1/src/kernel.cu +++ b/Part1/src/kernel.cu @@ -8,15 +8,15 @@ //GLOBALS dim3 threadsPerBlock(blockSize); -#define CAMHEIGHT 150.0f -#define CAMFORWARD 60.0f +#define CAMHEIGHT 75.0f +#define CAMFORWARD 30.0f int numObjects; const float planetMass = 3e8; const __device__ float starMass = 5e10; const __device__ float GravConst = 6.67384e-11; __device__ bool prefetch; -__device__ int attachedToIndex; +__device__ int attachedToIndex = 0; const float scene_scale = 2e2; //size of the height map in simulation space bool camUpdate = false; @@ -534,7 +534,15 @@ __global__ void moveCamera (int N, glm::vec4* campos, glm::vec4* pos) { for (int i = 0; i < N; i ++) { - if (glm::length (pos [i] - *campos) > 5.0) + if (i <= attachedToIndex) + { + /*if (attachedToIndex == N) + attachedToIndex = 0; + else*/ + continue; + } + + if (glm::length (pos [i] - pos [attachedToIndex]) > 5.0) { *campos = pos [i]; campos->z += CAMHEIGHT; @@ -547,6 +555,10 @@ __global__ void moveCamera (int N, glm::vec4* campos, glm::vec4* pos) } } +__global__ void attachedToIndexReset () +{ + attachedToIndex = 0; +} /************************************* * Wrappers for the __global__ calls * @@ -567,6 +579,8 @@ void initCuda(int N, const glm::vec4 &camera_position) cudaMalloc((void**)&dev_campos, sizeof(glm::vec4)); checkCUDAErrorWithLine("Kernel failed!"); + resetAttachedToIndex (); + checkCUDAErrorWithLine("Kernel failed!"); cudaMemcpy (dev_campos, &camera_position, sizeof (camera_position), cudaMemcpyHostToDevice); generateRandomPosArray<<>>(1, numObjects, dev_pos, scene_scale, planetMass); checkCUDAErrorWithLine("Kernel failed!"); @@ -621,6 +635,21 @@ glm::vec4 getCurrentCameraPosition () return camera_position/scene_scale; } +glm::vec3 getCurrentCameraLookAt () +{ + int attachedTo = 0; + cudaMemcpy (&attachedTo, &attachedToIndex, sizeof (int), cudaMemcpyDeviceToHost); + checkCUDAErrorWithLine("Kernel failed!"); + glm::vec3 accelerationDir = glm::vec3 (0); + glm::vec3 pos = glm::vec3 (0); + cudaMemcpy (&accelerationDir, &dev_acc [attachedTo], sizeof (glm::vec3), cudaMemcpyDeviceToHost); + checkCUDAErrorWithLine("Kernel failed!"); + cudaMemcpy (&pos, &dev_pos [attachedTo], sizeof (glm::vec3), cudaMemcpyDeviceToHost); + checkCUDAErrorWithLine("Kernel failed!"); + pos += accelerationDir * 5.0f; + return pos/scene_scale; +} + void setCurrentCameraPosition (const glm::vec4 &camera_position) { glm::vec4 cPos = camera_position * scene_scale; @@ -635,4 +664,9 @@ void moveCameraToNextFlock (glm::vec3 &cameraPos) void setCameraUpdate (bool shouldCameraUpdate) { camUpdate = shouldCameraUpdate; +} + +void resetAttachedToIndex () +{ + attachedToIndexReset<<<1,1>>> (); } \ No newline at end of file diff --git a/Part1/src/kernel.h b/Part1/src/kernel.h index 26cedc5..405552b 100644 --- a/Part1/src/kernel.h +++ b/Part1/src/kernel.h @@ -25,7 +25,10 @@ void setDevicePrefetch (bool prefetchEnabled); void moveCameraToNextFlock (glm::vec3 &cameraPos); void setCameraUpdate (bool shouldCameraUpdate); +void resetAttachedToIndex (); + glm::vec4 getCurrentCameraPosition (); +glm::vec3 getCurrentCameraLookAt (); void setCurrentCameraPosition (const glm::vec4 &camera_position); inline __device__ glm::vec3 safeNormalize (glm::vec3 vectorToBeNormalized); // normalize only if length > 0 diff --git a/Part1/src/main.cpp b/Part1/src/main.cpp index cb9c848..c2f5fea 100644 --- a/Part1/src/main.cpp +++ b/Part1/src/main.cpp @@ -108,6 +108,8 @@ void display() // VAO, shader program, and texture already bound //glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); //glDrawElements(GL_TRIANGLES, 6*field_width*field_height, GL_UNSIGNED_INT, 0); + if (cameraToggle) + updateCameraTransformation (); glUseProgram(program[HEIGHT_FIELD]); @@ -164,6 +166,7 @@ void keyboard(unsigned char key, int x, int y) cameraPosition = glm::vec3 (originalCamPosition); setCurrentCameraPosition (glm::vec4 (cameraPosition, 1.0)); view = glm::lookAt(cameraPosition, glm::vec3 (0), glm::vec3(0,0,1)); + resetAttachedToIndex (); } case 'N': if (cameraToggle) @@ -173,7 +176,7 @@ void keyboard(unsigned char key, int x, int y) glm::vec4 temp_cp = getCurrentCameraPosition (); cameraPosition.x = temp_cp.x; cameraPosition.y = temp_cp.y; cameraPosition.z = temp_cp.z; // cameraPosition = glm::vec3 (1.0, 1.0, 1.2); - view = glm::lookAt(cameraPosition, glm::vec3 (cameraPosition.x, cameraPosition.y +0.7f, cameraPosition.z-0.5f), + view = glm::lookAt(cameraPosition, getCurrentCameraLookAt (), glm::vec3(0,0,1)); } @@ -188,6 +191,19 @@ void keyboard(unsigned char key, int x, int y) } } +void updateCameraTransformation () +{ + glm::vec4 temp_cp = getCurrentCameraPosition (); + cameraPosition.x = temp_cp.x; cameraPosition.y = temp_cp.y; cameraPosition.z = temp_cp.z; + view = glm::lookAt(cameraPosition, /*glm::vec3 (cameraPosition.x, cameraPosition.y +0.7f, cameraPosition.z-0.5f)*/getCurrentCameraLookAt (), + glm::vec3(0,0,1)); + projection = perspMat * view; + glUseProgram(program[0]); + glUniformMatrix4fv (glGetUniformLocation(program[0], "u_projMatrix"), 1, GL_FALSE, &projection [0][0]); + glUseProgram(program[1]); + glUniformMatrix4fv (glGetUniformLocation(program[1], "u_projMatrix"), 1, GL_FALSE, &projection [0][0]); + glUniform3fv (glGetUniformLocation(program[1], "u_cameraPos"), 1, &cameraPosition [0]); +} //------------------------------- //----------SETUP STUFF---------- diff --git a/Part1/src/main.h b/Part1/src/main.h index 5b1fd25..2f84b5a 100644 --- a/Part1/src/main.h +++ b/Part1/src/main.h @@ -80,6 +80,7 @@ void runCuda(bool customSimulation); void display(); void keyboard(unsigned char key, int x, int y); +void updateCameraTransformation (); //------------------------------- //----------SETUP STUFF---------- From 639c3ccb8d8ad3137e86e705fae073c9b1bfd192 Mon Sep 17 00:00:00 2001 From: rohith10 Date: Wed, 23 Oct 2013 00:35:12 -0400 Subject: [PATCH 20/23] Update README.md --- README.md | 140 +++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 113 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 39a2bbf..443bd2b 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,11 @@ on performance without performing performance profiling using NSight, which is o Nevertheless, using this code, I was able to witness a HUGE speedup when using shared memory as opposed to global (53 fps vs. 243). +SCREENSHOTS +----------- +
+
+ DETAILS ------- In this project, the positions, velocities and accelerations of all objects are stored in global memory locations @@ -36,34 +41,115 @@ PERFORMANCE EVALUATION Performance of the program was compared for different number of planets/objects being simulated, using global memory, shared memory and prefetched version of shared memory. Here are the results:

-With visualization on:
-
-Memory type Number of objects Framerate Number of objects Framerate ------------ ----------------- --------- ----------------- --------- -Global 2500 1.75 5000
-Shared 2500 12 5000 6.77
-Shared (Prefetched) 2500 12 5000 6.77
-
-
-With visualization off:
-
-Memory type Number of objects Framerate (avg.) Number of objects Framerate ------------ ----------------- ---------------- ----------------- --------- -Global 1,500,000 53 3,000,000 53
-Shared 1,500,000 615 3,000,000 620
-Shared (Prefetched) 1,500,000 630 3,000,000 630
-
-Memory type Number of objects Framerate (avg.) Number of objects Framerate ------------ ----------------- ---------------- ----------------- --------- -Global 5,000,000 53 10,000,000 53
-Shared 5,000,000 630 10,000,000 615
-Shared (Prefetched) 5,000,000 630 10,000,000 615
+With visualization on: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Memory typeNumber of objectsFramerateNumber of objectsFramerate
Global25001.75
Shared2500 1250006.77
Shared (Prefetched)25001250006.77
+ +5000 objects were not simulated in global memory since the framerate was close to 0.
-Memory type Number of objects Framerate (avg.) Number of objects Framerate ------------ ----------------- ---------------- ----------------- --------- -Global 20,000,000 53 50,000,000 53
-Shared 20,000,000 620 50,000,000 620
-Shared (Prefetched) 20,000,000 615 50,000,000 630
+With visualization off: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Memory typeNumber of objectsFramerate (avg.)Number of objectsFramerate (avg.)
Global1,500,000533,000,00053
Shared1,500,0006153,000,000620
Shared (Prefetched)1,500,0006303,000,000630
Global5,000,0005310,000,00053
Shared5,000,00063010,000,000615
Shared (Prefetched)5,000,00063010,000,000615
Global20,000,0005350,000,00053
Shared20,000,00062050,000,000620
Shared (Prefetched)20,000,00061550,000,000630
These results show that shared memory is WAY better than global memory. As I mentioned above, if the bank conflicts resulting out of threads accessing multiple shared memory locations were to be corrected, the program would run much faster. From 88592841459581d962f0e4f38d5cfa8227e70d11 Mon Sep 17 00:00:00 2001 From: rohith10 Date: Wed, 23 Oct 2013 00:35:53 -0400 Subject: [PATCH 21/23] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 443bd2b..6687d18 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,9 @@ Nevertheless, using this code, I was able to witness a HUGE speedup when using s SCREENSHOTS ----------- +Flocking:

+Gravity Simulation:

DETAILS From dc3cffb62ba243f3fb36a69876d4c6ba041959e8 Mon Sep 17 00:00:00 2001 From: rohith10 Date: Wed, 23 Oct 2013 00:36:20 -0400 Subject: [PATCH 22/23] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 6687d18..e84f59d 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ With visualization on: -5000 objects were not simulated in global memory since the framerate was close to 0. +5000 objects were not simulated in global memory since the framerate was close to 0.

With visualization off: From 3448aacf2922b8fe939e0aa2003a10f81dd3a97a Mon Sep 17 00:00:00 2001 From: rohith10 Date: Thu, 24 Oct 2013 10:56:12 -0400 Subject: [PATCH 23/23] Update README.md Readme updated to describe how to run Part 2 (flocking) of the project. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e84f59d..6ec272a 100644 --- a/README.md +++ b/README.md @@ -35,7 +35,8 @@ iteration and then load that into shared during the current iteration) and two o Leapfrog (a Symplectic Euler integrator was provided by default). In addition to the above, I was also required to do my own simulation. I implemented dynamic flocking, where planets -dynamically drop in and out of flocks. Such flocks are created on the fly as planets move around. +dynamically drop in and out of flocks. Such flocks are created on the fly as planets move around. This dynamic flocking +runs when the command line parameter is set to 'true'. PERFORMANCE EVALUATION