Blender V5.0
path_trace_display.cpp
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2021-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
6
7#include "session/buffers.h"
9
10#include "util/log.h"
11
13
15{
16}
17
18void PathTraceDisplay::reset(const BufferParams &buffer_params, const bool reset_rendering)
19{
20 const thread_scoped_lock lock(mutex_);
21
22 params_.full_offset = make_int2(buffer_params.full_x + buffer_params.window_x,
23 buffer_params.full_y + buffer_params.window_y);
24 params_.full_size = make_int2(buffer_params.full_width, buffer_params.full_height);
25 params_.size = make_int2(buffer_params.window_width, buffer_params.window_height);
26
27 texture_state_.is_outdated = true;
28
29 if (!reset_rendering) {
30 driver_->next_tile_begin();
31 }
32}
33
34void PathTraceDisplay::mark_texture_updated()
35{
36 texture_state_.is_outdated = false;
37}
38
39/* --------------------------------------------------------------------
40 * Update procedure.
41 */
42
43bool PathTraceDisplay::update_begin(const int texture_width, const int texture_height)
44{
45 DCHECK(!update_state_.is_active);
46
47 if (update_state_.is_active) {
48 LOG_ERROR << "Attempt to re-activate update process.";
49 return false;
50 }
51
52 /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
53 * The update itself is non-blocking however, for better performance and to avoid
54 * potential deadlocks due to locks held by the subclass. */
56 {
57 const thread_scoped_lock lock(mutex_);
58 params = params_;
59 texture_state_.size = make_int2(texture_width, texture_height);
60 }
61
62 if (!driver_->update_begin(params, texture_width, texture_height)) {
63 LOG_ERROR << "PathTraceDisplay implementation could not begin update.";
64 return false;
65 }
66
67 update_state_.is_active = true;
68
69 return true;
70}
71
73{
74 DCHECK(update_state_.is_active);
75
76 if (!update_state_.is_active) {
77 LOG_ERROR << "Attempt to deactivate inactive update process.";
78 return;
79 }
80
81 driver_->update_end();
82
83 update_state_.is_active = false;
84}
85
87{
88 return texture_state_.size;
89}
90
91/* --------------------------------------------------------------------
92 * Texture update from CPU buffer.
93 */
94
96 const int texture_x,
97 const int texture_y,
98 const int pixels_width,
99 const int pixels_height)
100{
101 DCHECK(update_state_.is_active);
102
103 if (!update_state_.is_active) {
104 LOG_ERROR << "Attempt to copy pixels data outside of PathTraceDisplay update.";
105 return;
106 }
107
108 mark_texture_updated();
109
110 /* This call copies pixels to a mapped texture buffer which is typically much cheaper from CPU
111 * time point of view than to copy data directly to a texture.
112 *
113 * The possible downside of this approach is that it might require a higher peak memory when
114 * doing partial updates of the texture (although, in practice even partial updates might peak
115 * with a full-frame buffer stored on the CPU if the GPU is currently occupied). */
116 half4 *mapped_rgba_pixels = map_texture_buffer();
117 if (!mapped_rgba_pixels) {
118 return;
119 }
120
121 const int texture_width = texture_state_.size.x;
122 const int texture_height = texture_state_.size.y;
123
124 if (texture_x == 0 && texture_y == 0 && pixels_width == texture_width &&
125 pixels_height == texture_height)
126 {
127 const size_t size_in_bytes = sizeof(half4) * texture_width * texture_height;
128 memcpy(mapped_rgba_pixels, rgba_pixels, size_in_bytes);
129 }
130 else {
131 const half4 *rgba_row = rgba_pixels;
132 half4 *mapped_rgba_row = mapped_rgba_pixels + texture_y * texture_width + texture_x;
133 for (int y = 0; y < pixels_height;
134 ++y, rgba_row += pixels_width, mapped_rgba_row += texture_width)
135 {
136 memcpy(mapped_rgba_row, rgba_row, sizeof(half4) * pixels_width);
137 }
138 }
139
141}
142
143/* --------------------------------------------------------------------
144 * Texture buffer mapping.
145 */
146
148{
149 DCHECK(!texture_buffer_state_.is_mapped);
150 DCHECK(update_state_.is_active);
151
152 if (texture_buffer_state_.is_mapped) {
153 LOG_ERROR << "Attempt to re-map an already mapped texture buffer.";
154 return nullptr;
155 }
156
157 if (!update_state_.is_active) {
158 LOG_ERROR << "Attempt to copy pixels data outside of PathTraceDisplay update.";
159 return nullptr;
160 }
161
162 half4 *mapped_rgba_pixels = driver_->map_texture_buffer();
163
164 if (mapped_rgba_pixels) {
165 texture_buffer_state_.is_mapped = true;
166 }
167
168 return mapped_rgba_pixels;
169}
170
172{
173 DCHECK(texture_buffer_state_.is_mapped);
174
175 if (!texture_buffer_state_.is_mapped) {
176 LOG_ERROR << "Attempt to unmap non-mapped texture buffer.";
177 return;
178 }
179
180 texture_buffer_state_.is_mapped = false;
181
182 mark_texture_updated();
183 driver_->unmap_texture_buffer();
184}
185
186/* --------------------------------------------------------------------
187 * Graphics interoperability.
188 */
189
191{
192 return driver_->graphics_interop_get_device();
193}
194
196{
197 GraphicsInteropBuffer &interop_buffer = driver_->graphics_interop_get_buffer();
198 DCHECK(!texture_buffer_state_.is_mapped);
199 DCHECK(update_state_.is_active);
200
201 if (texture_buffer_state_.is_mapped) {
203 << "Attempt to use graphics interoperability mode while the texture buffer is mapped.";
204 interop_buffer.clear();
205 return interop_buffer;
206 }
207
208 if (!update_state_.is_active) {
209 LOG_ERROR << "Attempt to use graphics interoperability outside of PathTraceDisplay update.";
210 interop_buffer.clear();
211 return interop_buffer;
212 }
213
214 /* Assume that interop will write new values to the texture. */
215 mark_texture_updated();
216
217 driver_->graphics_interop_update_buffer();
218 return interop_buffer;
219}
220
222{
223 driver_->graphics_interop_activate();
224}
225
227{
228 driver_->graphics_interop_deactivate();
229}
230
231/* --------------------------------------------------------------------
232 * Drawing.
233 */
234
236{
237 driver_->zero();
238}
239
241{
242 /* Get parameters within a mutex lock, to avoid reset() modifying them at the same time.
243 * The drawing itself is non-blocking however, for better performance and to avoid
244 * potential deadlocks due to locks held by the subclass. */
246 bool is_outdated;
247
248 {
249 const thread_scoped_lock lock(mutex_);
250 params = params_;
251 is_outdated = texture_state_.is_outdated;
252 }
253
254 driver_->draw(params);
255
256 return !is_outdated;
257}
258
260{
261 driver_->flush();
262}
263
volatile int lock
int full_width
Definition buffers.h:85
int window_y
Definition buffers.h:78
int full_height
Definition buffers.h:86
int window_height
Definition buffers.h:80
int window_width
Definition buffers.h:79
int window_x
Definition buffers.h:77
void reset(const BufferParams &buffer_params, bool reset_rendering)
int2 get_texture_size() const
PathTraceDisplay(unique_ptr< DisplayDriver > driver)
bool update_begin(const int texture_width, const int texture_height)
void copy_pixels_to_texture(const half4 *rgba_pixels, const int texture_x, const int texture_y, const int pixels_width, const int pixels_height)
GraphicsInteropBuffer & graphics_interop_get_buffer()
GraphicsInteropDevice graphics_interop_get_device()
#define CCL_NAMESPACE_END
ccl_device_forceinline int2 make_int2(const int x, const int y)
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
#define DCHECK(expression)
Definition log.h:135
#define LOG_ERROR
Definition log.h:101
Definition half.h:60
std::unique_lock< std::mutex > thread_scoped_lock
Definition thread.h:28