Skip to content

Commit

Permalink
Convert new style Pinwheel to use Metal for rendering
Browse files Browse the repository at this point in the history
  • Loading branch information
dkulp committed Dec 28, 2023
1 parent 32b15d9 commit 44b4ad6
Show file tree
Hide file tree
Showing 9 changed files with 453 additions and 162 deletions.
2 changes: 1 addition & 1 deletion macOS
8 changes: 8 additions & 0 deletions xLights/RenderBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,14 @@ class /*NCCDLLEXPORT*/ RenderBuffer {
void SetPixel(int x, int y, const xlColor &color, bool wrap = false, bool useAlpha = false, bool dmx_ignore = false);
void SetPixel(int x, int y, const HSVValue& hsv, bool wrap = false);

//optimized/direct versions only usable in cases where x/y are known to be within bounds
void SetPixelDirect(int x, int y, const xlColor &color) {
pixels[y * BufferWi + x] = color;
}
const xlColor& GetPixelDirect(int x, int y) const {
return pixels[y * BufferWi + x];
}

int GetNodeCount() const { return Nodes.size();}
void SetNodePixel(int nodeNum, const xlColor &color, bool dmx_ignore = false);
void CopyNodeColorsToPixels(std::vector<uint8_t> &done);
Expand Down
339 changes: 180 additions & 159 deletions xLights/effects/PinwheelEffect.cpp

Large diffs are not rendered by default.

31 changes: 30 additions & 1 deletion xLights/effects/PinwheelEffect.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,38 @@ class PinwheelEffect : public RenderableEffect
PW_3D_Inverted,
PW_SWEEP
};

class PinwheelData {
public:
PinwheelData(int i) : pinwheel_arms(i), colorarray(i), colorIsSpacial(i), colorsAsHSV(i), colorsAsColor(i) {

}
std::vector<size_t> colorarray;
std::vector<bool> colorIsSpacial;
std::vector<HSVValue> colorsAsHSV;
std::vector<xlColor> colorsAsColor;

bool hasSpacial = false;
int pinwheel_arms;
Pinwheel3DType pw3dType;
int xc_adj = 0;
int yc_adj = 0;
float tmax;
int degrees_per_arm;
bool pinwheel_rotation;
int pinwheel_twist;
int max_radius;
int poffset;
float pos;
};

virtual xlEffectPanel* CreatePanel(wxWindow* parent) override;
virtual void Draw_arm(RenderBuffer& buffer, int base_degrees, int max_radius, int pinwheel_twist, int xc_adj, int yc_adj, int colorIdx, Pinwheel3DType pinwheel_3d, float round);

void RenderNewMethod(Effect* effect, const SettingsMap& settings, RenderBuffer& buffer);
virtual void RenderNewArms(RenderBuffer& buffer, PinwheelData &data);
void RenderOldMethod(Effect* effect, const SettingsMap& settings, RenderBuffer& buffer);

void Draw_arm(RenderBuffer& buffer, int base_degrees, int max_radius, int pinwheel_twist, int xc_adj, int yc_adj, int colorIdx, Pinwheel3DType pinwheel_3d, float round);

Pinwheel3DType to3dType(const std::string& pinwheel_3d);
void adjustColor(Pinwheel3DType pw3dType, xlColor& color, HSVValue& hsv, bool allowAlpha, float round);
Expand Down
23 changes: 23 additions & 0 deletions xLights/effects/metal/MetalEffectDataTypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,26 @@ struct RotoZoomData {
int32_t pivotpointx;
int32_t pivotpointy;
};

struct MetalPinwheelData {
uint32_t width;
uint32_t height;

int32_t pinwheel_arms;
int32_t xc_adj = 0;
int32_t yc_adj = 0;
int32_t degrees_per_arm;
int32_t pinwheel_twist;
int32_t max_radius;
int32_t poffset;
int32_t pw3dType;
int32_t pinwheel_rotation;

float tmax;
float pos;

int32_t allowAlpha;
simd::uchar4 colorsAsColor[8];
simd::float3 colorsAsHSV[8];
uint16_t numColors;
};
2 changes: 2 additions & 0 deletions xLights/effects/metal/MetalEffectManager.mm
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ virtual void setPrioritizeGraphics(bool p) override {
return new MetalPlasmaEffect(eff);
case EffectManager::eff_WARP:
return new MetalWarpEffect(eff);
case EffectManager::eff_PINWHEEL:
return new MetalPinwheelEffect(eff);
default:
return nullptr;
}
Expand Down
14 changes: 13 additions & 1 deletion xLights/effects/metal/MetalEffects.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
#include "../ButterflyEffect.h"
#include "../PlasmaEffect.h"
#include "../WarpEffect.h"

