Blender  V3.3
hydra/display_driver.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2022 NVIDIA Corporation
3  * Copyright 2022 Blender Foundation */
4 
5 #ifdef _WIN32
6 // Include first to avoid "NOGDI" definition set in Cycles headers
7 # include <Windows.h>
8 #endif
9 
10 #include "hydra/display_driver.h"
11 #include "hydra/render_buffer.h"
12 #include "hydra/session.h"
13 
14 #include <GL/glew.h>
15 #include <pxr/imaging/hgiGL/texture.h>
16 
18 
20  : _renderParam(renderParam), _hgi(hgi)
21 {
22 }
23 
25 {
26  if (texture_) {
27  _hgi->DestroyTexture(&texture_);
28  }
29 
30  if (gl_pbo_id_) {
31  glDeleteBuffers(1, &gl_pbo_id_);
32  }
33 
34  gl_context_dispose();
35 }
36 
37 void HdCyclesDisplayDriver::gl_context_create()
38 {
39 #ifdef _WIN32
40  if (!gl_context_) {
41  hdc_ = GetDC(CreateWindowA("STATIC",
42  "HdCycles",
43  WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
44  0,
45  0,
46  64,
47  64,
48  NULL,
49  NULL,
50  GetModuleHandle(NULL),
51  NULL));
52 
53  int pixelFormat = GetPixelFormat(wglGetCurrentDC());
54  PIXELFORMATDESCRIPTOR pfd = {sizeof(pfd)};
55  DescribePixelFormat((HDC)hdc_, pixelFormat, sizeof(pfd), &pfd);
56  SetPixelFormat((HDC)hdc_, pixelFormat, &pfd);
57 
58  TF_VERIFY(gl_context_ = wglCreateContext((HDC)hdc_));
59  TF_VERIFY(wglShareLists(wglGetCurrentContext(), (HGLRC)gl_context_));
60  }
61  if (!gl_context_) {
62  return;
63  }
64 #endif
65 
66  if (!gl_pbo_id_) {
67  if (glewInit() != GLEW_OK) {
68  return;
69  }
70 
71  glGenBuffers(1, &gl_pbo_id_);
72  }
73 }
74 
75 bool HdCyclesDisplayDriver::gl_context_enable()
76 {
77 #ifdef _WIN32
78  if (!hdc_ || !gl_context_) {
79  return false;
80  }
81 
82  mutex_.lock();
83 
84  // Do not change context if this is called in the main thread
85  if (wglGetCurrentContext() == nullptr) {
86  if (!TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_))) {
87  mutex_.unlock();
88  return false;
89  }
90  }
91 
92  return true;
93 #else
94  return false;
95 #endif
96 }
97 
98 void HdCyclesDisplayDriver::gl_context_disable()
99 {
100 #ifdef _WIN32
101  if (wglGetCurrentContext() == gl_context_) {
102  TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
103  }
104 
105  mutex_.unlock();
106 #endif
107 }
108 
109 void HdCyclesDisplayDriver::gl_context_dispose()
110 {
111 #ifdef _WIN32
112  if (gl_context_) {
113  TF_VERIFY(wglDeleteContext((HGLRC)gl_context_));
114  DestroyWindow(WindowFromDC((HDC)hdc_));
115  }
116 #endif
117 }
118 
119 void HdCyclesDisplayDriver::next_tile_begin()
120 {
121 }
122 
123 bool HdCyclesDisplayDriver::update_begin(const Params &params,
124  int texture_width,
125  int texture_height)
126 {
127  if (!gl_context_enable()) {
128  return false;
129  }
130 
131  if (gl_render_sync_) {
132  glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
133  }
134 
135  if (pbo_size_.x != params.full_size.x || pbo_size_.y != params.full_size.y) {
136  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
137  glBufferData(GL_PIXEL_UNPACK_BUFFER,
138  sizeof(half4) * params.full_size.x * params.full_size.y,
139  0,
140  GL_DYNAMIC_DRAW);
141  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
142 
143  pbo_size_ = params.full_size;
144  }
145 
146  need_update_ = true;
147 
148  return true;
149 }
150 
151 void HdCyclesDisplayDriver::update_end()
152 {
153  gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
154  glFlush();
155 
156  gl_context_disable();
157 }
158 
159 void HdCyclesDisplayDriver::flush()
160 {
161  gl_context_enable();
162 
163  if (gl_upload_sync_) {
164  glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
165  }
166 
167  if (gl_render_sync_) {
168  glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
169  }
170 
171  gl_context_disable();
172 }
173 
174 half4 *HdCyclesDisplayDriver::map_texture_buffer()
175 {
176  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
177 
178  const auto mapped_rgba_pixels = static_cast<half4 *>(
179  glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
180 
181  if (need_clear_ && mapped_rgba_pixels) {
182  memset(mapped_rgba_pixels, 0, sizeof(half4) * pbo_size_.x * pbo_size_.y);
183  need_clear_ = false;
184  }
185 
186  return mapped_rgba_pixels;
187 }
188 
189 void HdCyclesDisplayDriver::unmap_texture_buffer()
190 {
191  glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
192 
193  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
194 }
195 
196 DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get()
197 {
198  GraphicsInterop interop_dst;
199  interop_dst.buffer_width = pbo_size_.x;
200  interop_dst.buffer_height = pbo_size_.y;
201  interop_dst.opengl_pbo_id = gl_pbo_id_;
202 
203  interop_dst.need_clear = need_clear_;
204  need_clear_ = false;
205 
206  return interop_dst;
207 }
208 
209 void HdCyclesDisplayDriver::graphics_interop_activate()
210 {
211  gl_context_enable();
212 }
213 
214 void HdCyclesDisplayDriver::graphics_interop_deactivate()
215 {
216  gl_context_disable();
217 }
218 
219 void HdCyclesDisplayDriver::clear()
220 {
221  need_clear_ = true;
222 }
223 
224 void HdCyclesDisplayDriver::draw(const Params &params)
225 {
226  const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(
227  _renderParam->GetDisplayAovBinding().renderBuffer);
228  if (!renderBuffer || // Ensure this render buffer matches the texture dimensions
229  (renderBuffer->GetWidth() != params.size.x || renderBuffer->GetHeight() != params.size.y)) {
230  return;
231  }
232 
233  if (!renderBuffer->IsResourceUsed()) {
234  return;
235  }
236 
237  gl_context_create();
238 
239  // Cycles 'DisplayDriver' only supports 'half4' format
240  TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4);
241 
242  const thread_scoped_lock lock(mutex_);
243 
244  const GfVec3i dimensions(params.size.x, params.size.y, 1);
245  if (!texture_ || texture_->GetDescriptor().dimensions != dimensions) {
246  if (texture_) {
247  _hgi->DestroyTexture(&texture_);
248  }
249 
250  HgiTextureDesc texDesc;
251  texDesc.usage = 0;
252  texDesc.format = HgiFormatFloat16Vec4;
253  texDesc.type = HgiTextureType2D;
254  texDesc.dimensions = dimensions;
255  texDesc.sampleCount = HgiSampleCount1;
256 
257  texture_ = _hgi->CreateTexture(texDesc);
258 
259  renderBuffer->SetResource(VtValue(texture_));
260  }
261 
262  HgiGLTexture *const texture = dynamic_cast<HgiGLTexture *>(texture_.Get());
263  if (!texture || !need_update_ || pbo_size_.x != params.size.x || pbo_size_.y != params.size.y) {
264  return;
265  }
266 
267  if (gl_upload_sync_) {
268  glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
269  }
270 
271  glBindTexture(GL_TEXTURE_2D, texture->GetTextureId());
272  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
273  glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pbo_size_.x, pbo_size_.y, GL_RGBA, GL_HALF_FLOAT, 0);
274  glBindTexture(GL_TEXTURE_2D, 0);
275  glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
276 
277  gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
278  glFlush();
279 
280  need_update_ = false;
281 }
282 
volatile int lock
HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *hgi)
PXR_NS::HdRenderPassAovBinding GetDisplayAovBinding() const
Definition: hydra/session.h:42
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
Definition: hydra/config.h:17
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Definition: half.h:64
std::unique_lock< std::mutex > thread_scoped_lock
Definition: thread.h:28