CpuGeneratorsAVX.cpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. #include "CpuGenerators.h"
  2. #include <immintrin.h>
  3. #include <omp.h>
  4. #include <cmath>
  5. #include <utility>
  6. #include <memory>
  7. using mnd::CpuGenerator;
  8. namespace mnd
  9. {
  10. template class CpuGenerator<float, mnd::X86_AVX, false>;
  11. template class CpuGenerator<float, mnd::X86_AVX, true>;
  12. template class CpuGenerator<double, mnd::X86_AVX, false>;
  13. template class CpuGenerator<double, mnd::X86_AVX, true>;
  14. }
  15. template<bool parallel>
  16. void CpuGenerator<float, mnd::X86_AVX, parallel>::generate(const mnd::MandelInfo& info, float* data)
  17. {
  18. using T = float;
  19. const MandelViewport& view = info.view;
  20. if constexpr(parallel)
  21. omp_set_num_threads(2 * omp_get_num_procs());
  22. #pragma omp parallel for schedule(static, 1) if (parallel)
  23. for (long j = 0; j < info.bHeight; j++) {
  24. T y = T(view.y) + T(j) * T(view.height / info.bHeight);
  25. __m256 ys = {y, y, y, y, y, y, y, y};
  26. long i = 0;
  27. for (i; i < info.bWidth; i += 8) {
  28. __m256 xs = {
  29. float(view.x + double(i) * view.width / info.bWidth),
  30. float(view.x + double(i + 1) * view.width / info.bWidth),
  31. float(view.x + double(i + 2) * view.width / info.bWidth),
  32. float(view.x + double(i + 3) * view.width / info.bWidth),
  33. float(view.x + double(i + 4) * view.width / info.bWidth),
  34. float(view.x + double(i + 5) * view.width / info.bWidth),
  35. float(view.x + double(i + 6) * view.width / info.bWidth),
  36. float(view.x + double(i + 7) * view.width / info.bWidth)
  37. };
  38. __m256 counter = {0, 0, 0, 0, 0, 0, 0, 0};
  39. __m256 adder = {1, 1, 1, 1, 1, 1, 1, 1};
  40. __m256 resultsa = {0, 0, 0, 0, 0, 0, 0, 0};
  41. __m256 resultsb = {0, 0, 0, 0, 0, 0, 0, 0};
  42. __m256 threshold = {16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f, 16.0f};
  43. __m256 a = xs;
  44. __m256 b = ys;
  45. for (int k = 0; k < info.maxIter; k++) {
  46. __m256 aa = _mm256_mul_ps(a, a);
  47. __m256 bb = _mm256_mul_ps(b, b);
  48. __m256 abab = _mm256_mul_ps(a, b); abab = _mm256_add_ps(abab, abab);
  49. a = _mm256_add_ps(_mm256_sub_ps(aa, bb), xs);
  50. b = _mm256_add_ps(abab, ys);
  51. __m256 cmp = _mm256_cmp_ps(_mm256_add_ps(aa, bb), threshold, _CMP_LE_OQ);
  52. if (info.smooth) {
  53. resultsa = _mm256_or_ps(_mm256_andnot_ps(cmp, resultsa), _mm256_and_ps(cmp, a));
  54. resultsb = _mm256_or_ps(_mm256_andnot_ps(cmp, resultsb), _mm256_and_ps(cmp, b));
  55. }
  56. adder = _mm256_and_ps(adder, cmp);
  57. counter = _mm256_add_ps(counter, adder);
  58. if ((k & 0x7) == 0 && _mm256_testz_ps(cmp, cmp) != 0) {
  59. break;
  60. }
  61. }
  62. auto alignVec = [](float* data) -> float* {
  63. void* aligned = data;
  64. ::size_t length = 64;
  65. std::align(32, 8 * sizeof(float), aligned, length);
  66. return static_cast<float*>(aligned);
  67. };
  68. float resData[16];
  69. float* ftRes = alignVec(resData);
  70. float* resa = (float*) &resultsa;
  71. float* resb = (float*) &resultsb;
  72. _mm256_store_ps(ftRes, counter);
  73. for (int k = 0; k < 8 && i + k < info.bWidth; k++) {
  74. if (info.smooth) {
  75. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter :
  76. ftRes[k] >= info.maxIter ? info.maxIter :
  77. ((float)ftRes[k]) + 1 - ::log(::log(resa[k] * resa[k] + resb[k] * resb[k]) / 2) / ::log(2.0f);
  78. }
  79. else {
  80. data[i + k + j * info.bWidth] = ftRes[k] <= 0 ? info.maxIter : ftRes[k];
  81. }
  82. }
  83. }
  84. }
  85. }
  86. template<bool parallel>
  87. void CpuGenerator<double, mnd::X86_AVX, parallel>::generate(const mnd::MandelInfo& info, float* data)
  88. {
  89. using T = double;
  90. const MandelViewport& view = info.view;
  91. if constexpr(parallel)
  92. omp_set_num_threads(2 * omp_get_num_procs());
  93. #pragma omp parallel for schedule(static, 1) if (parallel)
  94. for (long j = 0; j < info.bHeight; j++) {
  95. T y = T(view.y + T(j) * view.height / info.bHeight);
  96. __m256d ys = { y, y, y, y };
  97. long i = 0;
  98. for (i; i < info.bWidth; i += 4) {
  99. __m256d xs = {
  100. double(view.x + double(i) * view.width / info.bWidth),
  101. double(view.x + double(i + 1) * view.width / info.bWidth),
  102. double(view.x + double(i + 2) * view.width / info.bWidth),
  103. double(view.x + double(i + 3) * view.width / info.bWidth)
  104. };
  105. int itRes[4] = { 0, 0, 0, 0 };
  106. __m256d threshold = { 16.0, 16.0, 16.0, 16.0 };
  107. __m256d counter = { 0, 0, 0, 0 };
  108. __m256d adder = { 1, 1, 1, 1 };
  109. __m256d a = xs;
  110. __m256d b = ys;
  111. for (int k = 0; k < info.maxIter; k++) {
  112. __m256d aa = _mm256_mul_pd(a, a);
  113. __m256d bb = _mm256_mul_pd(b, b);
  114. __m256d abab = _mm256_mul_pd(a, b); abab = _mm256_add_pd(abab, abab);
  115. a = _mm256_add_pd(_mm256_sub_pd(aa, bb), xs);
  116. b = _mm256_add_pd(abab, ys);
  117. __m256i cmp = _mm256_castpd_si256(_mm256_cmp_pd(_mm256_add_pd(aa, bb), threshold, _CMP_LE_OQ));
  118. /*if (info.smooth) {
  119. resultsa = _mm256_or_pd(_mm256_andnot_ps(cmp, resultsa), _mm256_and_ps(cmp, a));
  120. resultsb = _mm256_or_ps(_mm256_andnot_ps(cmp, resultsb), _mm256_and_ps(cmp, b));
  121. }*/
  122. adder = _mm256_and_pd(adder, _mm256_castsi256_pd(cmp));
  123. counter = _mm256_add_pd(counter, adder);
  124. if ((k & 0x7) == 0 && _mm256_testz_si256(cmp, cmp) != 0) {
  125. break;
  126. }
  127. }
  128. auto alignVec = [](double* data) -> double* {
  129. void* aligned = data;
  130. ::size_t length = 64;
  131. std::align(32, 4 * sizeof(double), aligned, length);
  132. return static_cast<double*>(aligned);
  133. };
  134. double resData[8];
  135. double* ftRes = alignVec(resData);
  136. _mm256_store_pd(ftRes, counter);
  137. for (int k = 0; k < 4 && i + k < info.bWidth; k++)
  138. data[i + k + j * info.bWidth] = ftRes[k] > 0 ? float(ftRes[k]) : info.maxIter;
  139. }
  140. }
  141. }