#include "../PinwheelEffect.h"

class MetalButterflyEffectData;

Expand Down Expand Up @@ -51,3 +51,15 @@ class MetalPlasmaEffect : public PlasmaEffect {
private:
MetalPlasmaEffectData *data;
};

class MetalPinwheelEffectData;

class MetalPinwheelEffect : public PinwheelEffect {
public:
MetalPinwheelEffect(int i);
virtual ~MetalPinwheelEffect();

virtual void RenderNewArms(RenderBuffer& buffer, PinwheelEffect::PinwheelData &data) override;
private:
MetalPinwheelEffectData *data;
};
118 changes: 118 additions & 0 deletions xLights/effects/metal/MetalPinwheelEffect.mm
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@

#include "MetalComputeUtilities.hpp"
#include "MetalEffects.hpp"
#include "MetalEffectDataTypes.h"

#include "../../RenderBuffer.h"

#include <array>

class MetalPinwheelEffectData {
public:
MetalPinwheelEffectData() {
for (auto &f : functions) {
f = nil;
}
functions[0] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
//functions[1] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
//functions[2] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
//functions[3] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
//functions[4] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
//functions[5] = MetalComputeUtilities::INSTANCE.FindComputeFunction("PinwheelEffectStyle0");
}
~MetalPinwheelEffectData() {
for (auto &f : functions) {
if (f != nil) {
[f release];
}
}
}
bool canRenderStyle(int style) {
return style < functions.size() && functions[style] != nil;
}

bool Render(int idx, MetalPinwheelData &data, RenderBuffer &buffer) {
@autoreleasepool {
MetalRenderBufferComputeData * rbcd = MetalRenderBufferComputeData::getMetalRenderBufferComputeData(&buffer);

id<MTLCommandBuffer> commandBuffer = rbcd->getCommandBuffer();
if (commandBuffer == nil) {
return false;
}

id<MTLBuffer> bufferResult = rbcd->getPixelBuffer();
if (bufferResult == nil) {
rbcd->abortCommandBuffer();
return false;
}
id<MTLComputeCommandEncoder> computeEncoder = [commandBuffer computeCommandEncoder];
if (computeEncoder == nil) {
rbcd->abortCommandBuffer();
return false;
}
[computeEncoder setLabel:@"PinwheelEffect"];
[computeEncoder setComputePipelineState:functions[idx]];

NSInteger dataSize = sizeof(data);
[computeEncoder setBytes:&data length:dataSize atIndex:0];
[computeEncoder setBuffer:bufferResult offset:0 atIndex:1];

NSInteger maxThreads = functions[idx].maxTotalThreadsPerThreadgroup;
dataSize = data.width * data.height;
NSInteger threads = std::min(dataSize, maxThreads);
MTLSize gridSize = MTLSizeMake(dataSize, 1, 1);
MTLSize threadsPerThreadgroup = MTLSizeMake(threads, 1, 1);

[computeEncoder dispatchThreads:gridSize
threadsPerThreadgroup:threadsPerThreadgroup];

[computeEncoder endEncoding];
}
return true;
}
std::array<id<MTLComputePipelineState>, 11> functions;
};

MetalPinwheelEffect::MetalPinwheelEffect(int i) : PinwheelEffect(i) {
data = new MetalPinwheelEffectData();
}
MetalPinwheelEffect::~MetalPinwheelEffect() {
if (data) {
delete data;
}
}

