Blender V4.3
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 NULL,
56 NULL,
57 GetModuleHandle(NULL),
58 NULL));
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 }
76}
77
78bool HdCyclesDisplayDriver::gl_context_enable()
79{
80#ifdef _WIN32
81 if (!hdc_ || !gl_context_) {
82 return false;
83 }
84
85 mutex_.lock();
86
87 // Do not change context if this is called in the main thread
88 if (wglGetCurrentContext() == nullptr) {
89 if (!TF_VERIFY(wglMakeCurrent((HDC)hdc_, (HGLRC)gl_context_))) {
90 mutex_.unlock();
91 return false;
92 }
93 }
94
95 return true;
96#else
97 return false;
98#endif
99}
100
101void HdCyclesDisplayDriver::gl_context_disable()
102{
103#ifdef _WIN32
104 if (wglGetCurrentContext() == gl_context_) {
105 TF_VERIFY(wglMakeCurrent(nullptr, nullptr));
106 }
107
108 mutex_.unlock();
109#endif
110}
111
112void HdCyclesDisplayDriver::gl_context_dispose()
113{
114#ifdef _WIN32
115 if (gl_context_) {
116 TF_VERIFY(wglDeleteContext((HGLRC)gl_context_));
117 DestroyWindow(WindowFromDC((HDC)hdc_));
118 }
119#endif
120}
121
122void HdCyclesDisplayDriver::next_tile_begin() {}
123
124bool HdCyclesDisplayDriver::update_begin(const Params &params,
125 int texture_width,
126 int texture_height)
127{
128 if (!gl_context_enable()) {
129 return false;
130 }
131
132 if (gl_render_sync_) {
133 glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
134 }
135
136 if (pbo_size_.x != params.full_size.x || pbo_size_.y != params.full_size.y) {
137 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
138 glBufferData(GL_PIXEL_UNPACK_BUFFER,
139 sizeof(half4) * params.full_size.x * params.full_size.y,
140 0,
141 GL_DYNAMIC_DRAW);
142 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
143
144 pbo_size_ = params.full_size;
145 }
146
147 need_update_ = true;
148
149 return true;
150}
151
152void HdCyclesDisplayDriver::update_end()
153{
154 gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
155 glFlush();
156
157 gl_context_disable();
158}
159
160void HdCyclesDisplayDriver::flush()
161{
162 gl_context_enable();
163
164 if (gl_upload_sync_) {
165 glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
166 }
167
168 if (gl_render_sync_) {
169 glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
170 }
171
172 gl_context_disable();
173}
174
175half4 *HdCyclesDisplayDriver::map_texture_buffer()
176{
177 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
178
179 const auto mapped_rgba_pixels = static_cast<half4 *>(
180 glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
181
182 if (need_clear_ && mapped_rgba_pixels) {
183 memset(mapped_rgba_pixels, 0, sizeof(half4) * pbo_size_.x * pbo_size_.y);
184 need_clear_ = false;
185 }
186
187 return mapped_rgba_pixels;
188}
189
190void HdCyclesDisplayDriver::unmap_texture_buffer()
191{
192 glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
193
194 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
195}
196
197DisplayDriver::GraphicsInterop HdCyclesDisplayDriver::graphics_interop_get()
198{
199 GraphicsInterop interop_dst;
200 interop_dst.buffer_width = pbo_size_.x;
201 interop_dst.buffer_height = pbo_size_.y;
202 interop_dst.opengl_pbo_id = gl_pbo_id_;
203
204 interop_dst.need_clear = need_clear_;
205 need_clear_ = false;
206
207 return interop_dst;
208}
209
210void HdCyclesDisplayDriver::graphics_interop_activate()
211{
212 gl_context_enable();
213}
214
215void HdCyclesDisplayDriver::graphics_interop_deactivate()
216{
217 gl_context_disable();
218}
219
220void HdCyclesDisplayDriver::clear()
221{
222 need_clear_ = true;
223}
224
225void HdCyclesDisplayDriver::draw(const Params &params)
226{
227 const auto renderBuffer = static_cast<HdCyclesRenderBuffer *>(
228 _renderParam->GetDisplayAovBinding().renderBuffer);
229 if (!renderBuffer || // Ensure this render buffer matches the texture dimensions
230 (renderBuffer->GetWidth() != params.size.x || renderBuffer->GetHeight() != params.size.y))
231 {
232 return;
233 }
234
235 if (!renderBuffer->IsResourceUsed()) {
236 return;
237 }
238
239 gl_context_create();
240
241 // Cycles 'DisplayDriver' only supports 'half4' format
242 TF_VERIFY(renderBuffer->GetFormat() == HdFormatFloat16Vec4);
243
244 const thread_scoped_lock lock(mutex_);
245
246 const GfVec3i dimensions(params.size.x, params.size.y, 1);
247 if (!texture_ || texture_->GetDescriptor().dimensions != dimensions) {
248 if (texture_) {
249 _hgi->DestroyTexture(&texture_);
250 }
251
252 HgiTextureDesc texDesc;
253 texDesc.usage = 0;
254 texDesc.format = HgiFormatFloat16Vec4;
255 texDesc.type = HgiTextureType2D;
256 texDesc.dimensions = dimensions;
257 texDesc.sampleCount = HgiSampleCount1;
258
259 texture_ = _hgi->CreateTexture(texDesc);
260
261 renderBuffer->SetResource(VtValue(texture_));
262 }
263
264 HgiGLTexture *const texture = dynamic_cast<HgiGLTexture *>(texture_.Get());
265 if (!texture || !need_update_ || pbo_size_.x != params.size.x || pbo_size_.y != params.size.y) {
266 return;
267 }
268
269 if (gl_upload_sync_) {
270 glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
271 }
272
273 glBindTexture(GL_TEXTURE_2D, texture->GetTextureId());
274 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl_pbo_id_);
275 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pbo_size_.x, pbo_size_.y, GL_RGBA, GL_HALF_FLOAT, 0);
276 glBindTexture(GL_TEXTURE_2D, 0);
277 glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
278
279 gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
280 glFlush();
281
282 need_update_ = false;
283}
284
volatile int lock
HdCyclesDisplayDriver(HdCyclesSession *renderParam, Hgi *hgi)
PXR_NS::HdRenderPassAovBinding GetDisplayAovBinding() const
#define NULL
#define HDCYCLES_NAMESPACE_CLOSE_SCOPE
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
Definition half.h:61
std::unique_lock< std::mutex > thread_scoped_lock
Definition thread.h:30