From f170811e096ac2c58a504dd5774812e1ebe051ca Mon Sep 17 00:00:00 2001 From: Person Date: Sun, 15 Mar 2020 00:40:57 -0700 Subject: [PATCH 1/2] --Code changes -Remove the unused field m_RotCenterY from Ember. -Make a #define for fma() testing, but seems to make no difference. -Optimize some of the OpenCL iteration kernel generation code. -Possible fix to an OpenCL compilation bug when using blur curve on AMD on Mac. --- Builds/QtCreator/Fractorium/Fractorium.pro | 1 + Source/Ember/Ember.h | 5 - Source/Ember/Renderer.cpp | 16 +- Source/Ember/XmlToEmber.cpp | 2 - Source/EmberCL/EmberCLFunctions.h | 14 ++ Source/EmberCL/IterOpenCLKernelCreator.cpp | 181 +++++++++++++++------ Source/EmberCL/IterOpenCLKernelCreator.h | 1 + Source/EmberCL/RendererCL.cpp | 4 +- Source/Fractorium/FractoriumParams.cpp | 6 +- Source/Fractorium/GLWidget.cpp | 4 +- archive/build_linux.sh | 2 +- 11 files changed, 160 insertions(+), 76 deletions(-) diff --git a/Builds/QtCreator/Fractorium/Fractorium.pro b/Builds/QtCreator/Fractorium/Fractorium.pro index 08da4bd..63dec28 100644 --- a/Builds/QtCreator/Fractorium/Fractorium.pro +++ b/Builds/QtCreator/Fractorium/Fractorium.pro @@ -241,6 +241,7 @@ examples.path = $$SHARE_INSTALL_DIR/examples examples.files += \ $$ASSETS_DIR/examples/b33rheart_examples.flame \ $$ASSETS_DIR/examples/b33rheart_sierpinski.flame \ + $$ASSETS_DIR/examples/c-91_examples.flame \ $$ASSETS_DIR/examples/pillemaster_hexagonal_tilings.flame \ $$ASSETS_DIR/examples/plangkye_examples.flame \ $$ASSETS_DIR/examples/tatasz_examples.flame \ diff --git a/Source/Ember/Ember.h b/Source/Ember/Ember.h index 08ab7ac..8af5f08 100644 --- a/Source/Ember/Ember.h +++ b/Source/Ember/Ember.h @@ -126,7 +126,6 @@ public: m_CamMat = ember.m_CamMat; m_CenterX = T(ember.m_CenterX); m_CenterY = T(ember.m_CenterY); - m_RotCenterY = T(ember.m_RotCenterY); m_Rotate = T(ember.m_Rotate); m_Brightness = T(ember.m_Brightness); m_Gamma = T(ember.m_Gamma); @@ -783,7 +782,6 @@ public: InterpX::m_CamMat>(embers, coefs, size); InterpT<&Ember::m_CenterX>(embers, coefs, size); InterpT<&Ember::m_CenterY>(embers, coefs, size); - InterpT<&Ember::m_RotCenterY>(embers, coefs, size); InterpT<&Ember::m_Rotate>(embers, coefs, size); InterpT<&Ember::m_Brightness>(embers, coefs, size); InterpT<&Ember::m_Gamma>(embers, coefs, size); @@ -1405,7 +1403,6 @@ public: m_Palette.m_Index = -1; m_CenterX = 0; m_CenterY = 0; - m_RotCenterY = 0; m_Gamma = 4; m_Vibrancy = 1; m_Brightness = 4; @@ -1540,7 +1537,6 @@ public: << "Depth Blur: " << m_CamDepthBlur << "\n" << "CenterX: " << m_CenterX << "\n" << "CenterY: " << m_CenterY << "\n" - << "RotCenterY: " << m_RotCenterY << "\n" << "Rotate: " << m_Rotate << "\n" << "Brightness: " << m_Brightness << "\n" << "Gamma: " << m_Gamma << "\n" @@ -1681,7 +1677,6 @@ public: //Xml field: "center". T m_CenterX = 0; T m_CenterY = 0; - T m_RotCenterY = 0; //Rotate the camera by this many degrees. Since this is a camera rotation, the final output image will be rotated counter-clockwise. //Xml field: "rotate". diff --git a/Source/Ember/Renderer.cpp b/Source/Ember/Renderer.cpp index eeb9387..becc656 100644 --- a/Source/Ember/Renderer.cpp +++ b/Source/Ember/Renderer.cpp @@ -1526,10 +1526,10 @@ void Renderer::Accumulate(QTIsaac& rand, Poin { if (Rotate() != 0) { - T p00 = p.m_X - CenterX(); - T p11 = p.m_Y - m_Ember.m_RotCenterY; - p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + CenterX(); - p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_RotCenterY; + T p00 = p.m_X - m_Ember.m_CenterX; + T p11 = p.m_Y - m_Ember.m_CenterY; + p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + m_Ember.m_CenterX; + p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_CenterY; } //Checking this first before converting gives better performance than converting and checking a single value, which the original did. @@ -1599,10 +1599,10 @@ void Renderer::Accumulate(QTIsaac& rand, Poin { if (Rotate() != 0) { - T p00 = p.m_X - CenterX(); - T p11 = p.m_Y - m_Ember.m_RotCenterY; - p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + CenterX(); - p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_RotCenterY; + T p00 = p.m_X - m_Ember.m_CenterX; + T p11 = p.m_Y - m_Ember.m_CenterY; + p.m_X = (p00 * m_RotMat.A()) + (p11 * m_RotMat.B()) + m_Ember.m_CenterX; + p.m_Y = (p00 * m_RotMat.D()) + (p11 * m_RotMat.E()) + m_Ember.m_CenterY; } if (m_CarToRas.InBounds(p)) diff --git a/Source/Ember/XmlToEmber.cpp b/Source/Ember/XmlToEmber.cpp index eba3c40..02d4a6e 100644 --- a/Source/Ember/XmlToEmber.cpp +++ b/Source/Ember/XmlToEmber.cpp @@ -1379,7 +1379,6 @@ bool XmlToEmber::ParseEmberElementFromChaos(xmlNode* emberNode, Ember& cur istringstream istr(pos); istr >> currentEmber.m_CenterX >> currentEmber.m_CenterY; currentEmber.m_CenterY *= -1; - currentEmber.m_RotCenterY = currentEmber.m_CenterY; } else { @@ -1669,7 +1668,6 @@ bool XmlToEmber::ParseEmberElement(xmlNode* emberNode, Ember& currentEmber { istringstream is(attStr); is >> currentEmber.m_CenterX >> currentEmber.m_CenterY; - currentEmber.m_RotCenterY = currentEmber.m_CenterY; } else if (!Compare(curAtt->name, "filter_shape")) { diff --git a/Source/EmberCL/EmberCLFunctions.h b/Source/EmberCL/EmberCLFunctions.h index d3097a7..0cfa88d 100644 --- a/Source/EmberCL/EmberCLFunctions.h +++ b/Source/EmberCL/EmberCLFunctions.h @@ -3,6 +3,8 @@ #include "EmberCLPch.h" #include "EmberCLStructs.h" +#define USEFMA 1 + /// /// OpenCL global function strings. /// @@ -185,13 +187,21 @@ static const char* RandFunctionString = "inline real_t MwcNextFRange(uint2* s, real_t lower, real_t upper)\n" "{\n" " real_t f = (real_t)MwcNext(s) / (real_t)UINT_MAX;\n" +#ifdef USEFMA " return fma(f, upper - lower, lower);\n" +#else + " return (f * (upper - lower) + lower);\n" +#endif "}\n" "\n" "inline real_t MwcNextNeg1Pos1(uint2* s)\n" "{\n" " real_t f = (real_t)MwcNext(s) / (real_t)UINT_MAX;\n" +#ifdef USEFMA " return fma(f, (real_t)2.0, (real_t)-1.0);\n" +#else + " return (f * (real_t)2.0 + (real_t)-1.0);\n" +#endif "}\n" "\n" "inline real_t MwcNext0505(uint2* s)\n" @@ -218,7 +228,11 @@ static const char* AddToAccumWithCheckFunctionString = static const char* CarToRasFunctionString = "inline void CarToRasConvertPointToSingle(__constant CarToRasCL* carToRas, Point* point, uint* singleBufferIndex)\n" "{\n" +#ifdef USEFMA " *singleBufferIndex = (uint)fma(carToRas->m_PixPerImageUnitW, point->m_X, carToRas->m_RasLlX) + (carToRas->m_RasWidth * (uint)fma(carToRas->m_PixPerImageUnitH, point->m_Y, carToRas->m_RasLlY));\n" +#else + " *singleBufferIndex = (uint)(carToRas->m_PixPerImageUnitW * point->m_X + carToRas->m_RasLlX) + (carToRas->m_RasWidth * (uint)(carToRas->m_PixPerImageUnitH * point->m_Y + carToRas->m_RasLlY));\n" +#endif "}\n" "\n" "inline bool CarToRasInBounds(__constant CarToRasCL* carToRas, Point* point)\n" diff --git a/Source/EmberCL/IterOpenCLKernelCreator.cpp b/Source/EmberCL/IterOpenCLKernelCreator.cpp index 0693e52..5c238eb 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.cpp +++ b/Source/EmberCL/IterOpenCLKernelCreator.cpp @@ -172,7 +172,11 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, if (needPrecalcAtanYX) xformFuncs << "\treal_t precalcAtanyx;\n"; +#ifdef USEFMA xformFuncs << "\treal_t tempColor = outPoint->m_ColorX = fma(xform->m_OneMinusColorCache, inPoint->m_ColorX, xform->m_ColorSpeedCache);\n\n"; +#else + xformFuncs << "\treal_t tempColor = outPoint->m_ColorX = (xform->m_OneMinusColorCache * inPoint->m_ColorX + xform->m_ColorSpeedCache);\n\n"; +#endif if (optAffine && xform->m_Affine.IsID()) { @@ -182,9 +186,15 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, } else { +#ifdef USEFMA xformFuncs << " transX = fma(xform->m_A, inPoint->m_X, fma(xform->m_B, inPoint->m_Y, xform->m_C));\n" << " transY = fma(xform->m_D, inPoint->m_X, fma(xform->m_E, inPoint->m_Y, xform->m_F));\n"; +#else + xformFuncs << + " transX = xform->m_A * inPoint->m_X + (xform->m_B * inPoint->m_Y + xform->m_C);\n" << + " transY = xform->m_D * inPoint->m_X + (xform->m_E * inPoint->m_Y + xform->m_F);\n"; +#endif } xformFuncs << " transZ = inPoint->m_Z;\n"; @@ -289,11 +299,20 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, "\n\t//Apply post affine transform.\n" "\treal_t tempX = outPoint->m_X;\n" "\n" +#ifdef USEFMA "\toutPoint->m_X = fma(xform->m_PostA, tempX, fma(xform->m_PostB, outPoint->m_Y, xform->m_PostC));\n" << "\toutPoint->m_Y = fma(xform->m_PostD, tempX, fma(xform->m_PostE, outPoint->m_Y, xform->m_PostF));\n"; +#else + "\toutPoint->m_X = (xform->m_PostA * tempX + (xform->m_PostB * outPoint->m_Y + xform->m_PostC));\n" << + "\toutPoint->m_Y = (xform->m_PostD * tempX + (xform->m_PostE * outPoint->m_Y + xform->m_PostF));\n"; +#endif } +#ifdef USEFMA xformFuncs << "\toutPoint->m_ColorX = fma(xform->m_DirectColor, (outPoint->m_ColorX - tempColor), tempColor);\n"; +#else + xformFuncs << "\toutPoint->m_ColorX = (xform->m_DirectColor * (outPoint->m_ColorX - tempColor) + tempColor);\n"; +#endif xformFuncs << "\n"; xformFuncs << "\tif (isnan(outPoint->m_ColorX))\n"; xformFuncs << "\t outPoint->m_ColorX = 0.0; \n"; @@ -365,16 +384,16 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, " uint threadsMinus1 = NTHREADS - 1;\n" " VariationState varState;\n" "\n"; +#ifndef STRAIGHT_RAND if (ember.XformCount() > 1) { os << -#ifndef STRAIGHT_RAND " __local Point swap[NTHREADS];\n" " __local uint xfsel[NWARPS];\n"; -#endif } +#endif os << " iPaletteCoord.y = 0;\n" "\n" @@ -418,7 +437,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, os << "\n" " if (THREAD_ID_Y == 0 && THREAD_ID_X < NWARPS)\n" - " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ";\n"//It's faster to do the & here ahead of time than every time an xform is looked up to use inside the loop. + " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u;\n"//It's faster to do the & here ahead of time than every time an xform is looked up to use inside the loop. "\n"; #endif } @@ -429,7 +448,9 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, } os << +#ifndef STRAIGHT_RAND " barrier(CLK_LOCAL_MEM_FENCE);\n" +#endif "\n" " for (i = 0; i < itersToDo; i++)\n" " {\n" @@ -447,16 +468,16 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, { os << #ifdef STRAIGHT_RAND - " secondPoint.m_LastXfUsed = xformDistributions[(MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ") + (" << CHOOSE_XFORM_GRAIN << " * (firstPoint.m_LastXfUsed + 1u))];\n\n"; + " secondPoint.m_LastXfUsed = xformDistributions[(MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u) + (" << CHOOSE_XFORM_GRAIN << "u * (firstPoint.m_LastXfUsed + 1u))];\n\n"; #else - " secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y] + (" << CHOOSE_XFORM_GRAIN << " * (firstPoint.m_LastXfUsed + 1u))];\n\n";//Partial cuburn hybrid. + " secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y] + (" << CHOOSE_XFORM_GRAIN << "u * (firstPoint.m_LastXfUsed + 1u))];\n\n";//Partial cuburn hybrid. #endif } else { os << #ifdef STRAIGHT_RAND - " secondPoint.m_LastXfUsed = xformDistributions[MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "];\n\n";//For testing, using straight rand flam4/fractron style instead of cuburn. + " secondPoint.m_LastXfUsed = xformDistributions[MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u];\n\n";//For testing, using straight rand flam4/fractron style instead of cuburn. #else " secondPoint.m_LastXfUsed = xformDistributions[xfsel[THREAD_ID_Y]];\n\n"; #endif @@ -531,7 +552,7 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, "\n" //Populate randomized xform index buffer with new random values. " if (THREAD_ID_Y == 0 && THREAD_ID_X < NWARPS)\n" - " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << ";\n" + " xfsel[THREAD_ID_X] = MwcNext(&mwc) & " << CHOOSE_XFORM_GRAIN_M1 << "u;\n" "\n" " barrier(CLK_LOCAL_MEM_FENCE);\n" //Another thread will have written to this thread's location, so read the new value and use it for accumulation below. @@ -565,12 +586,14 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, " i = 0;\n" " fuse = false;\n" " itersToDo = iterCount;\n"; +#ifndef STRAIGHT_RAND if (ember.XformCount() > 1) os << " barrier(CLK_LOCAL_MEM_FENCE);\n"//Sort of seems necessary, sort of doesn't. Makes no speed difference. ; +#endif os << " }\n" ; @@ -616,19 +639,40 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, if (doAccum) { + if (optAffine && AnyZeroOpacity(ember)) + { + os << + " if (xforms[secondPoint.m_LastXfUsed].m_Opacity != (real_t)(0.0))\n"; + } + + os << + " {\n"; + + //Add this point to the appropriate location in the histogram. + if (optAffine && ember.m_Rotate == 0) + { + os << + " if (CarToRasInBounds(carToRas, &secondPoint))\n" + " {\n" + " CarToRasConvertPointToSingle(carToRas, &secondPoint, &histIndex);\n"; + } + else + { + os << + " p00 = secondPoint.m_X - ember->m_CenterX;\n" + " p01 = secondPoint.m_Y - ember->m_CenterY;\n" + " tempPoint.m_X = fma(p00, ember->m_RotA, fma(p01, ember->m_RotB, ember->m_CenterX));\n" + " tempPoint.m_Y = fma(p00, ember->m_RotD, fma(p01, ember->m_RotE, ember->m_CenterY));\n" + "\n" + " if (CarToRasInBounds(carToRas, &tempPoint))\n" + " {\n" + " CarToRasConvertPointToSingle(carToRas, &tempPoint, &histIndex);\n"; + } + os << - " p00 = secondPoint.m_X - ember->m_CenterX;\n" - " p01 = secondPoint.m_Y - ember->m_CenterY;\n" - " tempPoint.m_X = fma(p00, ember->m_RotA, fma(p01, ember->m_RotB, ember->m_CenterX));\n" - " tempPoint.m_Y = fma(p00, ember->m_RotD, fma(p01, ember->m_RotE, ember->m_CenterY));\n" "\n" - //Add this point to the appropriate location in the histogram. - " if (CarToRasInBounds(carToRas, &tempPoint))\n" - " {\n" - " CarToRasConvertPointToSingle(carToRas, &tempPoint, &histIndex);\n" - "\n" - " if (histIndex < histSize)\n"//Provides an extra level of safety and makes no speed difference. - " {\n"; + " if (histIndex < histSize)\n"//Provides an extra level of safety and makes no speed difference. + " {\n"; //Basic texture index interoplation does not produce identical results //to the CPU. So the code here must explicitly do the same thing and not @@ -636,57 +680,62 @@ string IterOpenCLKernelCreator::CreateIterKernelString(const Ember& ember, if (ember.m_PaletteMode == ePaletteMode::PALETTE_LINEAR) { os << - " real_t colorIndexFrac;\n" - " real_t colorIndex = secondPoint.m_ColorX * ember->m_Psm1;\n" - " int intColorIndex;\n" - " float4 palColor2;\n" + " real_t colorIndexFrac;\n" + " real_t colorIndex = secondPoint.m_ColorX * ember->m_Psm1;\n" + " int intColorIndex;\n" + " float4 palColor2;\n" "\n" - " if (colorIndex < 0)\n" - " {\n" - " intColorIndex = 0;\n" - " colorIndexFrac = 0;\n" - " }\n" - " else if (colorIndex >= ember->m_Psm1)\n" - " {\n" - " intColorIndex = (int)ember->m_Psm2;\n" - " colorIndexFrac = 1.0;\n" - " }\n" - " else\n" - " {\n" - " intColorIndex = (int)colorIndex;\n" - " colorIndexFrac = colorIndex - intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1. - " }\n" + " if (colorIndex < 0)\n" + " {\n" + " intColorIndex = 0;\n" + " colorIndexFrac = 0;\n" + " }\n" + " else if (colorIndex >= ember->m_Psm1)\n" + " {\n" + " intColorIndex = (int)ember->m_Psm2;\n" + " colorIndexFrac = 1.0;\n" + " }\n" + " else\n" + " {\n" + " intColorIndex = (int)colorIndex;\n" + " colorIndexFrac = colorIndex - intColorIndex;\n"//Interpolate between intColorIndex and intColorIndex + 1. + " }\n" "\n" - " iPaletteCoord.x = intColorIndex;\n"//Palette operations are strictly float because OpenCL does not support dp64 textures. - " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n" - " iPaletteCoord.x += 1;\n" - " palColor2 = read_imagef(palette, paletteSampler, iPaletteCoord);\n" - " palColor1 = fma(palColor2, (float)colorIndexFrac, palColor1 * (1.0f - (float)colorIndexFrac));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile. + " iPaletteCoord.x = intColorIndex;\n"//Palette operations are strictly float because OpenCL does not support dp64 textures. + " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n" + " iPaletteCoord.x += 1;\n" + " palColor2 = read_imagef(palette, paletteSampler, iPaletteCoord);\n" +#ifdef USEFMA + " palColor1 = fma(palColor2, (float)colorIndexFrac, palColor1 * (1.0f - (float)colorIndexFrac));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile. +#else + " palColor1 = (palColor2 * (float)colorIndexFrac + (palColor1 * (1.0f - (float)colorIndexFrac)));\n";//The 1.0f here *must* have the 'f' suffix at the end to compile. +#endif } else if (ember.m_PaletteMode == ePaletteMode::PALETTE_STEP) { os << - " iPaletteCoord.x = (int)(secondPoint.m_ColorX * ember->m_Psm1);\n" - " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"; + " iPaletteCoord.x = (int)(secondPoint.m_ColorX * ember->m_Psm1);\n" + " palColor1 = read_imagef(palette, paletteSampler, iPaletteCoord);\n"; } if (lockAccum) { os << - " AtomicAdd(&(histogram[histIndex].m_Reals[0]), palColor1.x * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"//Always apply opacity, even though it's usually 1. - " AtomicAdd(&(histogram[histIndex].m_Reals[1]), palColor1.y * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n" - " AtomicAdd(&(histogram[histIndex].m_Reals[2]), palColor1.z * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n" - " AtomicAdd(&(histogram[histIndex].m_Reals[3]), palColor1.w * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"; + " AtomicAdd(&(histogram[histIndex].m_Reals[0]), palColor1.x * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"//Always apply opacity, even though it's usually 1. + " AtomicAdd(&(histogram[histIndex].m_Reals[1]), palColor1.y * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n" + " AtomicAdd(&(histogram[histIndex].m_Reals[2]), palColor1.z * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n" + " AtomicAdd(&(histogram[histIndex].m_Reals[3]), palColor1.w * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n"; } else { os << - " histogram[histIndex].m_Real4 += (palColor1 * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";//real_bucket_t should always be float. + " histogram[histIndex].m_Real4 += (palColor1 * (real_bucket_t)xforms[secondPoint.m_LastXfUsed].m_Opacity);\n";//real_bucket_t should always be float. } os << - " }\n"//histIndex < histSize. - " }\n"//CarToRasInBounds. + " }\n"//histIndex < histSize. + " }\n"//CarToRasInBounds. + " }\n"//Opacity != 0. "\n"; os << " barrier(CLK_GLOBAL_MEM_FENCE);\n";//Barrier every time, whether or not the point was in bounds, else artifacts will occur when doing strips. @@ -973,6 +1022,24 @@ string IterOpenCLKernelCreator::VariationStateInitString(const Ember& embe return os.str(); } + +/// +/// Determine whether the passed in ember has at least one xform with an opacity of 0. +/// +/// The first ember to compare +/// True if at least one xform had an opacity of 0, else false +template +bool IterOpenCLKernelCreator::AnyZeroOpacity(const Ember& ember) +{ + size_t i = 0; + + while (auto xform = ember.GetXform(i++)) + if (xform->m_Opacity == 0) + return true; + + return false; +} + /// /// Determine whether the two embers passed in differ enough /// to require a rebuild of the iteration code. @@ -1017,6 +1084,14 @@ bool IterOpenCLKernelCreator::IsBuildRequired(const Ember& ember1, const E if (ember1.ProjBits() != ember2.ProjBits()) return true; + if (optAffine && + ((ember1.m_Rotate == 0) ^ (ember2.m_Rotate == 0))) + return true; + + if (optAffine && + (AnyZeroOpacity(ember1) != AnyZeroOpacity(ember2))) + return true; + for (i = 0; i < xformCount; i++) { auto xform1 = ember1.GetTotalXform(i); @@ -1124,7 +1199,7 @@ string IterOpenCLKernelCreator::CreateProjectionString(const Ember& ember) " real_t prcx = (x - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n" " real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n" " real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n" - " real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n" + " real_t scale = ember->m_BlurCurve != (real_t)(0.0) ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n" " real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n" "\n" " dsin = sin(t);\n" @@ -1152,7 +1227,7 @@ string IterOpenCLKernelCreator::CreateProjectionString(const Ember& ember) " real_t prcx = (secondPoint.m_X - carToRas->m_CarCenterX) / carToRas->m_CarHalfX;\n" " real_t prcy = (y - carToRas->m_CarCenterY) / carToRas->m_CarHalfY;\n" " real_t dist = sqrt(SQR(prcx) + SQR(prcy)) * (real_t)(10.0);\n" - " real_t scale = ember->m_BlurCurve ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n" + " real_t scale = ember->m_BlurCurve != (real_t)(0.0) ? min((real_t)(1.0), (dist * dist) / (4 * ember->m_BlurCurve)) : (real_t)(1.0);\n" " real_t dr = MwcNext01(&mwc) * (ember->m_BlurCoef * scale) * z;\n" "\n" " secondPoint.m_X = fma(dr, dcos, secondPoint.m_X) / zr;\n" diff --git a/Source/EmberCL/IterOpenCLKernelCreator.h b/Source/EmberCL/IterOpenCLKernelCreator.h index 6fdb4eb..e0f4026 100644 --- a/Source/EmberCL/IterOpenCLKernelCreator.h +++ b/Source/EmberCL/IterOpenCLKernelCreator.h @@ -36,6 +36,7 @@ public: static void SharedDataIndexDefines(const Ember& ember, pair>& params, bool doVals = true, bool doString = true); static string VariationStateString(const Ember& ember); static string VariationStateInitString(const Ember& ember); + static bool AnyZeroOpacity(const Ember& ember); static bool IsBuildRequired(const Ember& ember1, const Ember& ember2, bool optAffine); private: diff --git a/Source/EmberCL/RendererCL.cpp b/Source/EmberCL/RendererCL.cpp index 16f194a..a95fa63 100644 --- a/Source/EmberCL/RendererCL.cpp +++ b/Source/EmberCL/RendererCL.cpp @@ -1836,8 +1836,8 @@ void RendererCL::ConvertEmber(Ember& ember, EmberCL& emberCL, emberCL.m_CamDepthBlur = ember.m_CamDepthBlur; emberCL.m_BlurCoef = ember.BlurCoef(); emberCL.m_CamMat = ember.m_CamMat; - emberCL.m_CenterX = CenterX(); - emberCL.m_CenterY = ember.m_RotCenterY; + emberCL.m_CenterX = ember.m_CenterX; + emberCL.m_CenterY = ember.m_CenterY; emberCL.m_RotA = m_RotMat.A(); emberCL.m_RotB = m_RotMat.B(); emberCL.m_RotD = m_RotMat.D(); diff --git a/Source/Fractorium/FractoriumParams.cpp b/Source/Fractorium/FractoriumParams.cpp index fe538e0..e70b687 100644 --- a/Source/Fractorium/FractoriumParams.cpp +++ b/Source/Fractorium/FractoriumParams.cpp @@ -369,7 +369,7 @@ template void FractoriumEmberController::CenterYChanged(double d { UpdateAll([&](Ember& ember, bool isMain) { - ember.m_CenterY = ember.m_RotCenterY = d; + ember.m_CenterY = d; }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); } void Fractorium::OnCenterYChanged(double d) { m_Controller->CenterYChanged(d); } @@ -772,7 +772,7 @@ void FractoriumEmberController::SetCenter(double x, double y) UpdateAll([&](Ember& ember, bool isMain) { ember.m_CenterX = x; - ember.m_CenterY = ember.m_RotCenterY = y; + ember.m_CenterY = y; }, true, eProcessAction::FULL_RENDER, m_Fractorium->ApplyAll()); m_Fractorium->m_CenterXSpin->SetValueStealth(x);//Don't trigger a redraw twice. m_Fractorium->m_CenterYSpin->SetValueStealth(y); @@ -873,7 +873,7 @@ void FractoriumEmberController::ParamsToEmberPrivate(Ember& ember, bool im ember.m_FinalRasW = m_Fractorium->m_WidthSpin->value();//Geometry. ember.m_FinalRasH = m_Fractorium->m_HeightSpin->value(); ember.m_CenterX = m_Fractorium->m_CenterXSpin->value(); - ember.m_CenterY = ember.m_RotCenterY = m_Fractorium->m_CenterYSpin->value(); + ember.m_CenterY = m_Fractorium->m_CenterYSpin->value(); ember.m_PixelsPerUnit = m_Fractorium->m_ScaleSpin->value(); ember.m_Zoom = m_Fractorium->m_ZoomSpin->value(); ember.m_Rotate = m_Fractorium->m_RotateSpin->value(); diff --git a/Source/Fractorium/GLWidget.cpp b/Source/Fractorium/GLWidget.cpp index af29a35..889893b 100644 --- a/Source/Fractorium/GLWidget.cpp +++ b/Source/Fractorium/GLWidget.cpp @@ -891,7 +891,7 @@ void GLEmberController::MousePress(QMouseEvent* e) m_DragState = eDragState::DragNone; } } - else if (e->button() == Qt::MiddleButton || (e->button() == Qt::RightButton && e->modifiers() & Qt::ShiftModifier))//Middle button or right button with shift key, do whole image translation. + else if (e->button() == Qt::MiddleButton || (e->button() == Qt::RightButton && e->modifiers() & Qt::ShiftModifier))//Middle button or right button with shift key, do whole image translation. { m_CenterDownX = ember->m_CenterX;//Capture where the center of the image is because this value will change when panning. m_CenterDownY = ember->m_CenterY; @@ -1043,7 +1043,7 @@ void GLEmberController::MouseMove(QMouseEvent* e) v2T v1(x, y); v2T v2 = rotMat.TransformVector(v1); ember->m_CenterX = v2.x; - ember->m_CenterY = ember->m_RotCenterY = v2.y; + ember->m_CenterY = v2.y; m_FractoriumEmberController->SetCenter(ember->m_CenterX, ember->m_CenterY);//Will restart the rendering process. } else if (m_DragState == eDragState::DragRotateScale)//Rotating and scaling the whole image. diff --git a/archive/build_linux.sh b/archive/build_linux.sh index 71b3818..bcb09af 100755 --- a/archive/build_linux.sh +++ b/archive/build_linux.sh @@ -185,7 +185,7 @@ mv rpmbuild/RPMS/x86_64/* ./ emberVersion=$(grep '#define EMBER_VERSION' ../Source/Ember/EmberDefines.h | sed 's/^.*EMBER_VERSION "\([^"]\+\)".*/\1/') -mv Fractorium.deb Fractorium-$emberVersion-.x86_64.deb +mv Fractorium.deb Fractorium-$emberVersion.x86_64.deb mv Fractorium-$emberVersion-1.x86_64.rpm Fractorium-$emberVersion.x86_64.rpm echo "" From fdafb64b6713476f6b7bf7e5284aedd9f32a4802 Mon Sep 17 00:00:00 2001 From: Person Date: Sun, 15 Mar 2020 00:48:50 -0700 Subject: [PATCH 2/2] --Bug fixes -Fix Wix. --- Builds/MSVC/Installer/Product.wxs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Builds/MSVC/Installer/Product.wxs b/Builds/MSVC/Installer/Product.wxs index c0950c6..524b061 100644 --- a/Builds/MSVC/Installer/Product.wxs +++ b/Builds/MSVC/Installer/Product.wxs @@ -371,8 +371,8 @@ - - + +