Changeset View
Changeset View
Standalone View
Standalone View
source/blender/compositor/operations/COM_DenoiseOperation.cc
| Show All 29 Lines | |||||
| DenoiseOperation::DenoiseOperation() | DenoiseOperation::DenoiseOperation() | ||||
| { | { | ||||
| this->addInputSocket(DataType::Color); | this->addInputSocket(DataType::Color); | ||||
| this->addInputSocket(DataType::Vector); | this->addInputSocket(DataType::Vector); | ||||
| this->addInputSocket(DataType::Color); | this->addInputSocket(DataType::Color); | ||||
| this->addOutputSocket(DataType::Color); | this->addOutputSocket(DataType::Color); | ||||
| this->m_settings = nullptr; | this->m_settings = nullptr; | ||||
| flags.is_fullframe_operation = true; | |||||
| output_rendered_ = false; | |||||
| } | } | ||||
| void DenoiseOperation::initExecution() | void DenoiseOperation::initExecution() | ||||
| { | { | ||||
| SingleThreadedOperation::initExecution(); | SingleThreadedOperation::initExecution(); | ||||
| this->m_inputProgramColor = getInputSocketReader(0); | this->m_inputProgramColor = getInputSocketReader(0); | ||||
| this->m_inputProgramNormal = getInputSocketReader(1); | this->m_inputProgramNormal = getInputSocketReader(1); | ||||
| this->m_inputProgramAlbedo = getInputSocketReader(2); | this->m_inputProgramAlbedo = getInputSocketReader(2); | ||||
| } | } | ||||
| Show All 12 Lines | MemoryBuffer *DenoiseOperation::createMemoryBuffer(rcti *rect2) | ||||
| MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2); | MemoryBuffer *tileNormal = (MemoryBuffer *)this->m_inputProgramNormal->initializeTileData(rect2); | ||||
| MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2); | MemoryBuffer *tileAlbedo = (MemoryBuffer *)this->m_inputProgramAlbedo->initializeTileData(rect2); | ||||
| rcti rect; | rcti rect; | ||||
| rect.xmin = 0; | rect.xmin = 0; | ||||
| rect.ymin = 0; | rect.ymin = 0; | ||||
| rect.xmax = getWidth(); | rect.xmax = getWidth(); | ||||
| rect.ymax = getHeight(); | rect.ymax = getHeight(); | ||||
| MemoryBuffer *result = new MemoryBuffer(DataType::Color, rect); | MemoryBuffer *result = new MemoryBuffer(DataType::Color, rect); | ||||
| float *data = result->getBuffer(); | this->generateDenoise(result, tileColor, tileNormal, tileAlbedo, this->m_settings); | ||||
| this->generateDenoise(data, tileColor, tileNormal, tileAlbedo, this->m_settings); | |||||
| return result; | return result; | ||||
| } | } | ||||
| bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/, | bool DenoiseOperation::determineDependingAreaOfInterest(rcti * /*input*/, | ||||
| ReadBufferOperation *readOperation, | ReadBufferOperation *readOperation, | ||||
| rcti *output) | rcti *output) | ||||
| { | { | ||||
| if (isCached()) { | if (isCached()) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| rcti newInput; | rcti newInput; | ||||
| newInput.xmax = this->getWidth(); | newInput.xmax = this->getWidth(); | ||||
| newInput.xmin = 0; | newInput.xmin = 0; | ||||
| newInput.ymax = this->getHeight(); | newInput.ymax = this->getHeight(); | ||||
| newInput.ymin = 0; | newInput.ymin = 0; | ||||
| return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); | return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); | ||||
| } | } | ||||
| void DenoiseOperation::generateDenoise(float *data, | void DenoiseOperation::generateDenoise(MemoryBuffer *output, | ||||
| MemoryBuffer *inputTileColor, | MemoryBuffer *input_color, | ||||
| MemoryBuffer *inputTileNormal, | MemoryBuffer *input_normal, | ||||
| MemoryBuffer *inputTileAlbedo, | MemoryBuffer *input_albedo, | ||||
| NodeDenoise *settings) | NodeDenoise *settings) | ||||
| { | { | ||||
| float *inputBufferColor = inputTileColor->getBuffer(); | BLI_assert(input_color->getBuffer()); | ||||
| BLI_assert(inputBufferColor); | if (!input_color->getBuffer()) { | ||||
| if (!inputBufferColor) { | |||||
| return; | return; | ||||
| } | } | ||||
| #ifdef WITH_OPENIMAGEDENOISE | #ifdef WITH_OPENIMAGEDENOISE | ||||
| /* Always supported through Accelerate framework BNNS on macOS. */ | /* Always supported through Accelerate framework BNNS on macOS. */ | ||||
| # ifndef __APPLE__ | # ifndef __APPLE__ | ||||
| if (BLI_cpu_support_sse41()) | if (BLI_cpu_support_sse41()) | ||||
| # endif | # endif | ||||
| { | { | ||||
| /* OpenImageDenoise needs full buffers. */ | |||||
| MemoryBuffer *buf_color = input_color->is_a_single_elem() ? input_color->inflate() : | |||||
| input_color; | |||||
| MemoryBuffer *buf_normal = input_normal && input_normal->is_a_single_elem() ? | |||||
| input_normal->inflate() : | |||||
| input_normal; | |||||
| MemoryBuffer *buf_albedo = input_albedo && input_albedo->is_a_single_elem() ? | |||||
| input_albedo->inflate() : | |||||
| input_albedo; | |||||
| /* Since it's memory intensive, it's better to run only one instance of OIDN at a time. | /* Since it's memory intensive, it's better to run only one instance of OIDN at a time. | ||||
| * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless. | * OpenImageDenoise is multithreaded internally and should use all available cores nonetheless. | ||||
| */ | */ | ||||
| BLI_mutex_lock(&oidn_lock); | BLI_mutex_lock(&oidn_lock); | ||||
| oidn::DeviceRef device = oidn::newDevice(); | oidn::DeviceRef device = oidn::newDevice(); | ||||
| device.commit(); | device.commit(); | ||||
| oidn::FilterRef filter = device.newFilter("RT"); | oidn::FilterRef filter = device.newFilter("RT"); | ||||
| filter.setImage("color", | filter.setImage("color", | ||||
| inputBufferColor, | buf_color->getBuffer(), | ||||
| oidn::Format::Float3, | oidn::Format::Float3, | ||||
| inputTileColor->getWidth(), | buf_color->getWidth(), | ||||
| inputTileColor->getHeight(), | buf_color->getHeight(), | ||||
| 0, | 0, | ||||
| sizeof(float[4])); | sizeof(float[4])); | ||||
| if (inputTileNormal && inputTileNormal->getBuffer()) { | if (buf_normal && buf_normal->getBuffer()) { | ||||
| filter.setImage("normal", | filter.setImage("normal", | ||||
| inputTileNormal->getBuffer(), | buf_normal->getBuffer(), | ||||
| oidn::Format::Float3, | oidn::Format::Float3, | ||||
| inputTileNormal->getWidth(), | buf_normal->getWidth(), | ||||
| inputTileNormal->getHeight(), | buf_normal->getHeight(), | ||||
| 0, | 0, | ||||
| sizeof(float[3])); | sizeof(float[3])); | ||||
| } | } | ||||
| if (inputTileAlbedo && inputTileAlbedo->getBuffer()) { | if (buf_albedo && buf_albedo->getBuffer()) { | ||||
| filter.setImage("albedo", | filter.setImage("albedo", | ||||
| inputTileAlbedo->getBuffer(), | buf_albedo->getBuffer(), | ||||
| oidn::Format::Float3, | oidn::Format::Float3, | ||||
| inputTileAlbedo->getWidth(), | buf_albedo->getWidth(), | ||||
| inputTileAlbedo->getHeight(), | buf_albedo->getHeight(), | ||||
| 0, | 0, | ||||
| sizeof(float[4])); | sizeof(float[4])); | ||||
| } | } | ||||
| filter.setImage("output", | filter.setImage("output", | ||||
| data, | output->getBuffer(), | ||||
| oidn::Format::Float3, | oidn::Format::Float3, | ||||
| inputTileColor->getWidth(), | buf_color->getWidth(), | ||||
| inputTileColor->getHeight(), | buf_color->getHeight(), | ||||
| 0, | 0, | ||||
| sizeof(float[4])); | sizeof(float[4])); | ||||
| BLI_assert(settings); | BLI_assert(settings); | ||||
| if (settings) { | if (settings) { | ||||
| filter.set("hdr", settings->hdr); | filter.set("hdr", settings->hdr); | ||||
| filter.set("srgb", false); | filter.set("srgb", false); | ||||
| } | } | ||||
| filter.commit(); | filter.commit(); | ||||
| filter.execute(); | filter.execute(); | ||||
| BLI_mutex_unlock(&oidn_lock); | BLI_mutex_unlock(&oidn_lock); | ||||
| /* copy the alpha channel, OpenImageDenoise currently only supports RGB */ | /* Copy the alpha channel, OpenImageDenoise currently only supports RGB. */ | ||||
| size_t numPixels = inputTileColor->getWidth() * inputTileColor->getHeight(); | output->copy_from(input_color, input_color->get_rect(), 3, COM_DATA_TYPE_VALUE_CHANNELS, 3); | ||||
| for (size_t i = 0; i < numPixels; i++) { | |||||
| data[i * 4 + 3] = inputBufferColor[i * 4 + 3]; | /* Delete inflated buffers. */ | ||||
| if (input_color->is_a_single_elem()) { | |||||
| delete buf_color; | |||||
| } | |||||
| if (input_normal && input_normal->is_a_single_elem()) { | |||||
| delete buf_normal; | |||||
| } | } | ||||
| if (input_albedo && input_albedo->is_a_single_elem()) { | |||||
| delete buf_albedo; | |||||
| } | |||||
| return; | return; | ||||
| } | } | ||||
| #endif | #endif | ||||
| /* If built without OIDN or running on an unsupported CPU, just pass through. */ | /* If built without OIDN or running on an unsupported CPU, just pass through. */ | ||||
| UNUSED_VARS(inputTileAlbedo, inputTileNormal, settings); | UNUSED_VARS(input_albedo, input_normal, settings); | ||||
| ::memcpy(data, | output->copy_from(input_color, input_color->get_rect()); | ||||
| inputBufferColor, | } | ||||
| sizeof(float[4]) * inputTileColor->getWidth() * inputTileColor->getHeight()); | |||||
| void DenoiseOperation::get_area_of_interest(const int UNUSED(input_idx), | |||||
| const rcti &UNUSED(output_area), | |||||
| rcti &r_input_area) | |||||
| { | |||||
| r_input_area.xmin = 0; | |||||
| r_input_area.xmax = this->getWidth(); | |||||
| r_input_area.ymin = 0; | |||||
| r_input_area.ymax = this->getHeight(); | |||||
| } | |||||
| void DenoiseOperation::update_memory_buffer(MemoryBuffer *output, | |||||
| const rcti &UNUSED(area), | |||||
| Span<MemoryBuffer *> inputs) | |||||
| { | |||||
| if (!output_rendered_) { | |||||
| this->generateDenoise(output, inputs[0], inputs[1], inputs[2], m_settings); | |||||
| output_rendered_ = true; | |||||
| } | |||||
| } | } | ||||
| } // namespace blender::compositor | } // namespace blender::compositor | ||||