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

gpu_display.h « render « cycles « intern - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: 3c3cfaea513d4a3b4fc05b70532aa57fbe3765d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
/*
 * 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