From a754e35198d852ea34e2b82cd2b126538e6f5a3b Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 14 Sep 2021 15:37:47 +0200 Subject: Cycles: refactor API for GPU display * Split GPUDisplay into two classes. PathTraceDisplay to implement the Cycles side, and DisplayDriver to implement the host application side. The DisplayDriver is now a fully abstract base class, embedded in the PathTraceDisplay. * Move copy_pixels_to_texture implementation out of the host side into the Cycles side, since it can be implemented in terms of the texture buffer mapping. * Move definition of DeviceGraphicsInteropDestination into display driver header, so that we do not need to expose private device headers in the public API. * Add more detailed comments about how the DisplayDriver should be implemented. The "driver" terminology might not be obvious, but is also used in other renderers. Differential Revision: https://developer.blender.org/D12626 --- intern/cycles/integrator/CMakeLists.txt | 2 + intern/cycles/integrator/path_trace.cpp | 47 ++-- intern/cycles/integrator/path_trace.h | 15 +- intern/cycles/integrator/path_trace_display.cpp | 268 +++++++++++++++++++++++ intern/cycles/integrator/path_trace_display.h | 201 +++++++++++++++++ intern/cycles/integrator/path_trace_work.cpp | 8 +- intern/cycles/integrator/path_trace_work.h | 12 +- intern/cycles/integrator/path_trace_work_cpu.cpp | 20 +- intern/cycles/integrator/path_trace_work_cpu.h | 8 +- intern/cycles/integrator/path_trace_work_gpu.cpp | 56 +++-- intern/cycles/integrator/path_trace_work_gpu.h | 24 +- intern/cycles/integrator/render_scheduler.h | 2 +- 12 files changed, 568 insertions(+), 95 deletions(-) create mode 100644 intern/cycles/integrator/path_trace_display.cpp create mode 100644 intern/cycles/integrator/path_trace_display.h (limited to 'intern/cycles/integrator') diff --git a/intern/cycles/integrator/CMakeLists.txt b/intern/cycles/integrator/CMakeLists.txt index bfabd35d7c3..8acd72f0508 100644 --- a/intern/cycles/integrator/CMakeLists.txt +++ b/intern/cycles/integrator/CMakeLists.txt @@ -27,6 +27,7 @@ set(SRC pass_accessor.cpp pass_accessor_cpu.cpp pass_accessor_gpu.cpp + path_trace_display.cpp path_trace_work.cpp path_trace_work_cpu.cpp path_trace_work_gpu.cpp @@ -47,6 +48,7 @@ set(SRC_HEADERS pass_accessor.h pass_accessor_cpu.h pass_accessor_gpu.h + path_trace_display.h path_trace_work.h path_trace_work_cpu.h path_trace_work_gpu.h diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp index 9633d3b87d3..36cd7314b4c 100644 --- a/intern/cycles/integrator/path_trace.cpp +++ b/intern/cycles/integrator/path_trace.cpp @@ -19,8 +19,8 @@ #include "device/cpu/device.h" #include "device/device.h" #include "integrator/pass_accessor.h" +#include "integrator/path_trace_display.h" #include "integrator/render_scheduler.h" -#include "render/gpu_display.h" #include "render/pass.h" #include "render/scene.h" #include "render/tile.h" @@ -67,11 +67,11 @@ PathTrace::PathTrace(Device *device, PathTrace::~PathTrace() { /* Destroy any GPU resource which was used for graphics interop. - * Need to have access to the GPUDisplay as it is the only source of drawing context which is - * used for interop. */ - if (gpu_display_) { + * Need to have access to the PathTraceDisplay as it is the only source of drawing context which + * is used for interop. */ + if (display_) { for (auto &&path_trace_work : path_trace_works_) { - path_trace_work->destroy_gpu_resources(gpu_display_.get()); + path_trace_work->destroy_gpu_resources(display_.get()); } } } @@ -94,7 +94,7 @@ bool PathTrace::ready_to_reset() { /* The logic here is optimized for the best feedback in the viewport, which implies having a GPU * display. Of there is no such display, the logic here will break. */ - DCHECK(gpu_display_); + DCHECK(display_); /* The logic here tries to provide behavior which feels the most interactive feel to artists. * General idea is to be able to reset as quickly as possible, while still providing interactive @@ -126,8 +126,8 @@ void PathTrace::reset(const BufferParams &full_params, const BufferParams &big_t /* NOTE: GPU display checks for buffer modification and avoids unnecessary re-allocation. * It is requires to inform about reset whenever it happens, so that the redraw state tracking is * properly updated. */ - if (gpu_display_) { - gpu_display_->reset(full_params); + if (display_) { + display_->reset(full_params); } render_state_.has_denoised_result = false; @@ -535,25 +535,30 @@ void PathTrace::denoise(const RenderWork &render_work) render_scheduler_.report_denoise_time(render_work, time_dt() - start_time); } -void PathTrace::set_gpu_display(unique_ptr gpu_display) +void PathTrace::set_display_driver(unique_ptr driver) { - gpu_display_ = move(gpu_display); + if (driver) { + display_ = make_unique(move(driver)); + } + else { + display_ = nullptr; + } } -void PathTrace::clear_gpu_display() +void PathTrace::clear_display() { - if (gpu_display_) { - gpu_display_->clear(); + if (display_) { + display_->clear(); } } void PathTrace::draw() { - if (!gpu_display_) { + if (!display_) { return; } - did_draw_after_reset_ |= gpu_display_->draw(); + did_draw_after_reset_ |= display_->draw(); } void PathTrace::update_display(const RenderWork &render_work) @@ -562,13 +567,13 @@ void PathTrace::update_display(const RenderWork &render_work) return; } - if (!gpu_display_ && !tile_buffer_update_cb) { + if (!display_ && !tile_buffer_update_cb) { VLOG(3) << "Ignore display update."; return; } if (full_params_.width == 0 || full_params_.height == 0) { - VLOG(3) << "Skipping GPUDisplay update due to 0 size of the render buffer."; + VLOG(3) << "Skipping PathTraceDisplay update due to 0 size of the render buffer."; return; } @@ -580,13 +585,13 @@ void PathTrace::update_display(const RenderWork &render_work) tile_buffer_update_cb(); } - if (gpu_display_) { + if (display_) { VLOG(3) << "Perform copy to GPUDisplay work."; const int resolution_divider = render_work.resolution_divider; const int texture_width = max(1, full_params_.width / resolution_divider); const int texture_height = max(1, full_params_.height / resolution_divider); - if (!gpu_display_->update_begin(texture_width, texture_height)) { + if (!display_->update_begin(texture_width, texture_height)) { LOG(ERROR) << "Error beginning GPUDisplay update."; return; } @@ -600,10 +605,10 @@ void PathTrace::update_display(const RenderWork &render_work) * all works in parallel. */ const int num_samples = get_num_samples_in_buffer(); for (auto &&path_trace_work : path_trace_works_) { - path_trace_work->copy_to_gpu_display(gpu_display_.get(), pass_mode, num_samples); + path_trace_work->copy_to_display(display_.get(), pass_mode, num_samples); } - gpu_display_->update_end(); + display_->update_end(); } render_scheduler_.report_display_update_time(render_work, time_dt() - start_time); diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h index f507c2d7e0a..46eb0435c91 100644 --- a/intern/cycles/integrator/path_trace.h +++ b/intern/cycles/integrator/path_trace.h @@ -31,12 +31,13 @@ CCL_NAMESPACE_BEGIN class AdaptiveSampling; class Device; class DeviceScene; +class DisplayDriver; class Film; class RenderBuffers; class RenderScheduler; class RenderWork; +class PathTraceDisplay; class Progress; -class GPUDisplay; class TileManager; /* PathTrace class takes care of kernel graph and scheduling on a (multi)device. It takes care of @@ -98,13 +99,13 @@ class PathTrace { * Use this to configure the adaptive sampler before rendering any samples. */ void set_adaptive_sampling(const AdaptiveSampling &adaptive_sampling); - /* Set GPU display which takes care of drawing the render result. */ - void set_gpu_display(unique_ptr gpu_display); + /* Set display driver which takes care of drawing the render result. */ + void set_display_driver(unique_ptr driver); - /* Clear the GPU display by filling it in with all zeroes. */ - void clear_gpu_display(); + /* Clear the display buffer by filling it in with all zeroes. */ + void clear_display(); - /* Perform drawing of the current state of the GPUDisplay. */ + /* Perform drawing of the current state of the DisplayDriver. */ void draw(); /* Cancel rendering process as soon as possible, without waiting for full tile to be sampled. @@ -252,7 +253,7 @@ class PathTrace { RenderScheduler &render_scheduler_; TileManager &tile_manager_; - unique_ptr gpu_display_; + unique_ptr display_; /* Per-compute device descriptors of work which is responsible for path tracing on its configured * device. */ diff --git a/intern/cycles/integrator/path_trace_display.cpp b/intern/cycles/integrator/path_trace_display.cpp new file mode 100644 index 00000000000..28f0a7f7745 --- /dev/null +++ b/intern/cycles/integrator/path_trace_display.cpp @@ -0,0 +1,268 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "integrator/path_trace_display.h" + +#include "render/buffers.h" + +#include "util/util_logging.h" + +CCL_NAMESPACE_BEGIN + +PathTraceDisplay::PathTraceDisplay(unique_ptr driver) : driver_(move(driver)) +{ +} + +void PathTraceDisplay::reset(const BufferParams &buffer_params) +{ + thread_scoped_lock lock(mutex_); + + const DisplayDriver::Params old_params = params_; + + params_.full_offset = make_int2(buffer_params.full_x, buffer_params.full_y); + params_.full_size = make_int2(buffer_params.full_width, buffer_params.full_height); + params_.size = make_int2(buffer_params.width, buffer_params.height); + + /* If the parameters did change tag texture as unusable. This avoids drawing old texture content + * in an updated configuration of the viewport. For example, avoids drawing old frame when render + * border did change. + * If the parameters did not change, allow drawing the current state of the texture, which will + * not count as an up-to-date redraw. This will avoid flickering when doping camera navigation by + * showing a previously rendered frame for until the new one is ready. */ + if (old_params.modified(params_)) { + texture_state_.is_usable = false; + } + + texture_state_.is_outdated = true; +} + +void PathTraceDisplay::mark_texture_updated() +{ + texture_state_.is_outdated = false; + texture_state_.is_usable = true; +} + +/* -------------------------------------------------------------------- + * Update procedure. + */ + +bool PathTraceDisplay::update_begin(int texture_width, int texture_height) +{ + DCHECK(!update_state_.is_active); + + if (update_state_.is_active) { + LOG(ERROR) << "Attempt to re-activate update process."; + return false; + } + + /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time. + * The update itself is non-blocking however, for better performance and to avoid + * potential deadlocks due to locks held by the subclass. */ + DisplayDriver::Params params; + { + thread_scoped_lock lock(mutex_); + params = params_; + texture_state_.size = make_int2(texture_width, texture_height); + } + + if (!driver_->update_begin(params, texture_width, texture_height)) { + LOG(ERROR) << "PathTraceDisplay implementation could not begin update."; + return false; + } + + update_state_.is_active = true; + + return true; +} + +void PathTraceDisplay::update_end() +{ + DCHECK(update_state_.is_active); + + if (!update_state_.is_active) { + LOG(ERROR) << "Attempt to deactivate inactive update process."; + return; + } + + driver_->update_end(); + + update_state_.is_active = false; +} + +int2 PathTraceDisplay::get_texture_size() const +{ + return texture_state_.size; +} + +/* -------------------------------------------------------------------- + * Texture update from CPU buffer. + */ + +void PathTraceDisplay::copy_pixels_to_texture( + const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height) +{ + DCHECK(update_state_.is_active); + + if (!update_state_.is_active) { + LOG(ERROR) << "Attempt to copy pixels data outside of PathTraceDisplay update."; + return; + } + + mark_texture_updated(); + + /* This call copies pixels to a mapped texture buffer which is typically much cheaper from CPU + * time point of view than to copy data directly to a texture. + * + * The possible downside of this approach is that it might require a higher peak memory when + * doing partial updates of the texture (although, in practice even partial updates might peak + * with a full-frame buffer stored on the CPU if the GPU is currently occupied). */ + half4 *mapped_rgba_pixels = map_texture_buffer(); + if (!mapped_rgba_pixels) { + return; + } + + const int texture_width = texture_state_.size.x; + const int texture_height = texture_state_.size.y; + + if (texture_x == 0 && texture_y == 0 && pixels_width == texture_width && + pixels_height == texture_height) { + const size_t size_in_bytes = sizeof(half4) * texture_width * texture_height; + memcpy(mapped_rgba_pixels, rgba_pixels, size_in_bytes); + } + else { + const half4 *rgba_row = rgba_pixels; + half4 *mapped_rgba_row = mapped_rgba_pixels + texture_y * texture_width + texture_x; + for (int y = 0; y < pixels_height; + ++y, rgba_row += pixels_width, mapped_rgba_row += texture_width) { + memcpy(mapped_rgba_row, rgba_row, sizeof(half4) * pixels_width); + } + } + + unmap_texture_buffer(); +} + +/* -------------------------------------------------------------------- + * Texture buffer mapping. + */ + +half4 *PathTraceDisplay::map_texture_buffer() +{ + DCHECK(!texture_buffer_state_.is_mapped); + DCHECK(update_state_.is_active); + + if (texture_buffer_state_.is_mapped) { + LOG(ERROR) << "Attempt to re-map an already mapped texture buffer."; + return nullptr; + } + + if (!update_state_.is_active) { + LOG(ERROR) << "Attempt to copy pixels data outside of PathTraceDisplay update."; + return nullptr; + } + + half4 *mapped_rgba_pixels = driver_->map_texture_buffer(); + + if (mapped_rgba_pixels) { + texture_buffer_state_.is_mapped = true; + } + + return mapped_rgba_pixels; +} + +void PathTraceDisplay::unmap_texture_buffer() +{ + DCHECK(texture_buffer_state_.is_mapped); + + if (!texture_buffer_state_.is_mapped) { + LOG(ERROR) << "Attempt to unmap non-mapped texture buffer."; + return; + } + + texture_buffer_state_.is_mapped = false; + + mark_texture_updated(); + driver_->unmap_texture_buffer(); +} + +/* -------------------------------------------------------------------- + * Graphics interoperability. + */ + +DisplayDriver::GraphicsInterop PathTraceDisplay::graphics_interop_get() +{ + DCHECK(!texture_buffer_state_.is_mapped); + DCHECK(update_state_.is_active); + + if (texture_buffer_state_.is_mapped) { + LOG(ERROR) + << "Attempt to use graphics interoperability mode while the texture buffer is mapped."; + return DisplayDriver::GraphicsInterop(); + } + + if (!update_state_.is_active) { + LOG(ERROR) << "Attempt to use graphics interoperability outside of PathTraceDisplay update."; + return DisplayDriver::GraphicsInterop(); + } + + /* Assume that interop will write new values to the texture. */ + mark_texture_updated(); + + return driver_->graphics_interop_get(); +} + +void PathTraceDisplay::graphics_interop_activate() +{ + driver_->graphics_interop_activate(); +} + +void PathTraceDisplay::graphics_interop_deactivate() +{ + driver_->graphics_interop_deactivate(); +} + +/* -------------------------------------------------------------------- + * Drawing. + */ + +void PathTraceDisplay::clear() +{ + driver_->clear(); +} + +bool PathTraceDisplay::draw() +{ + /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time. + * The drawing itself is non-blocking however, for better performance and to avoid + * potential deadlocks due to locks held by the subclass. */ + DisplayDriver::Params params; + bool is_usable; + bool is_outdated; + + { + thread_scoped_lock lock(mutex_); + params = params_; + is_usable = texture_state_.is_usable; + is_outdated = texture_state_.is_outdated; + } + + if (is_usable) { + driver_->draw(params); + } + + return !is_outdated; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/integrator/path_trace_display.h b/intern/cycles/integrator/path_trace_display.h new file mode 100644 index 00000000000..24aaa0df6b1 --- /dev/null +++ b/intern/cycles/integrator/path_trace_display.h @@ -0,0 +1,201 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include "render/display_driver.h" + +#include "util/util_half.h" +#include "util/util_thread.h" +#include "util/util_types.h" +#include "util/util_unique_ptr.h" + +CCL_NAMESPACE_BEGIN + +class BufferParams; + +/* PathTraceDisplay is used for efficient render buffer display. + * + * The host applications implements a DisplayDriver, storing a render pass in a GPU-side + * textures. This texture is continuously updated by the path tracer and drawn by the host + * application. + * + * PathTraceDisplay is a wrapper around the DisplayDriver, adding thread safety, state tracking + * and error checking. */ + +class PathTraceDisplay { + public: + PathTraceDisplay(unique_ptr driver); + virtual ~PathTraceDisplay() = default; + + /* Reset the display for the new state of render session. Is called whenever session is reset, + * which happens on changes like viewport navigation or viewport dimension change. + * + * This call will configure parameters for a changed buffer and reset the texture state. */ + void reset(const BufferParams &buffer_params); + + /* -------------------------------------------------------------------- + * Update procedure. + * + * These calls indicates a desire of the caller to update content of the displayed texture. */ + + /* Returns true when update is ready. Update should be finished with update_end(). + * + * If false is returned then no update is possible, and no update_end() call is needed. + * + * The texture width and height denotes an actual resolution of the underlying render result. */ + bool update_begin(int texture_width, int texture_height); + + void update_end(); + + /* Get currently configured texture size of the display (as configured by `update_begin()`. */ + int2 get_texture_size() const; + + /* -------------------------------------------------------------------- + * Texture update from CPU buffer. + * + * NOTE: The PathTraceDisplay should be marked for an update being in process with + * `update_begin()`. + * + * Most portable implementation, which must be supported by all platforms. Might not be the most + * efficient one. + */ + + /* Copy buffer of rendered pixels of a given size into a given position of the texture. + * + * This function does not acquire a lock. The reason for this is is to allow use of this function + * for partial updates from different devices. In this case the caller will acquire the lock + * once, update all the slices and release + * the lock once. This will ensure that draw() will never use partially updated texture. */ + void copy_pixels_to_texture( + const half4 *rgba_pixels, int texture_x, int texture_y, int pixels_width, int pixels_height); + + /* -------------------------------------------------------------------- + * Texture buffer mapping. + * + * This functionality is used to update GPU-side texture content without need to maintain CPU + * side buffer on the caller. + * + * NOTE: The PathTraceDisplay should be marked for an update being in process with + * `update_begin()`. + * + * NOTE: Texture buffer can not be mapped while graphics interoperability is active. This means + * that `map_texture_buffer()` is not allowed between `graphics_interop_begin()` and + * `graphics_interop_end()` calls. + */ + + /* Map pixels memory form texture to a buffer available for write from CPU. Width and height will + * define a requested size of the texture to write to. + * Upon success a non-null pointer is returned and the texture buffer is to be unmapped. + * If an error happens during mapping, or if mapping is not supported by this GPU display a + * null pointer is returned and the buffer is NOT to be unmapped. + * + * NOTE: Usually the implementation will rely on a GPU context of some sort, and the GPU context + * is often can not be bound to two threads simultaneously, and can not be released from a + * different thread. This means that the mapping API should be used from the single thread only, + */ + half4 *map_texture_buffer(); + void unmap_texture_buffer(); + + /* -------------------------------------------------------------------- + * Graphics interoperability. + * + * A special code path which allows to update texture content directly from the GPU compute + * device. Complementary part of DeviceGraphicsInterop. + * + * NOTE: Graphics interoperability can not be used while the texture buffer is mapped. This means + * that `graphics_interop_get()` is not allowed between `map_texture_buffer()` and + * `unmap_texture_buffer()` calls. */ + + /* Get PathTraceDisplay graphics interoperability information which acts as a destination for the + * device API. */ + DisplayDriver::GraphicsInterop graphics_interop_get(); + + /* (De)activate GPU display for graphics interoperability outside of regular display update + * routines. */ + void graphics_interop_activate(); + void graphics_interop_deactivate(); + + /* -------------------------------------------------------------------- + * Drawing. + */ + + /* Clear the texture by filling it with all zeroes. + * + * This call might happen in parallel with draw, but can never happen in parallel with the + * update. + * + * The actual zeroing can be deferred to a later moment. What is important is that after clear + * and before pixels update the drawing texture will be fully empty, and that partial update + * after clear will write new pixel values for an updating area, leaving everything else zeroed. + * + * If the GPU display supports graphics interoperability then the zeroing the display is to be + * delegated to the device via the `DisplayDriver::GraphicsInterop`. */ + void clear(); + + /* Draw the current state of the texture. + * + * Returns true if this call did draw an updated state of the texture. */ + bool draw(); + + private: + /* Display driver implemented by the host application. */ + unique_ptr driver_; + + /* Current display parameters */ + thread_mutex mutex_; + DisplayDriver::Params params_; + + /* Mark texture as its content has been updated. + * Used from places which knows that the texture content has been brought up-to-date, so that the + * drawing knows whether it can be performed, and whether drawing happened with an up-to-date + * texture state. */ + void mark_texture_updated(); + + /* State of the update process. */ + struct { + /* True when update is in process, indicated by `update_begin()` / `update_end()`. */ + bool is_active = false; + } update_state_; + + /* State of the texture, which is needed for an integration with render session and interactive + * updates and navigation. */ + struct { + /* Denotes whether possibly existing state of GPU side texture is still usable. + * It will not be usable in cases like render border did change (in this case we don't want + * previous texture to be rendered at all). + * + * However, if only navigation or object in scene did change, then the outdated state of the + * texture is still usable for draw, preventing display viewport flickering on navigation and + * object modifications. */ + bool is_usable = false; + + /* Texture is considered outdated after `reset()` until the next call of + * `copy_pixels_to_texture()`. */ + bool is_outdated = true; + + /* Texture size in pixels. */ + int2 size = make_int2(0, 0); + } texture_state_; + + /* State of the texture buffer. Is tracked to perform sanity checks. */ + struct { + /* True when the texture buffer is mapped with `map_texture_buffer()`. */ + bool is_mapped = false; + } texture_buffer_state_; +}; + +CCL_NAMESPACE_END diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp index d9634acac10..c29177907c9 100644 --- a/intern/cycles/integrator/path_trace_work.cpp +++ b/intern/cycles/integrator/path_trace_work.cpp @@ -16,12 +16,12 @@ #include "device/device.h" +#include "integrator/path_trace_display.h" #include "integrator/path_trace_work.h" #include "integrator/path_trace_work_cpu.h" #include "integrator/path_trace_work_gpu.h" #include "render/buffers.h" #include "render/film.h" -#include "render/gpu_display.h" #include "render/scene.h" #include "kernel/kernel_types.h" @@ -185,12 +185,12 @@ PassAccessor::PassAccessInfo PathTraceWork::get_display_pass_access_info(PassMod return pass_access_info; } -PassAccessor::Destination PathTraceWork::get_gpu_display_destination_template( - const GPUDisplay *gpu_display) const +PassAccessor::Destination PathTraceWork::get_display_destination_template( + const PathTraceDisplay *display) const { PassAccessor::Destination destination(film_->get_display_pass()); - const int2 display_texture_size = gpu_display->get_texture_size(); + const int2 display_texture_size = display->get_texture_size(); const int texture_x = effective_buffer_params_.full_x - effective_full_params_.full_x; const int texture_y = effective_buffer_params_.full_y - effective_full_params_.full_y; diff --git a/intern/cycles/integrator/path_trace_work.h b/intern/cycles/integrator/path_trace_work.h index e1be1655edd..404165b7c55 100644 --- a/intern/cycles/integrator/path_trace_work.h +++ b/intern/cycles/integrator/path_trace_work.h @@ -28,7 +28,7 @@ class BufferParams; class Device; class DeviceScene; class Film; -class GPUDisplay; +class PathTraceDisplay; class RenderBuffers; class PathTraceWork { @@ -83,11 +83,9 @@ class PathTraceWork { * noisy pass mode will be passed here when it is known that the buffer does not have denoised * passes yet (because denoiser did not run). If the denoised pass is requested and denoiser is * not used then this function will fall-back to the noisy pass instead. */ - virtual void copy_to_gpu_display(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) = 0; + virtual void copy_to_display(PathTraceDisplay *display, PassMode pass_mode, int num_samples) = 0; - virtual void destroy_gpu_resources(GPUDisplay *gpu_display) = 0; + virtual void destroy_gpu_resources(PathTraceDisplay *display) = 0; /* Copy data from/to given render buffers. * Will copy pixels from a corresponding place (from multi-device point of view) of the render @@ -162,8 +160,8 @@ class PathTraceWork { /* Get destination which offset and stride are configured so that writing to it will write to a * proper location of GPU display texture, taking current tile and device slice into account. */ - PassAccessor::Destination get_gpu_display_destination_template( - const GPUDisplay *gpu_display) const; + PassAccessor::Destination get_display_destination_template( + const PathTraceDisplay *display) const; /* Device which will be used for path tracing. * Note that it is an actual render device (and never is a multi-device). */ diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp index 14658d4d1ce..18a5365453d 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.cpp +++ b/intern/cycles/integrator/path_trace_work_cpu.cpp @@ -22,9 +22,9 @@ #include "kernel/kernel_path_state.h" #include "integrator/pass_accessor_cpu.h" +#include "integrator/path_trace_display.h" #include "render/buffers.h" -#include "render/gpu_display.h" #include "render/scene.h" #include "util/util_atomic.h" @@ -161,14 +161,14 @@ void PathTraceWorkCPU::render_samples_full_pipeline(KernelGlobals *kernel_global } } -void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) +void PathTraceWorkCPU::copy_to_display(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) { - half4 *rgba_half = gpu_display->map_texture_buffer(); + half4 *rgba_half = display->map_texture_buffer(); if (!rgba_half) { - /* TODO(sergey): Look into using copy_to_gpu_display() if mapping failed. Might be needed for - * some implementations of GPUDisplay which can not map memory? */ + /* TODO(sergey): Look into using copy_to_display() if mapping failed. Might be needed for + * some implementations of PathTraceDisplay which can not map memory? */ return; } @@ -178,7 +178,7 @@ void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display, const PassAccessorCPU pass_accessor(pass_access_info, kfilm.exposure, num_samples); - PassAccessor::Destination destination = get_gpu_display_destination_template(gpu_display); + PassAccessor::Destination destination = get_display_destination_template(display); destination.pixels_half_rgba = rgba_half; tbb::task_arena local_arena = local_tbb_arena_create(device_); @@ -186,10 +186,10 @@ void PathTraceWorkCPU::copy_to_gpu_display(GPUDisplay *gpu_display, pass_accessor.get_render_tile_pixels(buffers_.get(), effective_buffer_params_, destination); }); - gpu_display->unmap_texture_buffer(); + display->unmap_texture_buffer(); } -void PathTraceWorkCPU::destroy_gpu_resources(GPUDisplay * /*gpu_display*/) +void PathTraceWorkCPU::destroy_gpu_resources(PathTraceDisplay * /*display*/) { } diff --git a/intern/cycles/integrator/path_trace_work_cpu.h b/intern/cycles/integrator/path_trace_work_cpu.h index ab729bbf879..d011e8d05bd 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.h +++ b/intern/cycles/integrator/path_trace_work_cpu.h @@ -50,10 +50,10 @@ class PathTraceWorkCPU : public PathTraceWork { int start_sample, int samples_num) override; - virtual void copy_to_gpu_display(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) override; - virtual void destroy_gpu_resources(GPUDisplay *gpu_display) override; + virtual void copy_to_display(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) override; + virtual void destroy_gpu_resources(PathTraceDisplay *display) override; virtual bool copy_render_buffers_from_device() override; virtual bool copy_render_buffers_to_device() override; diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp index e41d8d1d252..17c49f244d2 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.cpp +++ b/intern/cycles/integrator/path_trace_work_gpu.cpp @@ -15,12 +15,12 @@ */ #include "integrator/path_trace_work_gpu.h" +#include "integrator/path_trace_display.h" #include "device/device.h" #include "integrator/pass_accessor_gpu.h" #include "render/buffers.h" -#include "render/gpu_display.h" #include "render/scene.h" #include "util/util_logging.h" #include "util/util_tbb.h" @@ -46,7 +46,7 @@ PathTraceWorkGPU::PathTraceWorkGPU(Device *device, queued_paths_(device, "queued_paths", MEM_READ_WRITE), num_queued_paths_(device, "num_queued_paths", MEM_READ_WRITE), work_tiles_(device, "work_tiles", MEM_READ_WRITE), - gpu_display_rgba_half_(device, "display buffer half", MEM_READ_WRITE), + display_rgba_half_(device, "display buffer half", MEM_READ_WRITE), max_num_paths_(queue_->num_concurrent_states(sizeof(IntegratorStateCPU))), min_num_active_paths_(queue_->num_concurrent_busy_states()), max_active_path_index_(0) @@ -652,7 +652,7 @@ int PathTraceWorkGPU::get_num_active_paths() bool PathTraceWorkGPU::should_use_graphics_interop() { /* There are few aspects with the graphics interop when using multiple devices caused by the fact - * that the GPUDisplay has a single texture: + * that the PathTraceDisplay has a single texture: * * CUDA will return `CUDA_ERROR_NOT_SUPPORTED` from `cuGraphicsGLRegisterBuffer()` when * attempting to register OpenGL PBO which has been mapped. Which makes sense, because @@ -678,9 +678,9 @@ bool PathTraceWorkGPU::should_use_graphics_interop() return interop_use_; } -void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) +void PathTraceWorkGPU::copy_to_display(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) { if (device_->have_error()) { /* Don't attempt to update GPU display if the device has errors: the error state will make @@ -694,7 +694,7 @@ void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display, } if (should_use_graphics_interop()) { - if (copy_to_gpu_display_interop(gpu_display, pass_mode, num_samples)) { + if (copy_to_display_interop(display, pass_mode, num_samples)) { return; } @@ -703,12 +703,12 @@ void PathTraceWorkGPU::copy_to_gpu_display(GPUDisplay *gpu_display, interop_use_ = false; } - copy_to_gpu_display_naive(gpu_display, pass_mode, num_samples); + copy_to_display_naive(display, pass_mode, num_samples); } -void PathTraceWorkGPU::copy_to_gpu_display_naive(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) +void PathTraceWorkGPU::copy_to_display_naive(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) { const int full_x = effective_buffer_params_.full_x; const int full_y = effective_buffer_params_.full_y; @@ -725,44 +725,42 @@ void PathTraceWorkGPU::copy_to_gpu_display_naive(GPUDisplay *gpu_display, * NOTE: allocation happens to the final resolution so that no re-allocation happens on every * change of the resolution divider. However, if the display becomes smaller, shrink the * allocated memory as well. */ - if (gpu_display_rgba_half_.data_width != final_width || - gpu_display_rgba_half_.data_height != final_height) { - gpu_display_rgba_half_.alloc(final_width, final_height); + if (display_rgba_half_.data_width != final_width || + display_rgba_half_.data_height != final_height) { + display_rgba_half_.alloc(final_width, final_height); /* TODO(sergey): There should be a way to make sure device-side memory is allocated without * transferring zeroes to the device. */ - queue_->zero_to_device(gpu_display_rgba_half_); + queue_->zero_to_device(display_rgba_half_); } PassAccessor::Destination destination(film_->get_display_pass()); - destination.d_pixels_half_rgba = gpu_display_rgba_half_.device_pointer; + destination.d_pixels_half_rgba = display_rgba_half_.device_pointer; get_render_tile_film_pixels(destination, pass_mode, num_samples); - queue_->copy_from_device(gpu_display_rgba_half_); + queue_->copy_from_device(display_rgba_half_); queue_->synchronize(); - gpu_display->copy_pixels_to_texture( - gpu_display_rgba_half_.data(), texture_x, texture_y, width, height); + display->copy_pixels_to_texture(display_rgba_half_.data(), texture_x, texture_y, width, height); } -bool PathTraceWorkGPU::copy_to_gpu_display_interop(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) +bool PathTraceWorkGPU::copy_to_display_interop(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) { if (!device_graphics_interop_) { device_graphics_interop_ = queue_->graphics_interop_create(); } - const DeviceGraphicsInteropDestination graphics_interop_dst = - gpu_display->graphics_interop_get(); - device_graphics_interop_->set_destination(graphics_interop_dst); + const DisplayDriver::GraphicsInterop graphics_interop_dst = display->graphics_interop_get(); + device_graphics_interop_->set_display_interop(graphics_interop_dst); const device_ptr d_rgba_half = device_graphics_interop_->map(); if (!d_rgba_half) { return false; } - PassAccessor::Destination destination = get_gpu_display_destination_template(gpu_display); + PassAccessor::Destination destination = get_display_destination_template(display); destination.d_pixels_half_rgba = d_rgba_half; get_render_tile_film_pixels(destination, pass_mode, num_samples); @@ -772,14 +770,14 @@ bool PathTraceWorkGPU::copy_to_gpu_display_interop(GPUDisplay *gpu_display, return true; } -void PathTraceWorkGPU::destroy_gpu_resources(GPUDisplay *gpu_display) +void PathTraceWorkGPU::destroy_gpu_resources(PathTraceDisplay *display) { if (!device_graphics_interop_) { return; } - gpu_display->graphics_interop_activate(); + display->graphics_interop_activate(); device_graphics_interop_ = nullptr; - gpu_display->graphics_interop_deactivate(); + display->graphics_interop_deactivate(); } void PathTraceWorkGPU::get_render_tile_film_pixels(const PassAccessor::Destination &destination, diff --git a/intern/cycles/integrator/path_trace_work_gpu.h b/intern/cycles/integrator/path_trace_work_gpu.h index 38788122b0d..9212537d2fd 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.h +++ b/intern/cycles/integrator/path_trace_work_gpu.h @@ -48,10 +48,10 @@ class PathTraceWorkGPU : public PathTraceWork { int start_sample, int samples_num) override; - virtual void copy_to_gpu_display(GPUDisplay *gpu_display, - PassMode pass_mode, - int num_samples) override; - virtual void destroy_gpu_resources(GPUDisplay *gpu_display) override; + virtual void copy_to_display(PathTraceDisplay *display, + PassMode pass_mode, + int num_samples) override; + virtual void destroy_gpu_resources(PathTraceDisplay *display) override; virtual bool copy_render_buffers_from_device() override; virtual bool copy_render_buffers_to_device() override; @@ -88,16 +88,16 @@ class PathTraceWorkGPU : public PathTraceWork { int get_num_active_paths(); - /* Check whether graphics interop can be used for the GPUDisplay update. */ + /* Check whether graphics interop can be used for the PathTraceDisplay update. */ bool should_use_graphics_interop(); - /* Naive implementation of the `copy_to_gpu_display()` which performs film conversion on the - * device, then copies pixels to the host and pushes them to the `gpu_display`. */ - void copy_to_gpu_display_naive(GPUDisplay *gpu_display, PassMode pass_mode, int num_samples); + /* Naive implementation of the `copy_to_display()` which performs film conversion on the + * device, then copies pixels to the host and pushes them to the `display`. */ + void copy_to_display_naive(PathTraceDisplay *display, PassMode pass_mode, int num_samples); - /* Implementation of `copy_to_gpu_display()` which uses driver's OpenGL/GPU interoperability + /* Implementation of `copy_to_display()` which uses driver's OpenGL/GPU interoperability * functionality, avoiding copy of pixels to the host. */ - bool copy_to_gpu_display_interop(GPUDisplay *gpu_display, PassMode pass_mode, int num_samples); + bool copy_to_display_interop(PathTraceDisplay *display, PassMode pass_mode, int num_samples); /* Synchronously run film conversion kernel and store display result in the given destination. */ void get_render_tile_film_pixels(const PassAccessor::Destination &destination, @@ -139,9 +139,9 @@ class PathTraceWorkGPU : public PathTraceWork { /* Temporary buffer for passing work tiles to kernel. */ device_vector work_tiles_; - /* Temporary buffer used by the copy_to_gpu_display() whenever graphics interoperability is not + /* Temporary buffer used by the copy_to_display() whenever graphics interoperability is not * available. Is allocated on-demand. */ - device_vector gpu_display_rgba_half_; + device_vector display_rgba_half_; unique_ptr device_graphics_interop_; diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h index 6ed368a2dc8..c4ab15e54ba 100644 --- a/intern/cycles/integrator/render_scheduler.h +++ b/intern/cycles/integrator/render_scheduler.h @@ -344,7 +344,7 @@ class RenderScheduler { /* Number of rendered samples on top of the start sample. */ int num_rendered_samples = 0; - /* Point in time the latest GPUDisplay work has been scheduled. */ + /* Point in time the latest PathTraceDisplay work has been scheduled. */ double last_display_update_time = 0.0; /* Value of -1 means display was never updated. */ int last_display_update_sample = -1; -- cgit v1.2.3