Panda3D
Loading...
Searching...
No Matches
wglGraphicsBuffer.cxx
Go to the documentation of this file.
1/**
2 * PANDA 3D SOFTWARE
3 * Copyright (c) Carnegie Mellon University. All rights reserved.
4 *
5 * All use of this software is subject to the terms of the revised BSD
6 * license. You should have received a copy of this license along
7 * with this source code in a file named "LICENSE."
8 *
9 * @file wglGraphicsBuffer.cxx
10 * @author drose
11 * @date 2004-02-08
12 */
13
14#include "wglGraphicsBuffer.h"
15#include "wglGraphicsPipe.h"
16#include "config_wgldisplay.h"
17#include "glgsg.h"
19#include "pStatTimer.h"
20
21#include <wingdi.h>
22
23TypeHandle wglGraphicsBuffer::_type_handle;
24
25
26/**
27 *
28 */
29wglGraphicsBuffer::
30wglGraphicsBuffer(GraphicsEngine *engine, GraphicsPipe *pipe,
31 const std::string &name,
32 const FrameBufferProperties &fb_prop,
33 const WindowProperties &win_prop,
34 int flags,
36 GraphicsOutput *host) :
37 GraphicsBuffer(engine, pipe, name, fb_prop, win_prop, flags, gsg, host)
38{
39 _pbuffer = (HPBUFFERARB)0;
40 _pbuffer_dc = (HDC)0;
41 release_pbuffer();
42
43 // Since the pbuffer never gets flipped, we get screenshots from the same
44 // buffer we draw into.
45 _screenshot_buffer_type = _draw_buffer_type;
46}
47
48/**
49 *
50 */
51wglGraphicsBuffer::
52~wglGraphicsBuffer() {
53}
54
55/**
56 * This function will be called within the draw thread before beginning
57 * rendering for a given frame. It should do whatever setup is required, and
58 * return true if the frame should be rendered, or false if it should be
59 * skipped.
60 */
62begin_frame(FrameMode mode, Thread *current_thread) {
63
64 begin_frame_spam(mode);
65 if (_gsg == nullptr) {
66 return false;
67 }
68
70 DCAST_INTO_R(wglgsg, _gsg, false);
71
72 HGLRC context = wglgsg->get_context(_pbuffer_dc);
73 if (context == 0) {
74 return false;
75 }
76
77 if (_pbuffer_bound) {
78 if (_fb_properties.is_single_buffered()) {
79 wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
80 } else {
81 wglgsg->_wglReleaseTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
82 }
83 }
84
85 if (!rebuild_bitplanes()) {
86 wglGraphicsPipe::wgl_make_current(0, 0, &_make_current_pcollector);
87 return false;
88 }
89
90 wglGraphicsPipe::wgl_make_current(_pbuffer_dc, context,
91 &_make_current_pcollector);
92
93 if (mode == FM_render) {
94 CDLockedReader cdata(_cycler);
95 for (size_t i = 0; i != cdata->_textures.size(); ++i) {
96 const RenderTexture &rt = cdata->_textures[i];
97 RenderTextureMode rtm_mode = rt._rtm_mode;
98 RenderTexturePlane plane = rt._plane;
99 if (rtm_mode == RTM_bind_or_copy && plane != RTP_color) {
100 CDWriter cdataw(_cycler, cdata, false);
101 nassertr(cdata->_textures.size() == cdataw->_textures.size(), false);
102 cdataw->_textures[i]._rtm_mode = RTM_copy_texture;
103 }
104 }
105 clear_cube_map_selection();
106 }
107
108 _gsg->set_current_properties(&get_fb_properties());
109 return _gsg->begin_frame(current_thread);
110}
111
112/**
113 * This function will be called within the draw thread after rendering is
114 * completed for a given frame. It should do whatever finalization is
115 * required.
116 */
118end_frame(FrameMode mode, Thread *current_thread) {
119 end_frame_spam(mode);
120 nassertv(_gsg != nullptr);
121
122 if (mode == FM_render) {
123 copy_to_textures();
124 bind_texture_to_pbuffer();
125 }
126
127 _gsg->end_frame(current_thread);
128
129 if (mode == FM_render) {
130 trigger_flip();
131 clear_cube_map_selection();
132 }
133}
134
135/**
136 * Looks for the appropriate texture, and binds that texture to the pbuffer.
137 */
138void wglGraphicsBuffer::
139bind_texture_to_pbuffer() {
141 DCAST_INTO_V(wglgsg, _gsg);
142
143 // Find the color texture, if there is one. That one can be bound to the
144 // framebuffer. All others must be marked RTM_copy_to_texture.
145
146 int tex_index = -1;
147 CDLockedReader cdata(_cycler);
148 for (size_t i = 0; i != cdata->_textures.size(); ++i) {
149 const RenderTexture &rt = cdata->_textures[i];
150 RenderTexturePlane plane = rt._plane;
151 if (plane == RTP_color && rt._rtm_mode == RTM_bind_or_copy) {
152 tex_index = i;
153 break;
154 }
155 }
156
157 if (tex_index >= 0) {
158 const RenderTexture &rt = cdata->_textures[tex_index];
159 Texture *tex = rt._texture;
160 if ((_pbuffer_bound != 0)&&(_pbuffer_bound != tex)) {
161 _pbuffer_bound->release(wglgsg->get_prepared_objects());
162 _pbuffer_bound = 0;
163 }
165
166 if (tex->get_match_framebuffer_format()) {
167 if (_fb_properties.get_alpha_bits()) {
168 tex->set_format(Texture::F_rgba);
169 } else {
170 tex->set_format(Texture::F_rgb);
171 }
172 }
173 TextureContext *tc = tex->prepare_now(0, _gsg->get_prepared_objects(), _gsg);
174 nassertv(tc != nullptr);
175 CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
176 GLenum target = wglgsg->get_texture_target(tex->get_texture_type());
177 if (target == GL_NONE) {
178 CDWriter cdataw(_cycler, cdata, false);
179 nassertv(cdata->_textures.size() == cdataw->_textures.size());
180 cdataw->_textures[tex_index]._rtm_mode = RTM_copy_texture;
181 return;
182 }
183 GLP(BindTexture)(target, gtc->_index);
184 if (_fb_properties.is_single_buffered()) {
185 wglgsg->_wglBindTexImageARB(_pbuffer, WGL_FRONT_LEFT_ARB);
186 } else {
187 wglgsg->_wglBindTexImageARB(_pbuffer, WGL_BACK_LEFT_ARB);
188 }
189 _pbuffer_bound = tex;
190 } else {
191 if (_pbuffer_bound != 0) {
192 _pbuffer_bound->release(wglgsg->get_prepared_objects());
193 _pbuffer_bound = 0;
194 }
195 }
196}
197
198/**
199 * Called internally when the window is in render-to-a-texture mode and we are
200 * in the process of rendering the six faces of a cube map. This should do
201 * whatever needs to be done to switch the buffer to the indicated face.
202 */
204select_target_tex_page(int page) {
206 DCAST_INTO_V(wglgsg, _gsg);
207
208 nassertv(wglgsg->_wglSetPbufferAttribARB != nullptr);
209
210 static const int max_attrib_list = 64;
211 int iattrib_list[max_attrib_list];
212 int ni = 0;
213
214 iattrib_list[ni++] = WGL_CUBE_MAP_FACE_ARB;
215 iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB + page;
216
217 // Terminate the list.
218 nassertv(ni <= max_attrib_list);
219 iattrib_list[ni] = 0;
220
221 wglgsg->_wglSetPbufferAttribARB(_pbuffer, iattrib_list);
222}
223
224/**
225 * Do whatever processing is necessary to ensure that the window responds to
226 * user events. Also, honor any requests recently made via
227 * request_properties()
228 *
229 * This function is called only within the window thread.
230 */
234
235 MSG msg;
236
237 // Handle all the messages on the queue in a row. Some of these might be
238 // for another window, but they will get dispatched appropriately.
239 while (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
240 process_1_event();
241 }
242}
243
244/**
245 * Returns true if this particular GraphicsOutput can render directly into a
246 * texture, or false if it must always copy-to-texture at the end of each
247 * frame to achieve this effect.
248 */
251 if (_gsg == nullptr) {
252 return false;
253 }
254
256 DCAST_INTO_R(wglgsg, _gsg, false);
257 return wglgsg->get_supports_wgl_render_texture();
258}
259
260/**
261 * Closes the buffer right now. Called from the window thread.
262 */
263void wglGraphicsBuffer::
264close_buffer() {
265 if (_gsg != nullptr) {
267 DCAST_INTO_V(wglgsg, _gsg);
268
269 _gsg.clear();
270 }
271
272 release_pbuffer();
273
274 _is_valid = false;
275}
276
277/**
278 * Opens the window right now. Called from the window thread. Returns true
279 * if the window is successfully opened, or false if there was a problem.
280 */
281bool wglGraphicsBuffer::
282open_buffer() {
283
284 // pbuffers don't seem to work correctly in double-buffered mode. Besides,
285 // the back buffer is a pointless waste of space. So always use a single-
286 // buffered gsg.
287
288 _fb_properties.set_back_buffers(0);
289 _draw_buffer_type = RenderBuffer::T_front;
290 _screenshot_buffer_type = RenderBuffer::T_front;
291
292 // GSG creationinitialization.
293
295 if (_gsg == 0) {
296 // There is no old gsg. Create a new one.
297 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, nullptr);
298 wglgsg->choose_pixel_format(_fb_properties, true);
299 _gsg = wglgsg;
300 } else {
301 // If the old gsg has the wrong pixel format, create a new one that shares
302 // with the old gsg.
303 DCAST_INTO_R(wglgsg, _gsg, false);
304 if ((!wglgsg->get_fb_properties().subsumes(_fb_properties))||
305 (!wglgsg->get_fb_properties().is_single_buffered())||
306 (!wglgsg->pfnum_supports_pbuffer())) {
307 wglgsg = new wglGraphicsStateGuardian(_engine, _pipe, wglgsg);
308 wglgsg->choose_pixel_format(_fb_properties, true);
309 _gsg = wglgsg;
310 }
311 }
312
313 // Use the temp window to initialize the gsg.
314
315 HDC twindow_dc = wglgsg->get_twindow_dc();
316 if (twindow_dc == 0) {
317 // If we couldn't make a window, we can't get a GL context.
318 _gsg = nullptr;
319 return false;
320 }
321 HGLRC context = wglgsg->get_context(twindow_dc);
322 if (context == 0) {
323 _gsg = nullptr;
324 return false;
325 }
326 wglGraphicsPipe::wgl_make_current(twindow_dc, context,
327 &_make_current_pcollector);
328 wglgsg->reset_if_new();
329 wglgsg->report_my_gl_errors();
331 (_fb_properties,wglgsg->get_gl_renderer())) {
332 _gsg = nullptr;
333 return false;
334 }
335 _fb_properties = wglgsg->get_fb_properties();
336
337 // Now that we have fully made a window and used that window to create a
338 // rendering context, we can attempt to create a pbuffer. This might fail
339 // if the pbuffer extensions are not supported.
340
341 if (!rebuild_bitplanes()) {
342 wglGraphicsPipe::wgl_make_current(0, 0, &_make_current_pcollector);
343 _gsg = nullptr;
344 return false;
345 }
346
347 _is_valid = true;
348
349 return true;
350}
351
352/**
353 * Destroys the pbuffer if it has been created. The intent is that this may
354 * allow it to be recreated with different options.
355 */
356void wglGraphicsBuffer::
357release_pbuffer() {
358 if (_gsg == 0) {
359 return;
360 }
361
363 DCAST_INTO_V(wglgsg, _gsg);
364
365 if (_pbuffer_bound != 0) {
366 _pbuffer_bound->release(wglgsg->get_prepared_objects());
367 _pbuffer_bound = 0;
368 }
369 wglGraphicsPipe::wgl_make_current(0, 0, nullptr);
370 if (_pbuffer_dc) {
371 wglgsg->_wglReleasePbufferDCARB(_pbuffer, _pbuffer_dc);
372 }
373 if (_pbuffer) {
374 wglgsg->_wglDestroyPbufferARB(_pbuffer);
375 }
376 _pbuffer = (HPBUFFERARB)0;
377 _pbuffer_dc = (HDC)0;
378 _pbuffer_mipmap = false;
379 _pbuffer_sizex = 0;
380 _pbuffer_sizey = 0;
381 _pbuffer_type = Texture::TT_2d_texture;
382}
383
384/**
385 * Once the GL context has been fully realized, attempts to create an
386 * offscreen pbuffer if the graphics API supports it. Returns true if
387 * successful, false on failure.
388 */
389bool wglGraphicsBuffer::
390rebuild_bitplanes() {
392 DCAST_INTO_R(wglgsg, _gsg, false);
393
394 if (!wglgsg->_supports_pbuffer) {
395 wgldisplay_cat.info()
396 << "PBuffers not supported by GL implementation.\n";
397 return false;
398 }
399
400 // Find the texture to bind to the color buffer.
401 Texture *bindtexture = nullptr;
402 for (int i=0; i<count_textures(); i++) {
403 if ((get_rtm_mode(i) == RTM_bind_or_copy)&&
404 (get_texture(i)->get_format() != Texture::F_depth_stencil)) {
405 bindtexture = get_texture(i);
406 break;
407 }
408 }
409
410 // If we already have a pbuffer, and if it's lost, then force the rebuild.
411
412 if (_pbuffer_dc) {
413 int flag = 0;
414 wglgsg->_wglQueryPbufferARB(_pbuffer, WGL_PBUFFER_LOST_ARB, &flag);
415 if (flag != 0) {
416 release_pbuffer();
417 }
418 }
419
420 // Determine what pbuffer attributes are needed for currently-applicable
421 // textures.
422
423 if ((_host != 0)&&(_creation_flags & GraphicsPipe::BF_size_track_host)) {
424 if (_host->get_size() != _size) {
425 set_size_and_recalc(_host->get_x_size(),
426 _host->get_y_size());
427 }
428 }
429 int desired_x = get_x_size();
430 int desired_y = get_y_size();
431 if ((bindtexture != 0)&&(Texture::get_textures_power_2() != ATS_none)) {
432 desired_x = Texture::up_to_power_2(desired_x);
433 desired_y = Texture::up_to_power_2(desired_y);
434 }
435 bool desired_mipmap = false;
436 Texture::TextureType desired_type = Texture::TT_2d_texture;
437 if (bindtexture != 0) {
438 desired_mipmap = bindtexture->uses_mipmaps();
439 desired_type = bindtexture->get_texture_type();
440 }
441
442 if ((_pbuffer != 0)&&
443 (_pbuffer_sizex == desired_x)&&
444 (_pbuffer_sizey == desired_y)&&
445 (_pbuffer_mipmap == desired_mipmap)&&
446 (_pbuffer_type == desired_type)) {
447 // the pbuffer we already have is fine. Do not rebuild.
448 return true;
449 }
450
451 // Release the old pbuffer, if there was one.
452
453 release_pbuffer();
454
455 // Allocate the new pbuffer.
456
457 int pfnum = wglgsg->get_pfnum();
458
459 static const int max_attrib_list = 64;
460 int iattrib_list[max_attrib_list];
461 int ni = 0;
462
463 if (_fb_properties.get_alpha_bits()) {
464 iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
465 iattrib_list[ni++] = WGL_TEXTURE_RGBA_ARB;
466 } else {
467 iattrib_list[ni++] = WGL_TEXTURE_FORMAT_ARB;
468 iattrib_list[ni++] = WGL_TEXTURE_RGB_ARB;
469 }
470
471 if (desired_mipmap) {
472 iattrib_list[ni++] = WGL_MIPMAP_TEXTURE_ARB;
473 iattrib_list[ni++] = 1;
474 }
475
476 switch (desired_type) {
477 case Texture::TT_cube_map:
478 iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
479 iattrib_list[ni++] = WGL_TEXTURE_CUBE_MAP_ARB;
480 break;
481
482 case Texture::TT_1d_texture:
483 iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
484 iattrib_list[ni++] = WGL_TEXTURE_1D_ARB;
485 break;
486
487 default:
488 iattrib_list[ni++] = WGL_TEXTURE_TARGET_ARB;
489 iattrib_list[ni++] = WGL_TEXTURE_2D_ARB;
490 }
491
492 // Terminate the list.
493 nassertr(ni <= max_attrib_list, false);
494 iattrib_list[ni] = 0;
495
496 HDC twindow_dc = wglgsg->get_twindow_dc();
497 if (twindow_dc == 0) {
498 return false;
499 }
500
501 HGLRC context = wglgsg->get_context(twindow_dc);
502 if (context == 0) {
503 return false;
504 }
505 wglGraphicsPipe::wgl_make_current(twindow_dc, context,
506 &_make_current_pcollector);
507
508 _pbuffer = wglgsg->_wglCreatePbufferARB(twindow_dc, pfnum,
509 desired_x, desired_y, iattrib_list);
510
511 if (_pbuffer == 0) {
512 wgldisplay_cat.info()
513 << "Attempt to create pbuffer failed.\n";
514 return false;
515 }
516
517 _pbuffer_dc = wglgsg->_wglGetPbufferDCARB(_pbuffer);
518 _pbuffer_mipmap = desired_mipmap;
519 _pbuffer_type = desired_type;
520 _pbuffer_sizex = desired_x;
521 _pbuffer_sizey = desired_y;
522
523 return true;
524}
525
526/**
527 * Handles one event from the message queue.
528 */
529void wglGraphicsBuffer::
530process_1_event() {
531 MSG msg;
532
533 if (!GetMessage(&msg, nullptr, 0, 0)) {
534 // WM_QUIT received. We need a cleaner way to deal with this.
535 // DestroyAllWindows(false);
536 exit(msg.wParam); // this will invoke AtExitFn
537 }
538
539 // Translate virtual key messages
540 TranslateMessage(&msg);
541 // Call window_proc
542 DispatchMessage(&msg);
543}
This template class calls PipelineCycler::read() in the constructor and PipelineCycler::release_read(...
This template class calls PipelineCycler::write() in the constructor and PipelineCycler::release_writ...
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
bool verify_hardware_software(const FrameBufferProperties &props, const std::string &renderer) const
Validates that the properties represent the desired kind of renderer (hardware or software).
bool subsumes(const FrameBufferProperties &other) const
Returns true if this set of properties makes strictly greater or equal demands of the framebuffer tha...
An offscreen buffer for rendering into.
virtual void process_events()
Honor any requests recently made via request_open() or request_close().
This class is the main interface to controlling the render process.
This is a base class for the various different classes that represent the result of a frame of render...
int count_textures() const
If the GraphicsOutput is set to render into a texture, returns the number of textures that are being ...
const FrameBufferProperties & get_fb_properties() const
Returns the framebuffer properties of the window.
void set_size_and_recalc(int x, int y)
Changes the x_size and y_size, then recalculates structures that depend on size.
int get_y_size() const
Returns the visible height of the window or buffer, if it is known.
RenderTextureMode get_rtm_mode(int i=0) const
Returns the RenderTextureMode associated with the nth render-texture.
int get_x_size() const
Returns the visible width of the window or buffer, if it is known.
virtual Texture * get_texture(int i=0) const
Returns the nth texture into which the GraphicsOutput renders.
An object to create GraphicsOutputs that share a particular 3-D API.
Encapsulates all the communication with a particular instance of a given rendering backend.
This is a special class object that holds all the information returned by a particular GSG to indicat...
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition texture.h:72
get_format
Returns the format of the texture, which represents both the semantic meaning of the texels and,...
Definition texture.h:371
TextureContext * prepare_now(int view, PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg)
Creates a context for the texture on the particular GSG, if it does not already exist.
Definition texture.cxx:1981
get_texture_type
Returns the overall interpretation of the texture.
Definition texture.h:366
set_format
Changes the format value for the texture components.
Definition texture.h:371
get_match_framebuffer_format
Returns true if the special flag was set that indicates to the GSG that the Texture's format should b...
Definition texture.h:592
static int up_to_power_2(int value)
Returns the smallest power of 2 greater than or equal to value.
Definition texture.cxx:2008
static AutoTextureScale get_textures_power_2()
This flag returns ATS_none, ATS_up, or ATS_down and controls the scaling of textures in general.
Definition texture.I:1864
bool release(PreparedGraphicsObjects *prepared_objects)
Frees the texture context only on the indicated object, if it exists there.
Definition texture.cxx:1573
bool uses_mipmaps() const
Returns true if the minfilter settings on this texture indicate the use of mipmapping,...
Definition texture.I:1128
void set_size_padded(int x=1, int y=1, int z=1)
Changes the size of the texture, padding if necessary, and setting the pad region as well.
Definition texture.cxx:1932
A thread; that is, a lightweight process.
Definition thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A container for the various kinds of properties we might ask to have on a graphics window before we o...
virtual bool begin_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread before beginning rendering for a given frame.
virtual void end_frame(FrameMode mode, Thread *current_thread)
This function will be called within the draw thread after rendering is completed for a given frame.
virtual void select_target_tex_page(int page)
Called internally when the window is in render-to-a-texture mode and we are in the process of renderi...
virtual bool get_supports_render_texture() const
Returns true if this particular GraphicsOutput can render directly into a texture,...
virtual void process_events()
Do whatever processing is necessary to ensure that the window responds to user events.
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
HDC get_twindow_dc()
Returns the DC associated with the temporary, invisible window that was created with the gsg to query...
bool get_supports_wgl_render_texture() const
Returns true if this particular GSG can render from a wglGraphicsBuffer directly into a texture,...
void choose_pixel_format(const FrameBufferProperties &properties, bool need_pbuffer)
Selects a pixel format for all the windows and buffers that use this gsg.
int get_pfnum() const
Returns the pixel format number chosen for windows that use this context.
bool pfnum_supports_pbuffer() const
Returns true if the gsg's pixel format is capable of supporting a pbuffer.
const FrameBufferProperties & get_fb_properties() const
Returns the properties of the pixel format that was chosen for this gsg.
HGLRC get_context(HDC hdc)
Returns the GL context associated with the GSG.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.