Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht@blender.org>2021-09-14 16:37:47 +0300
committerBrecht Van Lommel <brecht@blender.org>2021-09-30 21:48:08 +0300
commita754e35198d852ea34e2b82cd2b126538e6f5a3b (patch)
tree9118b3fa19ab70aa1b50440ce62e5d028d940cfd /intern/cycles/render
parentac582056e2e70f3b0d91ff69d0307dd357e2e2ed (diff)
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
Diffstat (limited to 'intern/cycles/render')
-rw-r--r--intern/cycles/render/CMakeLists.txt3
-rw-r--r--intern/cycles/render/display_driver.h131
-rw-r--r--intern/cycles/render/gpu_display.cpp227
-rw-r--r--intern/cycles/render/gpu_display.h247
-rw-r--r--intern/cycles/render/session.cpp8
-rw-r--r--intern/cycles/render/session.h4
6 files changed, 138 insertions, 482 deletions
diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt
index 6edb5261b32..ce1a9e5f430 100644
--- a/intern/cycles/render/CMakeLists.txt
+++ b/intern/cycles/render/CMakeLists.txt
@@ -35,7 +35,6 @@ set(SRC
denoising.cpp
film.cpp
geometry.cpp
- gpu_display.cpp
graph.cpp
hair.cpp
image.cpp
@@ -78,9 +77,9 @@ set(SRC_HEADERS
colorspace.h
constant_fold.h
denoising.h
+ display_driver.h
film.h
geometry.h
- gpu_display.h
graph.h
hair.h
image.h
diff --git a/intern/cycles/render/display_driver.h b/intern/cycles/render/display_driver.h
new file mode 100644
index 00000000000..85f305034d7
--- /dev/null
+++ b/intern/cycles/render/display_driver.h
@@ -0,0 +1,131 @@
+/*
+ * 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 "util/util_half.h"
+#include "util/util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Display driver for efficient interactive display of renders.
+ *
+ * Host applications implement this interface for viewport rendering. For best performance, we
+ * recommend:
+ * - Allocating a texture on the GPU to be interactively updated
+ * - Using the graphics interop mechanism to avoid CPU-GPU copying overhead
+ * - Using a dedicated or thread-safe graphics API context for updates, to avoid
+ * blocking the host application.
+ */
+class DisplayDriver {
+ public:
+ DisplayDriver() = default;
+ virtual ~DisplayDriver() = default;
+
+ /* Render buffer parameters. */
+ struct Params {
+ public:
+ /* Render resolution, ignoring progressive resolution changes.
+ * The texture buffer should be allocated with this size. */
+ int2 size = make_int2(0, 0);
+
+ /* For border rendering, the full resolution of the render, and the offset within that larger
+ * render. */
+ int2 full_size = make_int2(0, 0);
+ int2 full_offset = make_int2(0, 0);
+
+ bool modified(const Params &other) const
+ {
+ return !(full_offset == other.full_offset && full_size == other.full_size &&
+ size == other.size);
+ }
+ };
+
+ /* Update the render from the rendering thread.
+ *
+ * Cycles periodically updates the render to be displayed. For multithreaded updates with
+ * potentially multiple rendering devices, it will call these methods as follows.
+ *
+ * if (driver.update_begin(params, width, height)) {
+ * parallel_for_each(rendering_device) {
+ * buffer = driver.map_texture_buffer();
+ * if (buffer) {
+ * fill(buffer);
+ * driver.unmap_texture_buffer();
+ * }
+ * }
+ * driver.update_end();
+ * }
+ *
+ * The parameters may dynamically change due to camera changes in the scene, and resources should
+ * be re-allocated accordingly.
+ *
+ * The width and height passed to update_begin() are the effective render resolution taking into
+ * account progressive resolution changes, which may be equal to or smaller than the params.size.
+ * For efficiency, changes in this resolution should be handled without re-allocating resources,
+ * but rather by using a subset of the full resolution buffer. */
+ virtual bool update_begin(const Params &params, int width, int height) = 0;
+ virtual void update_end() = 0;
+
+ virtual half4 *map_texture_buffer() = 0;
+ virtual void unmap_texture_buffer() = 0;
+
+ /* Optionally return a handle to a native graphics API texture buffer. If supported,
+ * the rendering device may write directly to this buffer instead of calling
+ * map_texture_buffer() and unmap_texture_buffer(). */
+ class GraphicsInterop {
+ public:
+ /* Dimensions of the buffer, in pixels. */
+ int buffer_width = 0;
+ int buffer_height = 0;
+
+ /* OpenGL pixel buffer object. */
+ int opengl_pbo_id = 0;
+
+ /* Clear the entire buffer before doing partial write to it. */
+ bool need_clear = false;
+ };
+
+ virtual GraphicsInterop graphics_interop_get()
+ {
+ return GraphicsInterop();
+ }
+
+ /* (De)activate graphics context required for editing or deleting the graphics interop
+ * object.
+ *
+ * For example, destruction of the CUDA object associated with an OpenGL requires the
+ * OpenGL context to be active. */
+ virtual void graphics_interop_activate(){};
+ virtual void graphics_interop_deactivate(){};
+
+ /* Clear the display buffer by filling it with zeros. */
+ virtual void clear() = 0;
+
+ /* Draw the render using the native graphics API.
+ *
+ * Note that this may be called in parallel to updates. The implementation is responsible for
+ * mutex locking or other mechanisms to avoid conflicts.
+ *
+ * The parameters may have changed since the last update. The implementation is responsible for
+ * deciding to skip or adjust render display for such changes.
+ *
+ * Host application drawing the render buffer should use Session.draw(), which will
+ * call this method. */
+ virtual void draw(const Params &params) = 0;
+};
+
+CCL_NAMESPACE_END
diff --git a/intern/cycles/render/gpu_display.cpp b/intern/cycles/render/gpu_display.cpp
deleted file mode 100644
index a8f0cc50583..00000000000
--- a/intern/cycles/render/gpu_display.cpp
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * 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 "render/gpu_display.h"
-
-#include "render/buffers.h"
-#include "util/util_logging.h"
-
-CCL_NAMESPACE_BEGIN
-
-void GPUDisplay::reset(const BufferParams &buffer_params)
-{
- thread_scoped_lock lock(mutex_);
-
- const GPUDisplayParams old_params = params_;
-
- params_.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 GPUDisplay::mark_texture_updated()
-{
- texture_state_.is_outdated = false;
- texture_state_.is_usable = true;
-}
-
-/* --------------------------------------------------------------------
- * Update procedure.
- */
-
-bool GPUDisplay::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. */
- GPUDisplayParams params;
- {
- thread_scoped_lock lock(mutex_);
- params = params_;
- texture_state_.size = make_int2(texture_width, texture_height);
- }
-
- if (!do_update_begin(params, texture_width, texture_height)) {
- LOG(ERROR) << "GPUDisplay implementation could not begin update.";
- return false;
- }
-
- update_state_.is_active = true;
-
- return true;
-}
-
-void GPUDisplay::update_end()
-{
- DCHECK(update_state_.is_active);
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to deactivate inactive update process.";
- return;
- }
-
- do_update_end();
-
- update_state_.is_active = false;
-}
-
-int2 GPUDisplay::get_texture_size() const
-{
- return texture_state_.size;
-}
-
-/* --------------------------------------------------------------------
- * Texture update from CPU buffer.
- */
-
-void GPUDisplay::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 GPUDisplay update.";
- return;
- }
-
- mark_texture_updated();
- do_copy_pixels_to_texture(rgba_pixels, texture_x, texture_y, pixels_width, pixels_height);
-}
-
-/* --------------------------------------------------------------------
- * Texture buffer mapping.
- */
-
-half4 *GPUDisplay::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 GPUDisplay update.";
- return nullptr;
- }
-
- half4 *mapped_rgba_pixels = do_map_texture_buffer();
-
- if (mapped_rgba_pixels) {
- texture_buffer_state_.is_mapped = true;
- }
-
- return mapped_rgba_pixels;
-}
-
-void GPUDisplay::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();
- do_unmap_texture_buffer();
-}
-
-/* --------------------------------------------------------------------
- * Graphics interoperability.
- */
-
-DeviceGraphicsInteropDestination GPUDisplay::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 DeviceGraphicsInteropDestination();
- }
-
- if (!update_state_.is_active) {
- LOG(ERROR) << "Attempt to use graphics interoperability outside of GPUDisplay update.";
- return DeviceGraphicsInteropDestination();
- }
-
- /* Assume that interop will write new values to the texture. */
- mark_texture_updated();
-
- return do_graphics_interop_get();
-}
-
-void GPUDisplay::graphics_interop_activate()
-{
-}
-
-void GPUDisplay::graphics_interop_deactivate()
-{
-}
-
-/* --------------------------------------------------------------------
- * Drawing.
- */
-
-bool GPUDisplay::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. */
- GPUDisplayParams 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) {
- do_draw(params);
- }
-
- return !is_outdated;
-}
-
-CCL_NAMESPACE_END
diff --git a/intern/cycles/render/gpu_display.h b/intern/cycles/render/gpu_display.h
deleted file mode 100644
index 3c3cfaea513..00000000000
--- a/intern/cycles/render/gpu_display.h
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * 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 "device/device_graphics_interop.h"
-#include "util/util_half.h"
-#include "util/util_thread.h"
-#include "util/util_types.h"
-
-CCL_NAMESPACE_BEGIN
-
-class BufferParams;
-
-/* GPUDisplay class takes care of drawing render result in a viewport. The render result is stored
- * in a GPU-side texture, which is updated from a path tracer and drawn by an application.
- *
- * The base GPUDisplay does some special texture state tracking, which allows render Session to
- * make decisions on whether reset for an updated state is possible or not. This state should only
- * be tracked in a base class and a particular implementation should not worry about it.
- *
- * The subclasses should only implement the pure virtual methods, which allows them to not worry
- * about parent method calls, which helps them to be as small and reliable as possible. */
-
-class GPUDisplayParams {
- public:
- /* Offset of the display within a viewport.
- * For example, set to a lower-bottom corner of border render in Blender's viewport. */
- int2 offset = make_int2(0, 0);
-
- /* Full viewport size.
- *
- * NOTE: Is not affected by the resolution divider. */
- int2 full_size = make_int2(0, 0);
-
- /* Effective viewport size.
- * In the case of border render, size of the border rectangle.
- *
- * NOTE: Is not affected by the resolution divider. */
- int2 size = make_int2(0, 0);
-
- bool modified(const GPUDisplayParams &other) const
- {
- return !(offset == other.offset && full_size == other.full_size && size == other.size);
- }
-};
-
-class GPUDisplay {
- public:
- GPUDisplay() = default;
- virtual ~GPUDisplay() = 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);
-
- const GPUDisplayParams &get_params() const
- {
- return 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 GPUDisplay 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 GPUDisplay 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 GPUDisplay graphics interoperability information which acts as a destination for the
- * device API. */
- DeviceGraphicsInteropDestination graphics_interop_get();
-
- /* (De)activate GPU display for graphics interoperability outside of regular display update
- * routines. */
- virtual void graphics_interop_activate();
- virtual 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 `DeviceGraphicsInteropDestination`. */
- virtual void clear() = 0;
-
- /* Draw the current state of the texture.
- *
- * Returns true if this call did draw an updated state of the texture. */
- bool draw();
-
- protected:
- /* Implementation-specific calls which subclasses are to implement.
- * These `do_foo()` method corresponds to their `foo()` calls, but they are purely virtual to
- * simplify their particular implementation. */
- virtual bool do_update_begin(const GPUDisplayParams &params,
- int texture_width,
- int texture_height) = 0;
- virtual void do_update_end() = 0;
-
- virtual void do_copy_pixels_to_texture(const half4 *rgba_pixels,
- int texture_x,
- int texture_y,
- int pixels_width,
- int pixels_height) = 0;
-
- virtual half4 *do_map_texture_buffer() = 0;
- virtual void do_unmap_texture_buffer() = 0;
-
- /* Note that this might be called in parallel to do_update_begin() and do_update_end(),
- * the subclass is responsible for appropriate mutex locks to avoid multiple threads
- * editing and drawing the texture at the same time. */
- virtual void do_draw(const GPUDisplayParams &params) = 0;
-
- virtual DeviceGraphicsInteropDestination do_graphics_interop_get() = 0;
-
- private:
- thread_mutex mutex_;
- GPUDisplayParams 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/render/session.cpp b/intern/cycles/render/session.cpp
index 269d67e8bda..c191b9a9b4a 100644
--- a/intern/cycles/render/session.cpp
+++ b/intern/cycles/render/session.cpp
@@ -25,7 +25,7 @@
#include "render/bake.h"
#include "render/buffers.h"
#include "render/camera.h"
-#include "render/gpu_display.h"
+#include "render/display_driver.h"
#include "render/graph.h"
#include "render/integrator.h"
#include "render/light.h"
@@ -162,7 +162,7 @@ bool Session::ready_to_reset()
void Session::run_main_render_loop()
{
- path_trace_->clear_gpu_display();
+ path_trace_->clear_display();
while (true) {
RenderWork render_work = run_update_for_next_iteration();
@@ -514,9 +514,9 @@ void Session::set_pause(bool pause)
}
}
-void Session::set_gpu_display(unique_ptr<GPUDisplay> gpu_display)
+void Session::set_display_driver(unique_ptr<DisplayDriver> driver)
{
- path_trace_->set_gpu_display(move(gpu_display));
+ path_trace_->set_display_driver(move(driver));
}
double Session::get_estimated_remaining_time() const
diff --git a/intern/cycles/render/session.h b/intern/cycles/render/session.h
index e3056e7778b..607e40c47c1 100644
--- a/intern/cycles/render/session.h
+++ b/intern/cycles/render/session.h
@@ -35,9 +35,9 @@ CCL_NAMESPACE_BEGIN
class BufferParams;
class Device;
class DeviceScene;
+class DisplayDriver;
class PathTrace;
class Progress;
-class GPUDisplay;
class RenderBuffers;
class Scene;
class SceneParams;
@@ -143,7 +143,7 @@ class Session {
void set_samples(int samples);
void set_time_limit(double time_limit);
- void set_gpu_display(unique_ptr<GPUDisplay> gpu_display);
+ void set_display_driver(unique_ptr<DisplayDriver> driver);
double get_estimated_remaining_time() const;