add GraphicsEngine::open_windows(), GLGraphicsStateGuardian::_edge_clamp

This commit is contained in:
David Rose 2004-03-03 01:09:38 +00:00
parent baea752ded
commit 587de59ae8
14 changed files with 320 additions and 48 deletions

View File

@ -86,7 +86,7 @@ const bool show_buffers = config_display.GetBool("show-buffers", false);
// buffer. This may be desired if you know your graphics API does not
// support render-directly-to-texture and you want to minimize
// framebuffer memory.
const bool prefer_parasite_buffer = config_display.GetBool("prefer-parasite-buffer", false);
const bool prefer_parasite_buffer = config_display.GetBool("prefer-parasite-buffer", true);
// Set this true to make GraphicsOutput::make_render_texture() first
// try to create a single-buffered offscreen buffer, before falling

View File

@ -503,6 +503,50 @@ render_frame() {
_app_pcollector.start();
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::open_windows
// Access: Published
// Description: Fully opens (or closes) any windows that have
// recently been requested open or closed, without
// rendering any frames. It is not necessary to call
// this explicitly, since windows will be automatically
// opened or closed when the next frame is rendered, but
// you may call this if you want your windows now
// without seeing a frame go by.
////////////////////////////////////////////////////////////////////
void GraphicsEngine::
open_windows() {
MutexHolder holder(_lock);
if (!_windows_sorted) {
do_resort_windows();
}
_app.do_windows(this);
Threads::const_iterator ti;
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second;
if (thread->_thread_state == TS_wait) {
thread->_thread_state = TS_do_windows;
thread->_cv.signal();
}
thread->_cv_mutex.release();
}
// We do it twice, to allow both cull and draw to process the
// window.
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
RenderThread *thread = (*ti).second;
if (thread->_thread_state == TS_wait) {
thread->_thread_state = TS_do_windows;
thread->_cv.signal();
}
thread->_cv_mutex.release();
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::sync_frame
// Access: Published
@ -747,6 +791,24 @@ cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr) {
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::make_contexts
// Access: Private
// Description: Called in the draw thread, this calls make_context()
// on each window on the list to guarantee its graphics
// context gets created.
////////////////////////////////////////////////////////////////////
void GraphicsEngine::
make_contexts(const GraphicsEngine::Windows &wlist) {
Windows::const_iterator wi;
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
GraphicsOutput *win = (*wi);
if (win->needs_context()) {
win->make_context();
}
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::process_events
// Access: Private
@ -1321,6 +1383,25 @@ do_frame(GraphicsEngine *engine) {
do_callbacks(CB_post_frame);
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::WindowRenderer::do_windows
// Access: Public
// Description: Attempts to fully open or close any windows or
// buffers associated with this thread, but does not
// otherwise perform any rendering. (Normally, this
// step is handled during do_frame(); call this method
// only if you want these things to open immediately.)
////////////////////////////////////////////////////////////////////
void GraphicsEngine::WindowRenderer::
do_windows(GraphicsEngine *engine) {
MutexHolder holder(_wl_lock);
engine->process_events(_window);
engine->make_contexts(_cdraw);
engine->make_contexts(_draw);
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsEngine::WindowRenderer::do_flip
// Access: Public
@ -1542,6 +1623,13 @@ thread_main() {
_thread_state = TS_wait;
break;
case TS_do_windows:
do_windows(_engine);
do_pending(_engine);
do_release(_engine);
_thread_state = TS_wait;
break;
case TS_terminate:
do_pending(_engine);
do_close(_engine);

View File

@ -88,6 +88,7 @@ PUBLISHED:
bool is_empty() const;
void render_frame();
void open_windows();
void sync_frame();
void flip_frame();
@ -100,6 +101,7 @@ public:
TS_do_frame,
TS_do_flip,
TS_do_release,
TS_do_windows,
TS_terminate
};
@ -139,6 +141,7 @@ private:
void cull_bin_draw(const Windows &wlist);
void cull_bin_draw(GraphicsStateGuardian *gsg, DisplayRegion *dr);
void make_contexts(const Windows &wlist);
void process_events(const Windows &wlist);
void flip_windows(const Windows &wlist);
@ -171,6 +174,7 @@ private:
void remove_window(GraphicsOutput *window);
void resort_windows();
void do_frame(GraphicsEngine *engine);
void do_windows(GraphicsEngine *engine);
void do_flip(GraphicsEngine *engine);
void do_release(GraphicsEngine *engine);
void do_close(GraphicsEngine *engine);

View File

@ -160,17 +160,6 @@ is_valid() const {
return _is_valid;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::flip_ready
// Access: Published
// Description: Returns true if a frame has been rendered and needs
// to be flipped, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput::
flip_ready() const {
return _flip_ready;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::get_sort
// Access: Published
@ -243,6 +232,28 @@ win_display_regions_changed() {
_display_regions_stale = true;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::flip_ready
// Access: Public
// Description: Returns true if a frame has been rendered and needs
// to be flipped, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput::
flip_ready() const {
return _flip_ready;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::needs_context
// Access: Public
// Description: Returns true if make_context() still needs to be
// called, false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool GraphicsOutput::
needs_context() const {
return _needs_context;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::operator <
// Access: Public

View File

@ -52,6 +52,7 @@ GraphicsOutput(GraphicsPipe *pipe, GraphicsStateGuardian *gsg,
_is_valid = false;
_copy_texture = false;
_flip_ready = false;
_needs_context = true;
_sort = 0;
int mode = gsg->get_properties().get_frame_buffer_mode();
@ -365,7 +366,15 @@ make_texture_buffer(const string &name, int x_size, int y_size) {
if (sb_gsg != (GraphicsStateGuardian *)NULL) {
buffer = engine->make_buffer(sb_gsg, name, sort, x_size, y_size, true);
if (buffer != (GraphicsOutput *)NULL) {
return buffer;
// Check the buffer for goodness.
engine->open_windows();
if (buffer->is_valid()) {
return buffer;
}
// No good; delete the buffer and keep trying.
engine->remove_window(buffer);
buffer = (GraphicsOutput *)NULL;
}
}
}
@ -376,7 +385,13 @@ make_texture_buffer(const string &name, int x_size, int y_size) {
// source window is double-buffered.
buffer = engine->make_buffer(gsg, name, sort, x_size, y_size, true);
if (buffer != (GraphicsOutput *)NULL) {
return buffer;
engine->open_windows();
if (buffer->is_valid()) {
return buffer;
}
engine->remove_window(buffer);
buffer = (GraphicsOutput *)NULL;
}
// Looks like we have to settle for a parasite buffer.
@ -492,6 +507,12 @@ begin_frame() {
return false;
}
if (needs_context()) {
if (!make_context()) {
return false;
}
}
// Okay, we already have a GSG, so activate it.
make_current();
return _gsg->begin_frame();
@ -550,6 +571,22 @@ end_frame() {
}
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::make_context
// Access: Public, Virtual
// Description: If _needs_context is true, this will be called
// in the draw thread prior to rendering into the
// window. It should attempt to create a graphics
// context, and return true if successful, false
// otherwise. If it returns false the window will be
// considered failed.
////////////////////////////////////////////////////////////////////
bool GraphicsOutput::
make_context() {
_needs_context = false;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsOutput::make_current
// Access: Public, Virtual

View File

@ -80,7 +80,6 @@ PUBLISHED:
INLINE int get_y_size() const;
INLINE bool has_size() const;
INLINE bool is_valid() const;
INLINE bool flip_ready() const;
virtual bool is_active() const;
@ -109,6 +108,8 @@ public:
public:
// These are not intended to be called directly by the user.
INLINE void win_display_regions_changed();
INLINE bool needs_context() const;
INLINE bool flip_ready() const;
INLINE bool operator < (const GraphicsOutput &other) const;
@ -129,6 +130,7 @@ public:
// This method is called in the draw thread prior to issuing any
// drawing commands for the window.
virtual bool make_context();
virtual void make_current();
virtual void release_gsg();
@ -151,6 +153,7 @@ protected:
PT(Texture) _texture;
bool _copy_texture;
bool _flip_ready;
bool _needs_context;
private:
INLINE void determine_display_regions() const;

View File

@ -64,6 +64,7 @@ ParasiteBuffer(GraphicsOutput *host, const string &name,
////////////////////////////////////////////////////////////////////
ParasiteBuffer::
~ParasiteBuffer() {
_is_valid = false;
}
////////////////////////////////////////////////////////////////////

View File

@ -615,14 +615,14 @@ enable_multisample(bool val) {
if (_multisample_enabled != val) {
_multisample_enabled = val;
if (val) {
#ifdef GL_MULTISAMPLE_SGIS
GLP(Enable)(GL_MULTISAMPLE_SGIS);
#endif
if (_supports_multisample) {
GLP(Enable)(GL_MULTISAMPLE);
}
GLP(Hint)(GL_POINT_SMOOTH_HINT, GL_NICEST);
} else {
#ifdef GL_MULTISAMPLE_SGIS
GLP(Disable)(GL_MULTISAMPLE_SGIS);
#endif
if (_supports_multisample) {
GLP(Disable)(GL_MULTISAMPLE);
}
GLP(Hint)(GL_POINT_SMOOTH_HINT, GL_FASTEST);
}
}

View File

@ -380,6 +380,8 @@ reset() {
_current_projection_mat = LMatrix4f::ident_mat();
_projection_mat_stack_count = 0;
report_my_gl_errors();
// Make sure the GL state matches all of our initial attribute
// states.
CPT(RenderAttrib) dta = DepthTestAttrib::make(DepthTestAttrib::M_less);
@ -419,7 +421,7 @@ reset() {
// Output the vendor and version strings.
show_gl_string("GL_VENDOR", GL_VENDOR);
show_gl_string("GL_RENDERER", GL_RENDERER);
show_gl_string("GL_VERSION", GL_VERSION);
get_gl_version();
// Save the extensions tokens.
save_extensions((const char *)glGetString(GL_EXTENSIONS));
@ -427,6 +429,14 @@ reset() {
report_extensions();
_supports_bgr = has_extension("GL_EXT_bgra");
_supports_multisample = has_extension("GL_ARB_multisample");
_edge_clamp = GL_CLAMP;
if (has_extension("GL_SGIS_texture_edge_clamp") ||
is_at_least_version(1, 2)) {
_edge_clamp = GL_CLAMP_TO_EDGE;
}
_error_count = 0;
report_my_gl_errors();
@ -2663,6 +2673,47 @@ show_gl_string(const string &name, GLenum id) {
}
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::get_gl_version
// Access: Protected
// Description: Queries the runtime version of OpenGL in use.
////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian)::
get_gl_version() {
_gl_version_major = 0;
_gl_version_minor = 0;
_gl_version_release = 0;
const GLubyte *text = GLP(GetString)(GL_VERSION);
if (text == (const GLubyte *)NULL) {
GLCAT.debug()
<< "Unable to query GL_VERSION\n";
} else {
string input((const char *)text);
size_t space = input.find(' ');
if (space != string::npos) {
input = input.substr(0, space);
}
vector_string components;
tokenize(input, components, ".");
if (components.size() >= 1) {
string_to_int(components[0], _gl_version_major);
}
if (components.size() >= 2) {
string_to_int(components[1], _gl_version_minor);
}
if (components.size() >= 3) {
string_to_int(components[2], _gl_version_release);
}
GLCAT.debug()
<< "GL_VERSION = " << (const char *)text << ", decoded to "
<< _gl_version_major << "." << _gl_version_minor
<< "." << _gl_version_release << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::save_extensions
// Access: Protected
@ -2725,6 +2776,26 @@ has_extension(const string &extension) const {
return (_extensions.find(extension) != _extensions.end());
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::is_at_least_version
// Access: Public
// Description: Returns true if the runtime GL version number is at
// least the indicated value, false otherwise.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
is_at_least_version(int major, int minor, int release) const {
if (_gl_version_major < major) {
return false;
}
if (_gl_version_minor < minor) {
return false;
}
if (_gl_version_release < release) {
return false;
}
return true;
}
////////////////////////////////////////////////////////////////////
// Function: CLP(GraphicsStateGuardian)::set_draw_buffer
@ -2918,12 +2989,10 @@ compute_gl_image_size(int xsize, int ysize, int external_format, int type) {
pixel_width = 2 * num_components;
break;
#ifdef GL_UNSIGNED_BYTE_3_3_2_EXT
case GL_UNSIGNED_BYTE_3_3_2_EXT:
case GL_UNSIGNED_BYTE_3_3_2:
nassertr(num_components == 3, 0);
pixel_width = 1;
break;
#endif
case GL_FLOAT:
pixel_width = 4 * num_components;
@ -3255,7 +3324,7 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
}
switch (wm) {
case Texture::WM_clamp:
return GL_CLAMP;
return _edge_clamp;
case Texture::WM_repeat:
return GL_REPEAT;
@ -3269,7 +3338,7 @@ get_texture_wrap_mode(Texture::WrapMode wm) {
break;
}
GLCAT.error() << "Invalid Texture::WrapMode value!\n";
return GL_CLAMP;
return _edge_clamp;
}
////////////////////////////////////////////////////////////////////
@ -3332,10 +3401,8 @@ get_image_type(PixelBuffer::Type type) {
return GL_UNSIGNED_BYTE;
case PixelBuffer::T_unsigned_short:
return GL_UNSIGNED_SHORT;
#ifdef GL_UNSIGNED_BYTE_3_3_2_EXT
case PixelBuffer::T_unsigned_byte_332:
return GL_UNSIGNED_BYTE_3_3_2_EXT;
#endif
return GL_UNSIGNED_BYTE_3_3_2;
case PixelBuffer::T_float:
return GL_FLOAT;
@ -3480,9 +3547,7 @@ get_fog_mode_type(Fog::Mode m) const {
case Fog::M_exponential: return GL_EXP;
case Fog::M_exponential_squared: return GL_EXP2;
/*
#ifdef GL_FOG_FUNC_SGIS
case Fog::M_spline: return GL_FOG_FUNC_SGIS;
#endif
*/
default:
@ -3525,13 +3590,10 @@ print_gfx_visual() {
GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
#ifdef GL_MULTISAMPLE_SGIS
GLP(GetBooleanv)( GL_MULTISAMPLE_SGIS, &j ); cout << "Multisample? "
<< (int)j << endl;
#endif
#ifdef GL_SAMPLES_SGIS
GLP(GetIntegerv)( GL_SAMPLES_SGIS, &i ); cout << "Samples: " << i << endl;
#endif
if (_supports_multisample) {
GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
}
GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "

View File

@ -133,10 +133,12 @@ protected:
static bool report_errors_loop(int line, const char *source_file,
GLenum error_code, int &error_count);
void show_gl_string(const string &name, GLenum id);
void get_gl_version();
void save_extensions(const char *extensions);
virtual void get_extra_extensions();
void report_extensions() const;
bool has_extension(const string &extension) const;
bool is_at_least_version(int major, int minor, int release = 0) const;
virtual bool slot_new_light(int light_id);
virtual void enable_lighting(bool enable);
@ -299,8 +301,11 @@ protected:
int _pass_number;
int _gl_version_major, _gl_version_minor, _gl_version_release;
pset<string> _extensions;
bool _supports_bgr;
bool _supports_multisample;
GLenum _edge_clamp;
int _error_count;

View File

@ -152,6 +152,45 @@ end_frame() {
}
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::make_context
// Access: Public, Virtual
// Description: If _needs_context is true, this will be called
// in the draw thread prior to rendering into the
// window. It should attempt to create a graphics
// context, and return true if successful, false
// otherwise. If it returns false the window will be
// considered failed.
////////////////////////////////////////////////////////////////////
bool wglGraphicsBuffer::
make_context() {
PStatTimer timer(_make_current_pcollector);
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
if (_pbuffer_dc) {
HGLRC context = wglgsg->get_context(_pbuffer_dc);
if (context) {
wglMakeCurrent(_pbuffer_dc, context);
wglgsg->reset_if_new();
_needs_context = false;
return true;
}
} else {
HGLRC context = wglgsg->get_context(_window_dc);
if (context) {
wglMakeCurrent(_window_dc, context);
wglgsg->reset_if_new();
_needs_context = false;
return true;
}
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsBuffer::make_current
// Access: Public, Virtual

View File

@ -49,6 +49,7 @@ public:
virtual bool begin_frame();
virtual void end_frame();
virtual bool make_context();
virtual void make_current();
virtual void release_gsg();

View File

@ -147,6 +147,33 @@ wglGraphicsWindow::
~wglGraphicsWindow() {
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsWindow::make_context
// Access: Public, Virtual
// Description: If _needs_context is true, this will be called
// in the draw thread prior to rendering into the
// window. It should attempt to create a graphics
// context, and return true if successful, false
// otherwise. If it returns false the window will be
// considered failed.
////////////////////////////////////////////////////////////////////
bool wglGraphicsWindow::
make_context() {
PStatTimer timer(_make_current_pcollector);
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_R(wglgsg, _gsg, false);
HGLRC context = wglgsg->get_context(_hdc);
if (context) {
wglMakeCurrent(_hdc, context);
wglgsg->reset_if_new();
_needs_context = false;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: wglGraphicsWindow::make_current
// Access: Public, Virtual
@ -161,15 +188,8 @@ make_current() {
wglGraphicsStateGuardian *wglgsg;
DCAST_INTO_V(wglgsg, _gsg);
HGLRC context = wglgsg->get_context(_hdc);
if (context) {
wglMakeCurrent(_hdc, context);
// Now that we have made the context current to a window, we can
// reset the GSG state if this is the first time it has been used.
// (We can't just call reset() when we construct the GSG, because
// reset() requires having a current context.)
wglgsg->reset_if_new();
}
nassertv(context);
wglMakeCurrent(_hdc, context);
}
////////////////////////////////////////////////////////////////////

View File

@ -33,6 +33,7 @@ public:
const string &name);
virtual ~wglGraphicsWindow();
virtual bool make_context();
virtual void make_current();
virtual void release_gsg();