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