From 9a33c95b69b0eca342e0ba13701f7526782137c6 Mon Sep 17 00:00:00 2001 From: Nexrem Date: Thu, 4 Sep 2025 14:20:17 +0000 Subject: [PATCH] Add support for PowerColor Red Devil RX9070XT --- .../PowerColorGPUControllerDetect.cpp | 40 ++ .../PowerColorRedDevilV2Controller.cpp | 167 +++++++++ .../PowerColorRedDevilV2Controller.h | 101 +++++ .../RGBController_PowerColorRedDevilV2.cpp | 351 ++++++++++++++++++ .../RGBController_PowerColorRedDevilV2.h | 42 +++ pci_ids/pci_ids.h | 2 + 6 files changed, 703 insertions(+) create mode 100644 Controllers/PowerColorGPUController/PowerColorGPUControllerDetect.cpp create mode 100644 Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.cpp create mode 100644 Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.h create mode 100644 Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.cpp create mode 100644 Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.h diff --git a/Controllers/PowerColorGPUController/PowerColorGPUControllerDetect.cpp b/Controllers/PowerColorGPUController/PowerColorGPUControllerDetect.cpp new file mode 100644 index 000000000..696670112 --- /dev/null +++ b/Controllers/PowerColorGPUController/PowerColorGPUControllerDetect.cpp @@ -0,0 +1,40 @@ +/*---------------------------------------------------------*\ +| PowerColorGPUControllerDetect.cpp | +| | +| Driver for PowerColor GPUs | +| | +| Nexrem 15 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include "Detector.h" +#include "pci_ids.h" +#include "PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.h" +#include "PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.h" + +#define RED_DEVIL_V1_MAGIC_ADDR 0x90 + +static const unsigned char magic_v1[3] = {0x01, 0x05, 0x00}; +static const unsigned char magic_v2[3] = {0x01, 0x32, 0x00}; + +void DetectPowerColorRedDevilGPUControllersV2(i2c_smbus_interface* bus, uint8_t i2c_addr, const std::string& name) +{ + /*---------------------------------------------------------*\ + | The controller reports a unique identifier for V1 and V2. | + | Unfortunately they are on different addresses. Read it | + | for good measure anyways. | + \*---------------------------------------------------------*/ + unsigned char data[3]; + int ret = bus->i2c_smbus_read_i2c_block_data(i2c_addr, RED_DEVIL_V2_READ_REG_MAGIC, 3, data); + if(ret == 3 && memcmp(data, magic_v2, 3) == 0) + { + PowerColorRedDevilV2Controller* controller = new PowerColorRedDevilV2Controller(bus, i2c_addr, name); + RGBController_PowerColorRedDevilV2* rgb_controller = new RGBController_PowerColorRedDevilV2(controller); + + ResourceManager::get()->RegisterRGBController(rgb_controller); + } +} + +REGISTER_I2C_PCI_DETECTOR("PowerColor Red Devil RX9070XT", DetectPowerColorRedDevilGPUControllersV2, AMD_GPU_VEN, AMD_NAVI48_DEV, POWERCOLOR_SUB_VEN, POWERCOLOR_RED_DEVIL_RX9070XT_SUB_DEV, 0x22); \ No newline at end of file diff --git a/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.cpp b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.cpp new file mode 100644 index 000000000..2a837bf0f --- /dev/null +++ b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.cpp @@ -0,0 +1,167 @@ +/*---------------------------------------------------------*\ +| PowerColorRedDevilV2Controller.cpp | +| | +| Driver for PowerColor Red Devil GPU | +| | +| Nexrem 15 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "PowerColorRedDevilV2Controller.h" + + +PowerColorRedDevilV2Controller::PowerColorRedDevilV2Controller(i2c_smbus_interface* bus, red_devil_v2_dev_id dev, std::string dev_name) +{ + this->bus = bus; + this->dev = dev; + this->name = dev_name; +} + +PowerColorRedDevilV2Controller::~PowerColorRedDevilV2Controller() +{ + +} + +std::string PowerColorRedDevilV2Controller::GetDeviceLocation() +{ + std::string return_string(bus->device_name); + char addr[5]; + snprintf(addr, 5, "0x%02X", dev); + return_string.append(", address "); + return_string.append(addr); + return("I2C:" + return_string); +} + +std::string PowerColorRedDevilV2Controller::GetDeviceName() +{ + return(name); +} + +bool PowerColorRedDevilV2Controller::GetSync() +{ + unsigned char data[3]; + RegisterRead(RED_DEVIL_V2_READ_REG_SYNC, data); + + return data[0] && data[1] && data[2]; +} + +void PowerColorRedDevilV2Controller::SetSync(bool sync) +{ + if(sync) + { + unsigned char data[3] = {0x01, 0x01, 0x01}; + RegisterWrite(RED_DEVIL_V2_WRITE_REG_SYNC, data); + } + else + { + unsigned char data[3] = {0x00, 0x00, 0x00}; + RegisterWrite(RED_DEVIL_V2_WRITE_REG_SYNC, data); + } +} + +/*------------------------------------------------------------------*\ +| Mode returns MMBBSS | +\*------------------------------------------------------------------*/ +red_devil_v2_mode PowerColorRedDevilV2Controller::GetMode() +{ + unsigned char data[3]; + red_devil_v2_mode mode; + + RegisterRead(RED_DEVIL_V2_READ_REG_MODE, data); + + mode.mode = data[0]; + mode.brightness = data[1]; + mode.speed = data[2]; + + return mode; +} + +void PowerColorRedDevilV2Controller::SetMode(red_devil_v2_mode mode) +{ + if(mode.mode == RED_DEVIL_V2_MODE_SYNC) + { + SetSync(true); + return; + } + + SetSync(false); + + unsigned char data[3] = + { + mode.mode, + mode.brightness, + mode.speed + }; + + RegisterWrite(RED_DEVIL_V2_WRITE_REG_MODE, data); +} + +RGBColor PowerColorRedDevilV2Controller::GetLedColor(int led) +{ + /*------------------------------------------------------------------*\ + | On overflow read the first LED | + \*------------------------------------------------------------------*/ + if(led >= RED_DEVIL_V2_NUM_LEDS) + { + led = 0; + } + + unsigned char data[3]; + RegisterRead(RED_DEVIL_V2_READ_REG_RGBX + led, data); + + return ToRGBColor(data[0], data[1], data[2]); +} + +void PowerColorRedDevilV2Controller::SetLedColor(int led, RGBColor color) +{ + /*------------------------------------------------------------------*\ + | Skip writing to invalid LEDs | + \*------------------------------------------------------------------*/ + if(led >= RED_DEVIL_V2_NUM_LEDS) + { + return; + } + + unsigned char data[3] = + { + (unsigned char) RGBGetRValue(color), + (unsigned char) RGBGetGValue(color), + (unsigned char) RGBGetBValue(color) + }; + + RegisterWrite(RED_DEVIL_V2_WRITE_REG_RGBX+led, data); +} + +void PowerColorRedDevilV2Controller::SetLedColorAll(RGBColor color) +{ + unsigned char data[3] = + { + (unsigned char) RGBGetRValue(color), + (unsigned char) RGBGetGValue(color), + (unsigned char) RGBGetBValue(color) + }; + + /*------------------------------------------------------------------*\ + | Factory firmware writes both, but we only need 1 of them. | + | Write both anyways just in case... | + \*------------------------------------------------------------------*/ + RegisterWrite(RED_DEVIL_V2_WRITE_REG_RGB1, data); + RegisterWrite(RED_DEVIL_V2_WRITE_REG_RGB2, data); +} + +int PowerColorRedDevilV2Controller::RegisterRead(unsigned char reg, unsigned char *data) +{ + int ret = bus->i2c_smbus_read_i2c_block_data(dev, reg, 3, data); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + return ret; +} + +int PowerColorRedDevilV2Controller::RegisterWrite(unsigned char reg, unsigned char *data) +{ + int ret = bus->i2c_smbus_write_i2c_block_data(dev, reg, 3, data); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + return ret; +} \ No newline at end of file diff --git a/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.h b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.h new file mode 100644 index 000000000..63b614480 --- /dev/null +++ b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/PowerColorRedDevilV2Controller.h @@ -0,0 +1,101 @@ +/*---------------------------------------------------------*\ +| PowerColorRedDevilV2Controller.h | +| | +| Driver for PowerColor Red Devil GPU | +| | +| Nexrem 15 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#include +#include "i2c_smbus.h" +#include "RGBController.h" + +#pragma once + +typedef unsigned char red_devil_v2_dev_id; + +struct red_devil_v2_mode +{ + unsigned char mode; + unsigned char brightness; + unsigned char speed; +}; + +#define RED_DEVIL_V2_NUM_LEDS 24 + +enum +{ + RED_DEVIL_V2_WRITE_REG_MODE = 0x01, + RED_DEVIL_V2_WRITE_REG_SYNC = 0x04, + RED_DEVIL_V2_WRITE_REG_RGBX = 0x10, + RED_DEVIL_V2_WRITE_REG_RGB1 = 0x30, + RED_DEVIL_V2_WRITE_REG_RGB2 = 0x31 +}; + +enum +{ + RED_DEVIL_V2_READ_REG_MODE = 0x81, + RED_DEVIL_V2_READ_REG_MAGIC = 0x82, + RED_DEVIL_V2_READ_REG_SYNC = 0x84, + RED_DEVIL_V2_READ_REG_RGBX = 0x90 +}; + +enum +{ + RED_DEVIL_V2_MODE_OFF = 0x00, + RED_DEVIL_V2_MODE_STATIC = 0x01, + RED_DEVIL_V2_MODE_BREATHING = 0x02, + RED_DEVIL_V2_MODE_SECRET_RAINBOW = 0x03, + RED_DEVIL_V2_MODE_RADIANCE = 0x04, + RED_DEVIL_V2_MODE_DIFFUSE = 0x05, + RED_DEVIL_V2_MODE_COLOR_SHIFT = 0x06, + RED_DEVIL_V2_MODE_METEOR = 0x07, + RED_DEVIL_V2_MODE_RIPPLE = 0x08, + RED_DEVIL_V2_MODE_RAINBOW = 0x09, + RED_DEVIL_V2_MODE_SYNC = 0xFF +}; + +enum +{ + RED_DEVIL_V2_BRIGHTNESS_MIN = 0x00, + RED_DEVIL_V2_BRIGHTNESS_MAX = 0xFF +}; + +enum +{ + RED_DEVIL_V2_SPEED_MIN = 0xFF, + RED_DEVIL_V2_SPEED_DEFAULT = 0x32, + RED_DEVIL_V2_SPEED_MAX = 0x00 +}; + + +class PowerColorRedDevilV2Controller +{ +public: + PowerColorRedDevilV2Controller(i2c_smbus_interface* bus, red_devil_v2_dev_id dev, std::string dev_name); + ~PowerColorRedDevilV2Controller(); + + std::string GetDeviceLocation(); + std::string GetDeviceName(); + + bool GetSync(); + void SetSync(bool sync); + + red_devil_v2_mode GetMode(); + void SetMode(red_devil_v2_mode mode); + + RGBColor GetLedColor(int led); + void SetLedColor(int led, RGBColor color); + void SetLedColorAll(RGBColor color); + +private: + i2c_smbus_interface* bus; + red_devil_v2_dev_id dev; + std::string name; + + int RegisterRead(unsigned char reg, unsigned char *data); + int RegisterWrite(unsigned char reg, unsigned char *data); +}; diff --git a/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.cpp b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.cpp new file mode 100644 index 000000000..113213472 --- /dev/null +++ b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.cpp @@ -0,0 +1,351 @@ +/*---------------------------------------------------------*\ +| RGBController_PowerColorRedDevilV2.cpp | +| | +| Driver for PowerColor Red Devil GPU | +| | +| Nexrem 15 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "RGBController_PowerColorRedDevilV2.h" + +RGBController_PowerColorRedDevilV2::RGBController_PowerColorRedDevilV2(PowerColorRedDevilV2Controller* controller_ptr) +{ + controller = controller_ptr; + + name = controller->GetDeviceName(); + vendor = "PowerColor"; + description = "PowerColor Red Devil V2 GPU Device"; + location = controller->GetDeviceLocation(); + type = DEVICE_TYPE_GPU; + + mode Off; + Off.name = "Off"; + Off.value = RED_DEVIL_V2_MODE_OFF; + Off.flags = MODE_FLAG_AUTOMATIC_SAVE; + Off.color_mode = MODE_COLORS_NONE; + modes.push_back(Off); + + mode Static; + Static.name = "Custom"; + Static.value = RED_DEVIL_V2_MODE_STATIC; + Static.flags = MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Static.color_mode = MODE_COLORS_PER_LED; + Static.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Static.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Static.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + modes.push_back(Static); + + mode Breathing; + Breathing.name = "Breathing"; + Breathing.value = RED_DEVIL_V2_MODE_BREATHING; + Breathing.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Breathing.color_mode = MODE_COLORS_PER_LED; + Breathing.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Breathing.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Breathing.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Breathing.speed_min = RED_DEVIL_V2_SPEED_MIN; + Breathing.speed_max = RED_DEVIL_V2_SPEED_MAX; + Breathing.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Breathing); + + mode SecretRainbow; + SecretRainbow.name = "Secret Rainbow"; + SecretRainbow.value = RED_DEVIL_V2_MODE_SECRET_RAINBOW; + SecretRainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + SecretRainbow.color_mode = MODE_COLORS_NONE; + SecretRainbow.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + SecretRainbow.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + SecretRainbow.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + SecretRainbow.speed_min = RED_DEVIL_V2_SPEED_MIN; + SecretRainbow.speed_max = RED_DEVIL_V2_SPEED_MAX; + SecretRainbow.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(SecretRainbow); + + mode Radiance; + Radiance.name = "Radiance"; + Radiance.value = RED_DEVIL_V2_MODE_RADIANCE; + Radiance.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Radiance.color_mode = MODE_COLORS_NONE; + Radiance.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Radiance.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Radiance.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Radiance.speed_min = RED_DEVIL_V2_SPEED_MIN; + Radiance.speed_max = RED_DEVIL_V2_SPEED_MAX; + Radiance.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Radiance); + + mode Diffuse; + Diffuse.name = "Diffuse"; + Diffuse.value = RED_DEVIL_V2_MODE_DIFFUSE; + Diffuse.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Diffuse.color_mode = MODE_COLORS_NONE; + Diffuse.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Diffuse.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Diffuse.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Diffuse.speed_min = RED_DEVIL_V2_SPEED_MIN; + Diffuse.speed_max = RED_DEVIL_V2_SPEED_MAX; + Diffuse.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Diffuse); + + mode ColorShift; + ColorShift.name = "Color Shift"; + ColorShift.value = RED_DEVIL_V2_MODE_COLOR_SHIFT; + ColorShift.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + ColorShift.color_mode = MODE_COLORS_NONE; + ColorShift.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + ColorShift.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + ColorShift.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + ColorShift.speed_min = RED_DEVIL_V2_SPEED_MIN; + ColorShift.speed_max = RED_DEVIL_V2_SPEED_MAX; + ColorShift.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(ColorShift); + + mode Meteor; + Meteor.name = "Meteor"; + Meteor.value = RED_DEVIL_V2_MODE_METEOR; + Meteor.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Meteor.color_mode = MODE_COLORS_PER_LED; + Meteor.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Meteor.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Meteor.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Meteor.speed_min = RED_DEVIL_V2_SPEED_MIN; + Meteor.speed_max = RED_DEVIL_V2_SPEED_MAX; + Meteor.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Meteor); + + mode Ripple; + Ripple.name = "Ripple"; + Ripple.value = RED_DEVIL_V2_MODE_RIPPLE; + Ripple.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_PER_LED_COLOR | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Ripple.color_mode = MODE_COLORS_PER_LED; + Ripple.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Ripple.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Ripple.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Ripple.speed_min = RED_DEVIL_V2_SPEED_MIN; + Ripple.speed_max = RED_DEVIL_V2_SPEED_MAX; + Ripple.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Ripple); + + mode Rainbow; + Rainbow.name = "Rainbow"; + Rainbow.value = RED_DEVIL_V2_MODE_RAINBOW; + Rainbow.flags = MODE_FLAG_HAS_SPEED | MODE_FLAG_HAS_BRIGHTNESS | MODE_FLAG_AUTOMATIC_SAVE; + Rainbow.color_mode = MODE_COLORS_NONE; + Rainbow.brightness_min = RED_DEVIL_V2_BRIGHTNESS_MIN; + Rainbow.brightness_max = RED_DEVIL_V2_BRIGHTNESS_MAX; + Rainbow.brightness = RED_DEVIL_V2_BRIGHTNESS_MAX; + Rainbow.speed_min = RED_DEVIL_V2_SPEED_MIN; + Rainbow.speed_max = RED_DEVIL_V2_SPEED_MAX; + Rainbow.speed = RED_DEVIL_V2_SPEED_DEFAULT; + modes.push_back(Rainbow); + + mode Sync; + Sync.name = "Sync with motherboard"; + Sync.value = RED_DEVIL_V2_MODE_SYNC; + Sync.flags = MODE_FLAG_AUTOMATIC_SAVE; + Sync.color_mode = MODE_COLORS_NONE; + modes.push_back(Sync); + + SetupZones(); + + ReadConfig(); + + /*------------------------------------------------------------------*\ + | Copy the read colors for later delta-ing | + \*------------------------------------------------------------------*/ + colors_copy = colors; +} + +RGBController_PowerColorRedDevilV2::~RGBController_PowerColorRedDevilV2() +{ + delete controller; +} + +void RGBController_PowerColorRedDevilV2::SetupZones() +{ + zone stripe1; + stripe1.name = "Stripe 1"; + stripe1.type = ZONE_TYPE_LINEAR; + stripe1.leds_min = 3; + stripe1.leds_max = 3; + stripe1.leds_count = 3; + stripe1.matrix_map = NULL; + zones.push_back(stripe1); + + zone stripe2; + stripe2.name = "Stripe 2"; + stripe2.type = ZONE_TYPE_LINEAR; + stripe2.leds_min = 3; + stripe2.leds_max = 3; + stripe2.leds_count = 3; + stripe2.matrix_map = NULL; + zones.push_back(stripe2); + + static unsigned int hellstone_map[2][7] = + { + { 0, 1, 2, 3, 4, 5, 6 }, + { 13, 12, 11, 10, 9, 8, 7 } + }; + + zone hellstone; + hellstone.name = "Hellstone"; + hellstone.type = ZONE_TYPE_MATRIX; + hellstone.leds_min = 14; + hellstone.leds_max = 14; + hellstone.leds_count = 14; + hellstone.matrix_map = new matrix_map_type; + hellstone.matrix_map->height = 2; + hellstone.matrix_map->width = 7; + hellstone.matrix_map->map = (unsigned int *)hellstone_map; + zones.push_back(hellstone); + + zone devil; + devil.name = "Devil"; + devil.type = ZONE_TYPE_LINEAR; + devil.leds_min = 4; + devil.leds_max = 4; + devil.leds_count = 4; + devil.matrix_map = NULL; + zones.push_back(devil); + + /*------------------------------------------------------------------*\ + | Create the LEDs for each zone | + \*------------------------------------------------------------------*/ + for(unsigned int i = 0; i < stripe1.leds_count; i++) + { + led new_led; + new_led.name = stripe1.name + " " + std::to_string(i+1); + leds.push_back(new_led); + } + + for(unsigned int i = 0; i < stripe2.leds_count; i++) + { + led new_led; + new_led.name = stripe2.name + " " + std::to_string(i+1); + leds.push_back(new_led); + } + + for(unsigned int i = 0; i < hellstone.leds_count; i++) + { + led new_led; + new_led.name = hellstone.name + " " + std::to_string(i+1); + leds.push_back(new_led); + } + + for(unsigned int i = 0; i < devil.leds_count; i++) + { + led new_led; + new_led.name = devil.name + " " + std::to_string(i+1); + leds.push_back(new_led); + } + + SetupColors(); +} + +void RGBController_PowerColorRedDevilV2::ResizeZone(int, int) +{ + /*---------------------------------------------------------*\ + | This device does not support resizing zones | + \*---------------------------------------------------------*/ +} + +void RGBController_PowerColorRedDevilV2::DeviceUpdateLEDs() +{ + /*---------------------------------------------------------*\ + | Check if all colors are identical. If they are do a | + | single register write instead of writing to each LED | + \*---------------------------------------------------------*/ + bool all_same = true; + for(int i = 1; i < colors.size(); i++) + { + if(colors[i-1] != colors[i]) + { + all_same = false; + break; + } + } + + /*---------------------------------------------------------*\ + | Do single register write to set all | + \*---------------------------------------------------------*/ + if(all_same) + { + RGBColor color = colors[0]; + controller->SetLedColorAll(color); + } + else + { + /*---------------------------------------------------------*\ + | Since writing to each LED is slow check which colors have | + | changed and only write those instead | + \*---------------------------------------------------------*/ + for(int i = 0; i < colors.size(); i++) + { + if(colors[i] != colors_copy[i]) + { + controller->SetLedColor(i, colors[i]); + } + } + } + + /*---------------------------------------------------------*\ + | Store changed colors | + \*---------------------------------------------------------*/ + colors_copy = colors; +} + +void RGBController_PowerColorRedDevilV2::UpdateZoneLEDs(int) +{ + DeviceUpdateLEDs(); +} + +void RGBController_PowerColorRedDevilV2::UpdateSingleLED(int) +{ + DeviceUpdateLEDs(); +} + +void RGBController_PowerColorRedDevilV2::DeviceUpdateMode() +{ + red_devil_v2_mode mode; + mode.mode = (unsigned char)modes[active_mode].value; + mode.brightness = (unsigned char)modes[active_mode].brightness; + mode.speed = (unsigned char)modes[active_mode].speed; + + controller->SetMode(mode); +} + +void RGBController_PowerColorRedDevilV2::ReadConfig() +{ + red_devil_v2_mode mode = controller->GetMode(); + bool sync = controller->GetSync(); + + for(int i = 0; i < colors.size(); i++) + { + colors[i] = controller->GetLedColor(i); + } + + /*---------------------------------------------------------*\ + | Since Sync is not actually "a mode" it needs special | + | handling | + \*---------------------------------------------------------*/ + if(sync) + { + active_mode = 10; + } + else if(mode.mode < modes.size() - 1) + { + /*---------------------------------------------------------*\ + | Mode ordering is important, keep them in order | + \*---------------------------------------------------------*/ + active_mode = mode.mode; + } + + modes[active_mode].brightness = mode.brightness; + modes[active_mode].speed = mode.speed; +} \ No newline at end of file diff --git a/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.h b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.h new file mode 100644 index 000000000..92fc9938f --- /dev/null +++ b/Controllers/PowerColorGPUController/PowerColorRedDevilV2Controller/RGBController_PowerColorRedDevilV2.h @@ -0,0 +1,42 @@ +/*---------------------------------------------------------*\ +| RGBController_PowerColorRedDevilV2.h | +| | +| Driver for PowerColor Red Devil GPU | +| | +| Nexrem 15 Aug 2025 | +| | +| This file is part of the OpenRGB project | +| SPDX-License-Identifier: GPL-2.0-only | +\*---------------------------------------------------------*/ + +#pragma once + +#include "RGBController.h" +#include "PowerColorRedDevilV2Controller.h" + +class RGBController_PowerColorRedDevilV2 : public RGBController +{ +public: + RGBController_PowerColorRedDevilV2(PowerColorRedDevilV2Controller* controller_ptr); + ~RGBController_PowerColorRedDevilV2(); + + void SetupZones(); + + void ResizeZone(int, int); + + void DeviceUpdateLEDs(); + void UpdateZoneLEDs(int); + void UpdateSingleLED(int); + + void DeviceUpdateMode(); + +private: + PowerColorRedDevilV2Controller *controller; + /*------------------------------------------------------------------*\ + | To optimize color writes we store a copy of the colors in order to | + | later only write changed colors | + \*------------------------------------------------------------------*/ + std::vector colors_copy; + + void ReadConfig(); +}; diff --git a/pci_ids/pci_ids.h b/pci_ids/pci_ids.h index 9bf455cde..b1450328d 100644 --- a/pci_ids/pci_ids.h +++ b/pci_ids/pci_ids.h @@ -880,6 +880,8 @@ #define POWERCOLOR_RED_DEVIL_RX6750XT_SUB_DEV 0x2419 #define POWERCOLOR_RED_DEVIL_RX6950XT_SUB_DEV 0x2420 +#define POWERCOLOR_RED_DEVIL_RX9070XT_SUB_DEV 0x2435 + /*-----------------------------------------------------*\ | Sapphire Sub-Device IDs | \*-----------------------------------------------------*/