void MetalPinwheelEffect::RenderNewArms(RenderBuffer& buffer, PinwheelEffect::PinwheelData &data) {

MetalRenderBufferComputeData * rbcd = MetalRenderBufferComputeData::getMetalRenderBufferComputeData(&buffer);
if (rbcd == nullptr || ((buffer.BufferWi * buffer.BufferHt) < 1024) || data.hasSpacial) {
PinwheelEffect::RenderNewArms(buffer, data);
return;
}

MetalPinwheelData rdata;
rdata.width = buffer.BufferWi;
rdata.height = buffer.BufferHt;
rdata.pinwheel_arms = data.pinwheel_arms;
rdata.xc_adj = data.xc_adj;
rdata.yc_adj = data.yc_adj;
rdata.degrees_per_arm = data.degrees_per_arm;
rdata.pinwheel_twist = data.pinwheel_twist;
rdata.max_radius= data.max_radius;
rdata.poffset = data.poffset;
rdata.pw3dType = data.pw3dType;
rdata.pinwheel_rotation = data.pinwheel_rotation;
rdata.tmax = data.tmax;
rdata.pos = data.pos;
rdata.allowAlpha = buffer.allowAlpha;

rdata.numColors = data.colorsAsColor.size();
for (int x = 0; x < rdata.numColors; x++) {
rdata.colorsAsColor[x] = data.colorsAsColor[x].asChar4();
rdata.colorsAsHSV[x] = {(float)data.colorsAsHSV[x].hue, (float)data.colorsAsHSV[x].saturation, (float)data.colorsAsHSV[x].value};
}
if (this->data->Render(0, rdata, buffer)) {
return;
}
PinwheelEffect::RenderNewArms(buffer, data);
}
78 changes: 78 additions & 0 deletions xLights/effects/metal/PinwheelFunctions.metal
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

#include <metal_stdlib>
using namespace metal;


#include "MetalEffectDataTypes.h"

constant simd::float4 K = simd::float4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);

uchar4 hsv2rgb(simd::float3 c) {
simd::float3 p = abs(fract(c.xxx + K.xyz) * 6.0h - K.www);
c = c.z * mix(K.xxx, clamp(p - K.xxx, 0.0h, 1.0h), c.y);
return uchar4(c.r * 255.0h, c.g * 255.0h, c.b * 255.0h, 255);
}

kernel void PinwheelEffectStyle0(constant MetalPinwheelData &data,
device uchar4* result,
uint index [[thread_position_in_grid]])
{
if (index > (data.width * data.height)) return;
int x = index % data.width;
int y = index / data.width;

float y1 = y - data.yc_adj - ((float)data.height / 2.0f);
float x1 = x - data.xc_adj - ((float)data.width / 2.0f);
float r = sqrt((x1*x1) + (y1*y1));

simd::float3 hsv;
if (r <= data.max_radius) {
float degrees_twist = (r / data.max_radius) * data.pinwheel_twist;
float theta = (atan2(x1, y1) * 180 / 3.14159) + degrees_twist;
if (data.pinwheel_rotation == 1) { // do we have CW rotation
theta = data.pos + theta + (data.tmax / 2) + data.poffset;
} else {
theta = data.pos - theta + (data.tmax / 2) + data.poffset;
}
theta = theta + 540.0;
int t2 = (int)theta % data.degrees_per_arm;
if (t2 <= data.tmax) {
float round = (float)t2 / (float)data.tmax;
t2 = abs(t2 - (data.tmax / 2)) * 2;
int ColorIdx2 = ((int)((theta / data.degrees_per_arm))) % data.pinwheel_arms;
simd::uchar4 color = data.colorsAsColor[ColorIdx2];
if (!data.allowAlpha) {
hsv = data.colorsAsHSV[ColorIdx2];
}
switch (data.pw3dType) {
case 1:
if (data.allowAlpha) {
color.a = 255.0 * ((data.tmax - t2) / data.tmax);
} else {
hsv.z = hsv.z * ((data.tmax - t2) / data.tmax);
color = hsv2rgb(hsv);
}
break;
case 2:
if (data.allowAlpha) {
color.a = 255.0 * ((t2) / data.tmax);
} else {
hsv.z = hsv.z * ((t2) / data.tmax);
color = hsv2rgb(hsv);
}
break;
case 3:
if (data.allowAlpha) {
color.a = 255.0 * (1.0 - round);
} else {
hsv.z = hsv.z * (1.0 - round);
color = hsv2rgb(hsv);
}
break;
default:
break;
}
result[index] = color;
}
}
}

0 comments on commit 44b4ad6

Please sign in to comment.