Changeset View
Changeset View
Standalone View
Standalone View
source/blender/compositor/intern/COM_FullFrameExecutionModel.cc
| Show First 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | for (NodeOperation *op : operations_) { | ||||
| get_output_render_area(op, area); | get_output_render_area(op, area); | ||||
| determine_areas_to_render(op, area); | determine_areas_to_render(op, area); | ||||
| determine_reads(op); | determine_reads(op); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void FullFrameExecutionModel::ensure_inputs_rendered(NodeOperation *op, | |||||
| ExecutionSystem &exec_system) | |||||
| { | |||||
| const int num_inputs = op->getNumberOfInputSockets(); | |||||
| for (int i = 0; i < num_inputs; i++) { | |||||
| NodeOperation *input_op = op->get_input_operation(i); | |||||
| if (!active_buffers_.is_operation_rendered(input_op)) { | |||||
| render_operation(input_op, exec_system); | |||||
| } | |||||
| } | |||||
| } | |||||
| Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op) | Vector<MemoryBuffer *> FullFrameExecutionModel::get_input_buffers(NodeOperation *op) | ||||
| { | { | ||||
| const int num_inputs = op->getNumberOfInputSockets(); | const int num_inputs = op->getNumberOfInputSockets(); | ||||
| Vector<MemoryBuffer *> inputs_buffers(num_inputs); | Vector<MemoryBuffer *> inputs_buffers(num_inputs); | ||||
| for (int i = 0; i < num_inputs; i++) { | for (int i = 0; i < num_inputs; i++) { | ||||
| NodeOperation *input_op = op->get_input_operation(i); | NodeOperation *input_op = op->get_input_operation(i); | ||||
| inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op); | inputs_buffers[i] = active_buffers_.get_rendered_buffer(input_op); | ||||
| } | } | ||||
| Show All 9 Lines | MemoryBuffer *FullFrameExecutionModel::create_operation_buffer(NodeOperation *op) | ||||
| /* TODO: We should check if the operation is constant instead of is_set_operation. Finding a way | /* TODO: We should check if the operation is constant instead of is_set_operation. Finding a way | ||||
| * to know if an operation is constant has to be implemented yet. */ | * to know if an operation is constant has to be implemented yet. */ | ||||
| const bool is_a_single_elem = op->get_flags().is_set_operation; | const bool is_a_single_elem = op->get_flags().is_set_operation; | ||||
| return new MemoryBuffer(data_type, op_rect, is_a_single_elem); | return new MemoryBuffer(data_type, op_rect, is_a_single_elem); | ||||
| } | } | ||||
| void FullFrameExecutionModel::render_operation(NodeOperation *op, ExecutionSystem &exec_system) | void FullFrameExecutionModel::render_operation(NodeOperation *op, ExecutionSystem &exec_system) | ||||
| { | { | ||||
| if (active_buffers_.is_operation_rendered(op)) { | |||||
| return; | |||||
| } | |||||
| ensure_inputs_rendered(op, exec_system); | |||||
| Vector<MemoryBuffer *> input_bufs = get_input_buffers(op); | Vector<MemoryBuffer *> input_bufs = get_input_buffers(op); | ||||
| const bool has_outputs = op->getNumberOfOutputSockets() > 0; | const bool has_outputs = op->getNumberOfOutputSockets() > 0; | ||||
| MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr; | MemoryBuffer *op_buf = has_outputs ? create_operation_buffer(op) : nullptr; | ||||
| Span<rcti> areas = active_buffers_.get_areas_to_render(op); | Span<rcti> areas = active_buffers_.get_areas_to_render(op); | ||||
| op->render(op_buf, areas, input_bufs, exec_system); | op->render(op_buf, areas, input_bufs, exec_system); | ||||
| active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf)); | active_buffers_.set_rendered_buffer(op, std::unique_ptr<MemoryBuffer>(op_buf)); | ||||
| operation_finished(op); | operation_finished(op); | ||||
| } | } | ||||
| /** | /** | ||||
| * Render output operations in order of priority. | * Render output operations in order of priority. | ||||
| */ | */ | ||||
| void FullFrameExecutionModel::render_operations(ExecutionSystem &exec_system) | void FullFrameExecutionModel::render_operations(ExecutionSystem &exec_system) | ||||
| { | { | ||||
| const bool is_rendering = context_.isRendering(); | const bool is_rendering = context_.isRendering(); | ||||
| WorkScheduler::start(this->context_); | WorkScheduler::start(this->context_); | ||||
| for (eCompositorPriority priority : priorities_) { | for (eCompositorPriority priority : priorities_) { | ||||
| for (NodeOperation *op : operations_) { | for (NodeOperation *op : operations_) { | ||||
| if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) { | if (op->isOutputOperation(is_rendering) && op->getRenderPriority() == priority) { | ||||
| render_output_dependencies(op, exec_system); | |||||
| render_operation(op, exec_system); | render_operation(op, exec_system); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| WorkScheduler::stop(); | WorkScheduler::stop(); | ||||
| } | } | ||||
| /** | /** | ||||
| * Determines all input operations areas needed to render given operation area. | * Returns all dependencies from inputs to outputs. A dependency may be repeated when | ||||
| * \param operation: Renderer operation. | * several operations depend on it. | ||||
| * \param render_area: Area within given operation bounds to render. | |||||
| */ | */ | ||||
| void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *operation, | static Vector<NodeOperation *> get_operation_dependencies(NodeOperation *operation) | ||||
| const rcti &render_area) | |||||
| { | { | ||||
| /* Get dependencies from outputs to inputs. */ | |||||
| Vector<NodeOperation *> dependencies; | |||||
| Vector<NodeOperation *> next_outputs; | |||||
| next_outputs.append(operation); | |||||
| while (next_outputs.size() > 0) { | |||||
| Vector<NodeOperation *> outputs(next_outputs); | |||||
| next_outputs.clear(); | |||||
| for (NodeOperation *output : outputs) { | |||||
| for (int i = 0; i < output->getNumberOfInputSockets(); i++) { | |||||
| next_outputs.append(output->get_input_operation(i)); | |||||
| } | |||||
| } | |||||
| dependencies.extend(next_outputs); | |||||
| } | |||||
| /* Reverse to get dependencies from inputs to outputs. */ | |||||
| std::reverse(dependencies.begin(), dependencies.end()); | |||||
| return dependencies; | |||||
| } | |||||
| void FullFrameExecutionModel::render_output_dependencies(NodeOperation *output_op, | |||||
| ExecutionSystem &exec_system) | |||||
| { | |||||
| BLI_assert(output_op->isOutputOperation(context_.isRendering())); | |||||
| Vector<NodeOperation *> dependencies = get_operation_dependencies(output_op); | |||||
| for (NodeOperation *op : dependencies) { | |||||
| if (!active_buffers_.is_operation_rendered(op)) { | |||||
| render_operation(op, exec_system); | |||||
| } | |||||
| } | |||||
| } | |||||
| /** | |||||
| * Determines all operations areas needed to render given output area. | |||||
| */ | |||||
| void FullFrameExecutionModel::determine_areas_to_render(NodeOperation *output_op, | |||||
| const rcti &output_area) | |||||
| { | |||||
| BLI_assert(output_op->isOutputOperation(context_.isRendering())); | |||||
| Vector<std::pair<NodeOperation *, const rcti>> stack; | |||||
| stack.append({output_op, output_area}); | |||||
| while (stack.size() > 0) { | |||||
| std::pair<NodeOperation *, rcti> pair = stack.pop_last(); | |||||
| NodeOperation *operation = pair.first; | |||||
| const rcti &render_area = pair.second; | |||||
| if (active_buffers_.is_area_registered(operation, render_area)) { | if (active_buffers_.is_area_registered(operation, render_area)) { | ||||
| return; | continue; | ||||
| } | } | ||||
| active_buffers_.register_area(operation, render_area); | active_buffers_.register_area(operation, render_area); | ||||
| const int num_inputs = operation->getNumberOfInputSockets(); | const int num_inputs = operation->getNumberOfInputSockets(); | ||||
| for (int i = 0; i < num_inputs; i++) { | for (int i = 0; i < num_inputs; i++) { | ||||
| NodeOperation *input_op = operation->get_input_operation(i); | NodeOperation *input_op = operation->get_input_operation(i); | ||||
| rcti input_op_rect, input_area; | rcti input_op_rect, input_area; | ||||
| BLI_rcti_init(&input_op_rect, 0, input_op->getWidth(), 0, input_op->getHeight()); | BLI_rcti_init(&input_op_rect, 0, input_op->getWidth(), 0, input_op->getHeight()); | ||||
| operation->get_area_of_interest(input_op, render_area, input_area); | operation->get_area_of_interest(input_op, render_area, input_area); | ||||
| /* Ensure area of interest is within operation bounds, cropping areas outside. */ | /* Ensure area of interest is within operation bounds, cropping areas outside. */ | ||||
| BLI_rcti_isect(&input_area, &input_op_rect, &input_area); | BLI_rcti_isect(&input_area, &input_op_rect, &input_area); | ||||
| determine_areas_to_render(input_op, input_area); | stack.append({input_op, input_area}); | ||||
| } | |||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Determines the reads given operation and its inputs will receive (i.e: Number of dependent | * Determines reads to receive by operations in output operation tree (i.e: Number of dependent | ||||
| * operations each operation has). | * operations each operation has). | ||||
| */ | */ | ||||
| void FullFrameExecutionModel::determine_reads(NodeOperation *operation) | void FullFrameExecutionModel::determine_reads(NodeOperation *output_op) | ||||
| { | { | ||||
| if (active_buffers_.has_registered_reads(operation)) { | BLI_assert(output_op->isOutputOperation(context_.isRendering())); | ||||
| return; | |||||
| } | |||||
| Vector<NodeOperation *> stack; | |||||
| stack.append(output_op); | |||||
| while (stack.size() > 0) { | |||||
| NodeOperation *operation = stack.pop_last(); | |||||
| const int num_inputs = operation->getNumberOfInputSockets(); | const int num_inputs = operation->getNumberOfInputSockets(); | ||||
| for (int i = 0; i < num_inputs; i++) { | for (int i = 0; i < num_inputs; i++) { | ||||
| NodeOperation *input_op = operation->get_input_operation(i); | NodeOperation *input_op = operation->get_input_operation(i); | ||||
| determine_reads(input_op); | if (!active_buffers_.has_registered_reads(input_op)) { | ||||
| stack.append(input_op); | |||||
| } | |||||
| active_buffers_.register_read(input_op); | active_buffers_.register_read(input_op); | ||||
| } | } | ||||
| } | } | ||||
| } | |||||
| /** | /** | ||||
| * Calculates given output operation area to be rendered taking into account viewer and render | * Calculates given output operation area to be rendered taking into account viewer and render | ||||
| * borders. | * borders. | ||||
| */ | */ | ||||
| void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area) | void FullFrameExecutionModel::get_output_render_area(NodeOperation *output_op, rcti &r_area) | ||||
| { | { | ||||
| BLI_assert(output_op->isOutputOperation(context_.isRendering())); | BLI_assert(output_op->isOutputOperation(context_.isRendering())); | ||||
| ▲ Show 20 Lines • Show All 117 Lines • Show Last 20 Lines | |||||