Panda3D
osxGraphicsStateGuardian.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 osxGraphicsStateGuardian.cxx
10  */
11 
13 #include "osxGraphicsBuffer.h"
14 #include "string_utils.h"
15 #include "config_osxdisplay.h"
16 #include "depthWriteAttrib.h"
17 #include "depthTestAttrib.h"
18 #include "textureAttrib.h"
19 #include "pnmImage.h"
20 
21 #include <OpenGL/gl.h>
22 #import <mach-o/dyld.h>
23 
24 // This is generated data for the standard texture we use for drawing the
25 // resize box in the window corner.
26 #include "resize_box.rgb.c"
27 
28 TypeHandle osxGraphicsStateGuardian::_type_handle;
29 
30 /**
31  * Returns the pointer to the GL extension function with the indicated name.
32  * It is the responsibility of the caller to ensure that the required
33  * extension is defined in the OpenGL runtime prior to calling this; it is an
34  * error to call this for a function that is not defined.
35  */
36 void *osxGraphicsStateGuardian::
37 do_get_extension_func(const char *name) {
38  std::string fullname = "_" + std::string(name);
39  NSSymbol symbol = nullptr;
40 
41  if (NSIsSymbolNameDefined(fullname.c_str())) {
42  symbol = NSLookupAndBindSymbol(fullname.c_str());
43  }
44 
45  return symbol ? NSAddressOfSymbol(symbol) : nullptr;
46 }
47 
48 /**
49  *
50  */
51 osxGraphicsStateGuardian::
52 osxGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
53  osxGraphicsStateGuardian *share_with) :
54  GLGraphicsStateGuardian(engine, pipe),
55  _share_with(share_with),
56  _aglPixFmt(nullptr),
57  _aglcontext(nullptr)
58 {
59  _shared_buffer = 1011;
60  get_gamma_table();
61 }
62 
63 /**
64  *
65  */
66 osxGraphicsStateGuardian::
67 ~osxGraphicsStateGuardian() {
68  if (_aglcontext != (AGLContext)nullptr) {
69  aglSetCurrentContext(nullptr);
70  aglDestroyContext(_aglcontext);
71  report_agl_error("aglDestroyContext");
72  _aglcontext = (AGLContext)nullptr;
73  }
74 }
75 
76 /**
77  * Resets all internal state as if the gsg were newly created.
78  */
80 {
81 /*
82  if(_aglcontext != (AGLContext)NULL)
83  {
84  aglDestroyContext(_aglcontext);
85  report_agl_error();
86  _aglcontext = (AGLContext)NULL;
87  }
88  */
89 
90  GLGraphicsStateGuardian::reset();
91 
92  if (_aglcontext != (AGLContext)nullptr) {
93  // Apply the video-sync setting.
94  GLint value = sync_video ? 1 : 0;
95  aglSetInteger(_aglcontext, AGL_SWAP_INTERVAL, &value);
96  }
97 }
98 
99 /**
100  * Draws an OSX-style resize icon in the bottom right corner of the current
101  * display region. This is normally done automatically at the end of each
102  * frame when the window is indicated as resizable, since the 3-D graphics
103  * overlay the normal, OS-drawn resize icon and the user won't be able see it.
104  */
106 draw_resize_box() {
107  // This state is created, once, and never freed.
108  static CPT(RenderState) state;
109  if (state == nullptr) {
110  state = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
111  DepthWriteAttrib::make(DepthWriteAttrib::M_off),
112  DepthTestAttrib::make(DepthTestAttrib::M_none));
113 
114  // Get the default texture to apply to the resize box; it's compiled into
115  // the code.
116  std::string resize_box_string((const char *)resize_box, resize_box_len);
117  std::istringstream resize_box_strm(resize_box_string);
118  PNMImage resize_box_pnm;
119  if (resize_box_pnm.read(resize_box_strm, "resize_box.rgb")) {
120  PT(Texture) tex = new Texture;
121  tex->set_name("resize_box.rgb");
122  tex->load(resize_box_pnm);
123  tex->set_minfilter(SamplerState::FT_linear);
124  tex->set_magfilter(SamplerState::FT_linear);
125  state = state->add_attrib(TextureAttrib::make(tex));
126  }
127  }
128 
129  // Clear out the lens.
130  _projection_mat_inv = _projection_mat = TransformState::make_identity();
131  prepare_lens();
132 
133  // Set the state to our specific, known state for drawing the icon.
134  set_state_and_transform(state, TransformState::make_identity());
135 
136  // Now determine the inner corner of the quad, choosing a 15x15 pixel square
137  // in the lower-right corner, computed from the viewport size.
138  PN_stdfloat inner_x = 1.0f - (15.0f * 2.0f / _viewport_width);
139  PN_stdfloat inner_y = (15.0f * 2.0f / _viewport_height) - 1.0f;
140 
141  // Draw the quad. We just use the slow, simple immediate mode calls here.
142  // It's just one quad, after all.
143  glBegin(GL_QUADS);
144 
145  glColor4f(1.0, 1.0, 1.0, 1.0);
146  glTexCoord2f(0.0, 0.0);
147  glVertex2f(inner_x, -1.0);
148 
149  glTexCoord2f(0.9375, 0.0);
150  glVertex2f(1.0, -1.0);
151 
152  glTexCoord2f(0.9375, 0.9375);
153  glVertex2f(1.0, inner_y);
154 
155  glTexCoord2f(0.0, 0.9375);
156  glVertex2f(inner_x, inner_y);
157 
158  glEnd();
159 }
160 
161 /**
162  * This function will build up a context for a gsg..
163  */
165 build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props) {
166  if (_aglcontext) {
167  describe_pixel_format(fb_props);
168  return noErr; // already built
169  }
170 
171  OSStatus err = noErr;
172 
173  GDHandle display = GetMainDevice();
174 
175  pvector<GLint> attrib;
176  if (!fb_props.get_indexed_color()) {
177  attrib.push_back(AGL_RGBA);
178  int color_bits = fb_props.get_color_bits();
179  int alpha_bits = fb_props.get_alpha_bits();
180  attrib.push_back(AGL_BUFFER_SIZE);
181  attrib.push_back(color_bits + alpha_bits);
182  attrib.push_back(AGL_PIXEL_SIZE);
183  attrib.push_back(color_bits);
184  attrib.push_back(AGL_RED_SIZE);
185  attrib.push_back(fb_props.get_red_bits());
186  attrib.push_back(AGL_GREEN_SIZE);
187  attrib.push_back(fb_props.get_green_bits());
188  attrib.push_back(AGL_BLUE_SIZE);
189  attrib.push_back(fb_props.get_blue_bits());
190  attrib.push_back(AGL_ALPHA_SIZE);
191  attrib.push_back(alpha_bits);
192  }
193  attrib.push_back(AGL_DEPTH_SIZE);
194  attrib.push_back(fb_props.get_depth_bits());
195  attrib.push_back(AGL_STENCIL_SIZE);
196  attrib.push_back(fb_props.get_stencil_bits());
197  if (fb_props.get_multisamples() != 0) {
198  attrib.push_back(AGL_MULTISAMPLE);
199  attrib.push_back(AGL_SAMPLE_BUFFERS_ARB);
200  attrib.push_back(1);
201  attrib.push_back(AGL_SAMPLES_ARB);
202  attrib.push_back(fb_props.get_multisamples());
203  }
204 
205  if (fb_props.is_stereo()) {
206  attrib.push_back(AGL_STEREO);
207  }
208 
209  if (!fb_props.is_single_buffered()) {
210  attrib.push_back(AGL_DOUBLEBUFFER);
211  }
212  if (full_screen) {
213  attrib.push_back(AGL_FULLSCREEN);
214  }
215  if (pbuffer) {
216  attrib.push_back(AGL_PBUFFER);
217  }
218 
219  if (fb_props.get_force_hardware()) {
220  attrib.push_back(AGL_ACCELERATED);
221  attrib.push_back(AGL_NO_RECOVERY);
222  }
223 
224  // Allow the system to choose the largest buffers requested that meets all
225  // our selections.
226  attrib.push_back(AGL_MAXIMUM_POLICY);
227 
228  // Terminate the list.
229  attrib.push_back(AGL_NONE);
230 
231  // build context
232  _aglcontext = nullptr;
233  _aglPixFmt = aglChoosePixelFormat(&display, 1, &attrib[0]);
234  err = report_agl_error("aglChoosePixelFormat");
235  if (_aglPixFmt) {
236  if(_share_with == nullptr) {
237  _aglcontext = aglCreateContext(_aglPixFmt, nullptr);
238  } else {
239  _aglcontext = aglCreateContext(_aglPixFmt, ((osxGraphicsStateGuardian *)_share_with)->_aglcontext);
240  }
241  err = report_agl_error("aglCreateContext");
242 
243  if (_aglcontext == nullptr) {
244  osxdisplay_cat.error()
245  << "osxGraphicsStateGuardian::build_gl Error Getting GL Context \n" ;
246  if(err == noErr) {
247  err = -1;
248  }
249  } else {
250  aglSetInteger(_aglcontext, AGL_BUFFER_NAME, &_shared_buffer);
251  err = report_agl_error("aglSetInteger AGL_BUFFER_NAME");
252  }
253 
254  } else {
255  osxdisplay_cat.error()
256  << "osxGraphicsStateGuardian::build_gl Error Getting Pixel Format\n" ;
257  osxdisplay_cat.error()
258  << fb_props << "\n";
259  if(err == noErr) {
260  err = -1;
261  }
262  }
263 
264  if (err == noErr) {
265  describe_pixel_format(fb_props);
266  }
267 
268  if (osxdisplay_cat.is_debug()) {
269  osxdisplay_cat.debug()
270  << "osxGraphicsStateGuardian::build_gl Returning :" << err << "\n";
271  osxdisplay_cat.debug()
272  << fb_props << "\n";
273  }
274 
275  return err;
276 }
277 
278 
279 /**
280  * Fills in the fb_props member with the appropriate values according to the
281  * chosen pixel format.
282  */
283 void osxGraphicsStateGuardian::
284 describe_pixel_format(FrameBufferProperties &fb_props) {
285  fb_props.clear();
286  GLint value;
287 
288  if (aglDescribePixelFormat(_aglPixFmt, AGL_RGBA, &value)) {
289  fb_props.set_indexed_color(!value);
290  fb_props.set_rgb_color(value);
291  }
292  if (aglDescribePixelFormat(_aglPixFmt, AGL_DEPTH_SIZE, &value)) {
293  fb_props.set_depth_bits(value);
294  }
295  int color_bits = 0;
296  if (aglDescribePixelFormat(_aglPixFmt, AGL_RED_SIZE, &value)) {
297  fb_props.set_red_bits(value);
298  color_bits += value;
299  }
300  if (aglDescribePixelFormat(_aglPixFmt, AGL_GREEN_SIZE, &value)) {
301  fb_props.set_green_bits(value);
302  color_bits += value;
303  }
304  if (aglDescribePixelFormat(_aglPixFmt, AGL_BLUE_SIZE, &value)) {
305  fb_props.set_blue_bits(value);
306  color_bits += value;
307  }
308  fb_props.set_color_bits(color_bits);
309  if (aglDescribePixelFormat(_aglPixFmt, AGL_ALPHA_SIZE, &value)) {
310  fb_props.set_alpha_bits(value);
311  }
312 
313  if (aglDescribePixelFormat(_aglPixFmt, AGL_STENCIL_SIZE, &value)) {
314  fb_props.set_stencil_bits(value);
315  }
316 
317  int accum_bits = 0;
318  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_RED_SIZE, &value)) {
319  accum_bits += value;
320  }
321  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_GREEN_SIZE, &value)) {
322  accum_bits += value;
323  }
324  if (aglDescribePixelFormat(_aglPixFmt, AGL_ACCUM_BLUE_SIZE, &value)) {
325  accum_bits += value;
326  }
327 
328  if (aglDescribePixelFormat(_aglPixFmt, AGL_SAMPLES_ARB, &value)) {
329  fb_props.set_multisamples(value);
330  }
331 
332  if (aglDescribePixelFormat(_aglPixFmt, AGL_DOUBLEBUFFER, &value)) {
333  if (value) {
334  fb_props.set_back_buffers(1);
335  } else {
336  fb_props.set_back_buffers(0);
337  }
338  }
339 
340  if (aglDescribePixelFormat(_aglPixFmt, AGL_STEREO, &value)) {
341  fb_props.set_stereo(value);
342  }
343 
344  // Until we query the renderer, we don't know whether it's hardware or
345  // software based, so set both flags to indicate we don't know.
346  fb_props.set_force_hardware(true);
347  fb_props.set_force_software(true);
348 
349  GLint ndevs;
350  AGLDevice *gdevs = aglDevicesOfPixelFormat(_aglPixFmt, &ndevs);
351  if (gdevs != nullptr) {
352  AGLRendererInfo rinfo = aglQueryRendererInfo(gdevs, ndevs);
353  if (rinfo != nullptr) {
354  if (aglDescribeRenderer(rinfo, AGL_ACCELERATED, &value)) {
355  // Now we know whether it's hardware or software.
356  fb_props.set_force_hardware(value);
357  fb_props.set_force_software(!value);
358  }
359  if (aglDescribeRenderer(rinfo, AGL_VIDEO_MEMORY, &value)) {
360  osxdisplay_cat.debug()
361  << "Reported video memory is " << value << "\n";
362  }
363  if (aglDescribeRenderer(rinfo, AGL_TEXTURE_MEMORY, &value)) {
364  osxdisplay_cat.debug()
365  << "Reported texture memory is " << value << "\n";
366  }
367  }
368  }
369 }
370 
371 /**
372  * Static function for getting the orig gamma tables
373  */
375 get_gamma_table() {
376  CGDisplayRestoreColorSyncSettings();
377  _cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable, _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount);
378 }
379 
380 /**
381  * Static function for setting gamma which is needed for atexit.
382  */
384 static_set_gamma(bool restore, PN_stdfloat gamma) {
385  bool set;
386 
387  set = false;
388 
389  if (restore) {
390  CGDisplayRestoreColorSyncSettings();
391  set = true;
392  return set;
393  }
394  // CGDisplayRestoreColorSyncSettings();
395 
396  // CGGammaValue gOriginalRedTable[ 256 ]; CGGammaValue gOriginalGreenTable[
397  // 256 ]; CGGammaValue gOriginalBlueTable[ 256 ];
398 
399  // CGTableCount sampleCount; CGDisplayErr cgErr;
400 
401  // cgErr = CGGetDisplayTransferByTable( 0, 256, _gOriginalRedTable,
402  // _gOriginalGreenTable, _gOriginalBlueTable, &_sampleCount);
403 
404  CGGammaValue redTable[ 256 ];
405  CGGammaValue greenTable[ 256 ];
406  CGGammaValue blueTable[ 256 ];
407 
408  short j, i;
409  short y[3];
410 
411  for (j = 0; j < 3; j++) {
412  y[j] = 255;
413  }
414 
415  y[0] = 256 * gamma;
416  y[1] = 256 * gamma;
417  y[2] = 256 * gamma;
418 
419  for (i = 0; i < 256; i++) {
420  redTable[i] = _gOriginalRedTable[ i ] * (y[ 0 ] ) / 256;
421  greenTable[ i ] = _gOriginalGreenTable[ i ] * (y[ 1 ] ) / 256;
422  blueTable[ i ] = _gOriginalBlueTable[ i ] * (y[ 2 ] ) / 256;
423  }
424  _cgErr = CGSetDisplayTransferByTable( 0, 256, redTable, greenTable, blueTable);
425 
426  if (_cgErr == 0) {
427  set = true;
428  }
429 
430  return set;
431 }
432 
433 /**
434  * Non static version of setting gamma. Returns true on success.
435  */
437 set_gamma(PN_stdfloat gamma) {
438  bool set;
439 
440  set = static_set_gamma(false, gamma);
441 
442  return set;
443 }
444 
445 /**
446  * Restore original gamma.
447  */
449 restore_gamma() {
450  static_set_gamma(true, 1.0f);
451 }
452 
453 /**
454  * This function is passed to the atexit function.
455  */
457 atexit_function() {
458  static_set_gamma(true, 1.0);
459 }
osxGraphicsStateGuardian
A tiny specialization on GLGraphicsStateGuardian to add some wgl-specific information.
Definition: osxGraphicsStateGuardian.h:32
FrameBufferProperties
A container for the various kinds of properties we might ask to have on a graphics frameBuffer before...
Definition: frameBufferProperties.h:26
pvector
This is our own Panda specialization on the default STL vector.
Definition: pvector.h:42
osxGraphicsStateGuardian::reset
virtual void reset()
Resets all internal state as if the gsg were newly created.
Definition: osxGraphicsStateGuardian.cxx:79
string_utils.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
pnmImage.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Texture
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition: texture.h:71
PNMImage::read
bool read(const Filename &filename, PNMFileType *type=nullptr, bool report_unknown_type=true)
Reads the indicated image filename.
Definition: pnmImage.cxx:278
PNMImage
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
Definition: pnmImage.h:58
osxGraphicsStateGuardian::set_gamma
bool set_gamma(PN_stdfloat gamma)
Non static version of setting gamma.
Definition: osxGraphicsStateGuardian.cxx:437
RenderState
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
FrameBufferProperties::clear
void clear()
Unsets all properties that have been specified so far, and resets the FrameBufferProperties structure...
Definition: frameBufferProperties.cxx:185
GraphicsEngine
This class is the main interface to controlling the render process.
Definition: graphicsEngine.h:53
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
osxGraphicsStateGuardian::build_gl
OSStatus build_gl(bool full_screen, bool pbuffer, FrameBufferProperties &fb_props)
This function will build up a context for a gsg.
Definition: osxGraphicsStateGuardian.cxx:165
depthWriteAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
GraphicsPipe
An object to create GraphicsOutputs that share a particular 3-D API.
Definition: graphicsPipe.h:52
osxGraphicsStateGuardian::get_gamma_table
bool get_gamma_table()
Static function for getting the orig gamma tables.
Definition: osxGraphicsStateGuardian.cxx:375
config_osxdisplay.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
depthTestAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
osxGraphicsStateGuardian::static_set_gamma
bool static_set_gamma(bool restore, PN_stdfloat gamma)
Static function for setting gamma which is needed for atexit.
Definition: osxGraphicsStateGuardian.cxx:384
osxGraphicsStateGuardian::atexit_function
void atexit_function()
This function is passed to the atexit function.
Definition: osxGraphicsStateGuardian.cxx:457
textureAttrib.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
osxGraphicsStateGuardian::restore_gamma
void restore_gamma()
Restore original gamma.
Definition: osxGraphicsStateGuardian.cxx:449
osxGraphicsStateGuardian::draw_resize_box
void draw_resize_box()
Draws an OSX-style resize icon in the bottom right corner of the current display region.
Definition: osxGraphicsStateGuardian.cxx:106
FrameBufferProperties::set_color_bits
set_color_bits
Sets the number of requested color bits as a single number that represents the sum of the individual ...
Definition: frameBufferProperties.h:124
osxGraphicsStateGuardian.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
osxGraphicsBuffer.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.