Memory barriers, immutable texture storage, bindless textures, fixes for multisample FBOs, code cleanup, etc.

This commit is contained in:
rdb 2014-07-15 08:46:58 +00:00
parent de54dda8c1
commit efa258ebf3
15 changed files with 1035 additions and 477 deletions

View File

@ -40,7 +40,7 @@ valid() {
////////////////////////////////////////////////////////////////////
INLINE bool CLP(CgShaderContext)::
uses_standard_vertex_arrays() {
return _uses_standard_vertex_arrays;
return false;
}
////////////////////////////////////////////////////////////////////

View File

@ -40,8 +40,10 @@ TypeHandle CLP(CgShaderContext)::_type_handle;
CLP(CgShaderContext)::
CLP(CgShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
_glgsg = glgsg;
_uses_standard_vertex_arrays = false;
_cg_context = 0;
_cg_vprogram = 0;
_cg_fprogram = 0;
_cg_gprogram = 0;
_cg_vprofile = CG_PROFILE_UNKNOWN;
_cg_fprofile = CG_PROFILE_UNKNOWN;
_cg_gprofile = CG_PROFILE_UNKNOWN;
@ -409,10 +411,14 @@ disable_shader_vertex_arrays() {
////////////////////////////////////////////////////////////////////
bool CLP(CgShaderContext)::
update_shader_vertex_arrays(ShaderContext *prev, bool force) {
if (prev) prev->disable_shader_vertex_arrays();
if (prev) {
prev->disable_shader_vertex_arrays();
}
if (!valid()) {
return true;
}
cg_report_errors();
#ifdef SUPPORT_IMMEDIATE_MODE
@ -451,11 +457,17 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
}
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
cgGLSetParameterPointer(p,
num_values, _glgsg->get_numeric_type(numeric_type),
stride, client_pointer + start);
cgGLEnableClientState(p);
} else {
if (numeric_type == GeomEnums::NT_packed_dabc) {
cgGLSetParameterPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
stride, client_pointer + start);
} else {
cgGLSetParameterPointer(p,
num_values, _glgsg->get_numeric_type(numeric_type),
stride, client_pointer + start);
}
} else {
CGparameter p = _cg_parameter_map[_shader->_var_spec[i]._id._seqno];
cgGLDisableClientState(p);
}
@ -507,7 +519,6 @@ disable_shader_texture_bindings() {
// cgGLDisableTextureParameter(p);
}
#endif // OPENGLES_2
_stage_offset = 0;
cg_report_errors();
_glgsg->report_my_gl_errors();
@ -538,7 +549,6 @@ update_shader_texture_bindings(ShaderContext *prev) {
// filtered TextureAttrib in _target_texture.
const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
nassertv(texattrib != (TextureAttrib *)NULL);
_stage_offset = texattrib->get_num_on_stages();
for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
InternalName *id = _shader->_tex_spec[i]._name;

View File

@ -61,11 +61,8 @@ private:
pvector <CGparameter> _cg_parameter_map;
int _stage_offset;
CLP(GraphicsStateGuardian) *_glgsg;
bool _uses_standard_vertex_arrays;
void release_resources();
public:

View File

@ -84,9 +84,13 @@ munge_format_impl(const GeomVertexFormat *orig,
PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
new_format->set_animation(animation);
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, get_gsg(), NULL);
const GeomVertexColumn *color_type = orig->get_color_column();
if (color_type != (GeomVertexColumn *)NULL &&
color_type->get_numeric_type() == NT_packed_dabc) {
color_type->get_numeric_type() == NT_packed_dabc &&
!glgsg->_supports_packed_dabc) {
// We need to convert the color format; OpenGL doesn't support the
// byte order of DirectX's packed ARGB format.
int color_array = orig->get_array_with(InternalName::get_color());
@ -230,9 +234,13 @@ CPT(GeomVertexFormat) CLP(GeomMunger)::
premunge_format_impl(const GeomVertexFormat *orig) {
PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, get_gsg(), NULL);
const GeomVertexColumn *color_type = orig->get_color_column();
if (color_type != (GeomVertexColumn *)NULL &&
color_type->get_numeric_type() == NT_packed_dabc) {
color_type->get_numeric_type() == NT_packed_dabc &&
!glgsg->_supports_packed_dabc) {
// We need to convert the color format; OpenGL doesn't support the
// byte order of DirectX's packed ARGB format.
int color_array = orig->get_array_with(InternalName::get_color());

View File

@ -73,9 +73,8 @@ CLP(GraphicsBuffer)(GraphicsEngine *engine, GraphicsPipe *pipe,
_rb_size_x = 0;
_rb_size_y = 0;
_rb_size_z = 0;
for (int i=0; i<RTP_COUNT; i++) {
for (int i = 0; i < RTP_COUNT; ++i) {
_rb[i] = 0;
_tex[i] = 0;
_rbm[i] = 0;
}
@ -170,6 +169,24 @@ begin_frame(FrameMode mode, Thread *current_thread) {
// rebuild_bitplanes().
return false;
}
// In case of multisample rendering, we don't need to issue
// the barrier until we call glBlitFramebuffer.
if (gl_enable_memory_barriers && _fbo_multisample == 0) {
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_R(glgsg, _gsg, false);
pvector<CLP(TextureContext)*>::iterator it;
for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
CLP(TextureContext) *gtc = *it;
if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT);
// If we've done it for one, we've done it for all.
break;
}
}
}
}
_gsg->set_current_properties(&get_fb_properties());
@ -248,7 +265,9 @@ rebuild_bitplanes() {
DCAST_INTO_V(glgsg, _gsg);
if (!_needs_rebuild) {
if (_fbo.size() > 0) {
if (_fbo_multisample != 0) {
glgsg->bind_fbo(_fbo_multisample);
} else if (_fbo.size() > 0) {
glgsg->bind_fbo(_fbo[0]);
} else {
glgsg->bind_fbo(0);
@ -284,6 +303,7 @@ rebuild_bitplanes() {
// These variables indicate what should be bound to each bitplane.
Texture *attach[RTP_COUNT];
memset(attach, 0, sizeof(Texture *) * RTP_COUNT);
_texture_contexts.clear();
// Sort the textures list into appropriate slots.
{
@ -437,12 +457,13 @@ rebuild_bitplanes() {
bind_slot(layer, rb_resize, attach, RTP_color, next++);
if (_fb_properties.is_stereo()) {
// The texture has already been initialized, so bind it straight away.
// The second tex view has already been initialized, so bind it straight away.
if (attach[RTP_color] != NULL) {
attach_tex(layer, 1, attach[RTP_color], next++);
} else {
//XXX hack: I needed a slot to use, and we don't currently use RTP_stencil
// which is treated as a color attachment below, so this fits the bill.
// and it's treated as a color attachment below, so this fits the bill.
// Eventually, we might want to add RTP_color_left and RTP_color_right.
bind_slot(layer, rb_resize, attach, RTP_stencil, next++);
}
}
@ -553,7 +574,6 @@ bind_slot(int layer, bool rb_resize, Texture **attach, RenderTexturePlane slot,
DCAST_INTO_V(glgsg, _gsg);
Texture *tex = attach[slot];
_tex[slot] = tex;
if (tex && layer >= tex->get_z_size()) {
// If the requested layer index exceeds the number of layers
@ -1047,7 +1067,10 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
TextureContext *tc = attach->prepare_now(view, glgsg->get_prepared_objects(), glgsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
glgsg->update_texture(tc, true);
glgsg->update_texture(gtc, true);
gtc->set_active(true);
_texture_contexts.push_back(gtc);
#ifndef OPENGLES
GLclampf priority = 1.0f;
@ -1098,23 +1121,26 @@ attach_tex(int layer, int view, Texture *attach, GLenum attachpoint) {
////////////////////////////////////////////////////////////////////
void CLP(GraphicsBuffer)::
generate_mipmaps() {
if (gl_ignore_mipmaps && !gl_force_mipmaps) {
return;
}
CLP(GraphicsStateGuardian) *glgsg;
DCAST_INTO_V(glgsg, _gsg);
for (int slot=0; slot<RTP_COUNT; slot++) {
Texture *tex = _tex[slot];
if ((tex != 0) && (tex->uses_mipmaps())) {
pvector<CLP(TextureContext)*>::iterator it;
for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
CLP(TextureContext) *gtc = *it;
if (gtc->_generate_mipmaps) {
glgsg->_state_texture = 0;
TextureContext *tc = tex->prepare_now(0, glgsg->get_prepared_objects(), glgsg);
nassertv(tc != (TextureContext *)NULL);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
glgsg->update_texture(tc, true);
GLenum target = glgsg->get_texture_target(tex->get_texture_type());
glBindTexture(target, gtc->_index);
glgsg->_glGenerateMipmap(target);
glBindTexture(target, 0);
glgsg->update_texture(gtc, true);
glgsg->apply_texture(gtc);
glgsg->_glGenerateMipmap(gtc->_target);
glBindTexture(gtc->_target, 0);
}
}
report_my_gl_errors();
}
@ -1198,7 +1224,11 @@ select_target_tex_page(int page) {
}
}
glgsg->bind_fbo(_fbo[page]);
if (_fbo_multisample != 0) {
// TODO: re-issue clears?
} else {
glgsg->bind_fbo(_fbo[page]);
}
_bound_tex_page = page;
}
@ -1305,7 +1335,8 @@ open_buffer() {
_fb_properties.set_stencil_bits(0);
}
_fb_properties.set_accum_bits(0);
_fb_properties.set_multisamples(_host->get_fb_properties().get_multisamples());
_fb_properties.set_multisamples(_requested_multisamples);
// Update aux settings to reflect the GL_MAX_DRAW_BUFFERS limit,
// if we exceed it, that is.
@ -1378,7 +1409,6 @@ close_buffer() {
glgsg->_glDeleteRenderbuffers(1, &(_rb[i]));
_rb[i] = 0;
}
_tex[i] = 0;
}
// Delete the renderbuffers.
for (int i=0; i<RTP_COUNT; i++) {
@ -1386,7 +1416,6 @@ close_buffer() {
glgsg->_glDeleteRenderbuffers(1, &(_rbm[i]));
_rb[i] = 0;
}
_tex[i] = 0;
}
_rb_size_x = 0;
_rb_size_y = 0;
@ -1577,6 +1606,21 @@ resolve_multisamples() {
nassertv(_fbo.size() > 0);
if (gl_enable_memory_barriers) {
// Issue memory barriers as necessary to make sure that the
// texture memory is synchronized before we blit to it.
pvector<CLP(TextureContext)*>::iterator it;
for (it = _texture_contexts.begin(); it != _texture_contexts.end(); ++it) {
CLP(TextureContext) *gtc = *it;
if (gtc->needs_barrier(GL_FRAMEBUFFER_BARRIER_BIT)) {
glgsg->issue_memory_barrier(GL_FRAMEBUFFER_BARRIER_BIT);
// If we've done it for one, we've done it for all.
break;
}
}
}
glgsg->report_my_gl_errors();
GLuint fbo = _fbo[0];
if (_bound_tex_page != -1) {
@ -1586,31 +1630,34 @@ resolve_multisamples() {
glgsg->_glBindFramebuffer(GL_READ_FRAMEBUFFER_EXT, _fbo_multisample);
// If the depth buffer is shared, resolve it only on the last to render FBO.
int do_depth_blit = 0;
if (_shared_depth_buffer) {
CLP(GraphicsBuffer) *graphics_buffer = NULL;
CLP(GraphicsBuffer) *highest_sort_graphics_buffer = NULL;
list <CLP(GraphicsBuffer) *>::iterator graphics_buffer_iterator;
bool do_depth_blit = false;
if (_rbm[RTP_depth_stencil] != 0 || _rbm[RTP_depth] != 0) {
if (_shared_depth_buffer) {
CLP(GraphicsBuffer) *graphics_buffer = NULL;
CLP(GraphicsBuffer) *highest_sort_graphics_buffer = NULL;
list <CLP(GraphicsBuffer) *>::iterator graphics_buffer_iterator;
int max_sort_order = 0;
for (graphics_buffer_iterator = _shared_depth_buffer_list.begin();
graphics_buffer_iterator != _shared_depth_buffer_list.end();
graphics_buffer_iterator++) {
graphics_buffer = (*graphics_buffer_iterator);
if (graphics_buffer) {
// this call removes the entry from the list
if ( graphics_buffer->get_sort() >= max_sort_order ) {
max_sort_order = graphics_buffer->get_sort();
highest_sort_graphics_buffer = graphics_buffer;
int max_sort_order = 0;
for (graphics_buffer_iterator = _shared_depth_buffer_list.begin();
graphics_buffer_iterator != _shared_depth_buffer_list.end();
graphics_buffer_iterator++) {
graphics_buffer = (*graphics_buffer_iterator);
if (graphics_buffer) {
// this call removes the entry from the list
if (graphics_buffer->get_sort() >= max_sort_order) {
max_sort_order = graphics_buffer->get_sort();
highest_sort_graphics_buffer = graphics_buffer;
}
}
}
if (max_sort_order == this->get_sort()) {
do_depth_blit = true;
}
} else {
do_depth_blit = true;
}
if (max_sort_order == this->get_sort()) {
do_depth_blit = 1;
}
} else {
do_depth_blit = 1;
}
if (do_depth_blit) {
glgsg->_glBlitFramebuffer(0, 0, _rb_size_x, _rb_size_y, 0, 0, _rb_size_x, _rb_size_y,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT,
@ -1620,7 +1667,6 @@ resolve_multisamples() {
GL_COLOR_BUFFER_BIT,
GL_NEAREST);
}
#ifndef OPENGLES
// Now handle the other color buffers.
int next = GL_COLOR_ATTACHMENT1_EXT;
if (_fb_properties.is_stereo()) {
@ -1630,6 +1676,7 @@ resolve_multisamples() {
GL_COLOR_BUFFER_BIT, GL_NEAREST);
next += 1;
}
#ifndef OPENGLES
for (int i = 0; i < _fb_properties.get_aux_rgba(); ++i) {
glReadBuffer(next);
glDrawBuffer(next);

View File

@ -120,13 +120,15 @@ private:
int _rb_size_y;
int _rb_size_z;
// The texture or render buffer bound to each plane.
PT(Texture) _tex[RTP_COUNT];
// Stores the render buffers for each plane.
// _rbm stores the multisample renderbuffers.
GLuint _rb[RTP_COUNT];
// The render buffer for _fbo_multisample.
GLuint _rbm[RTP_COUNT];
// List of textures for which we might have to generate mipmaps
// after rendering one frame.
pvector<CLP(TextureContext)*> _texture_contexts;
// The cube map face we are currently drawing to or have just
// finished drawing to, or -1 if we are not drawing to a cube map.
int _bound_tex_page;

View File

@ -730,6 +730,38 @@ reset() {
}
}
_supports_tex_storage = false;
if (is_at_least_gl_version(4, 2) || has_extension("GL_ARB_texture_storage")) {
_supports_tex_storage = true;
_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)
get_extension_func("glTexStorage1D");
_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)
get_extension_func("glTexStorage2D");
_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)
get_extension_func("glTexStorage3D");
} else if (has_extension("GL_EXT_texture_storage")) { // GLES case
_supports_tex_storage = true;
_glTexStorage1D = (PFNGLTEXSTORAGE1DPROC)
get_extension_func("glTexStorage1DEXT");
_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC)
get_extension_func("glTexStorage2DEXT");
_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC)
get_extension_func("glTexStorage3DEXT");
}
if (_supports_tex_storage) {
if (_glTexStorage1D == NULL || _glTexStorage2D == NULL || _glTexStorage3D == NULL) {
GLCAT.warning()
<< "Immutable texture storage advertised as supported by OpenGL runtime, but could not get pointers to extension functions.\n";
_supports_tex_storage = false;
}
}
_supports_2d_texture_array = false;
#ifndef OPENGLES
_supports_2d_texture_array = has_extension("GL_EXT_texture_array");
@ -897,6 +929,9 @@ reset() {
(has_extension("GL_EXT_rescale_normal") || is_at_least_gl_version(1, 2));
#endif
_supports_packed_dabc = /*gl_support_packed_dabc &&*/
has_extension("GL_ARB_vertex_array_bgra") || has_extension("GL_EXT_vertex_array_bgra");
_supports_multisample =
has_extension("GL_ARB_multisample") || is_at_least_gl_version(1, 3);
@ -1282,6 +1317,8 @@ reset() {
_glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameteriv;
_glGenerateMipmap = glGenerateMipmap;
#else
//TODO: add ARB/3.0 version
_supports_framebuffer_object = false;
if (has_extension("GL_EXT_framebuffer_object")) {
_supports_framebuffer_object = true;
@ -1757,15 +1794,21 @@ reset() {
get_extension_func("glMemoryBarrierEXT");
glGetIntegerv(GL_MAX_IMAGE_UNITS_EXT, &_max_image_units);
} else {
_glBindImageTexture = NULL;
_glMemoryBarrier = NULL;
}
// Check availability of multi-bind functions.
_supports_multi_bind = false;
if (is_at_least_gl_version(4, 4) || has_extension("GL_ARB_multi_bind")) {
_glBindTextures = (PFNGLBINDTEXTURESPROC)
get_extension_func("glBindTextures");
_glBindImageTextures = (PFNGLBINDIMAGETEXTURESPROC)
get_extension_func("glBindImageTextures");
if (_glBindImageTextures != NULL) {
if (_glBindTextures != NULL && _glBindImageTextures != NULL) {
_supports_multi_bind = true;
} else {
GLCAT.warning()
@ -1782,6 +1825,24 @@ reset() {
<< "ARB_internalformat_query2 advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
}
}
_supports_bindless_texture = false;
if (has_extension("GL_ARB_bindless_texture")) {
_glGetTextureHandle = (PFNGLGETTEXTUREHANDLEPROC)
get_extension_func("glGetTextureHandleARB");
_glMakeTextureHandleResident = (PFNGLMAKETEXTUREHANDLERESIDENTPROC)
get_extension_func("glMakeTextureHandleResidentARB");
_glUniformHandleui64 = (PFNGLUNIFORMHANDLEUI64PROC)
get_extension_func("glUniformHandleui64ARB");
if (_glGetTextureHandle == NULL || _glMakeTextureHandleResident == NULL ||
_glUniformHandleui64 == NULL) {
GLCAT.warning()
<< "GL_ARB_bindless_texture advertised as supported by OpenGL runtime, but could not get pointers to extension function.\n";
} else {
_supports_bindless_texture = true;
}
}
#endif
#ifndef OPENGLES
@ -1879,11 +1940,11 @@ reset() {
#ifndef OPENGLES_1
_current_shader = (Shader *)NULL;
_current_shader_context = (CLP(ShaderContext) *)NULL;
_current_shader_context = (ShaderContext *)NULL;
_vertex_array_shader = (Shader *)NULL;
_vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
_vertex_array_shader_context = (ShaderContext *)NULL;
_texture_binding_shader = (Shader *)NULL;
_texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
_texture_binding_shader_context = (ShaderContext *)NULL;
#endif
#ifdef OPENGLES_2
@ -2508,17 +2569,17 @@ end_frame(Thread *current_thread) {
if (_vertex_array_shader_context != 0) {
_vertex_array_shader_context->disable_shader_vertex_arrays();
_vertex_array_shader = (Shader *)NULL;
_vertex_array_shader_context = (CLP(ShaderContext) *)NULL;
_vertex_array_shader_context = (ShaderContext *)NULL;
}
if (_texture_binding_shader_context != 0) {
_texture_binding_shader_context->disable_shader_texture_bindings();
_texture_binding_shader = (Shader *)NULL;
_texture_binding_shader_context = (CLP(ShaderContext) *)NULL;
_texture_binding_shader_context = (ShaderContext *)NULL;
}
if (_current_shader_context != 0) {
_current_shader_context->unbind();
_current_shader = (Shader *)NULL;
_current_shader_context = (CLP(ShaderContext) *)NULL;
_current_shader_context = (ShaderContext *)NULL;
}
#endif
@ -3008,13 +3069,17 @@ update_standard_vertex_arrays(bool force) {
} else
#endif // NDEBUG
if (_data_reader->get_color_info(array_reader, num_values, numeric_type,
start, stride) &&
numeric_type != Geom::NT_packed_dabc) {
start, stride)) {
if (!setup_array_data(client_pointer, array_reader, force)) {
return false;
}
glColorPointer(num_values, get_numeric_type(numeric_type),
stride, client_pointer + start);
if (numeric_type == Geom::NT_packed_dabc) {
glColorPointer(GL_BGRA, GL_UNSIGNED_BYTE,
stride, client_pointer + start);
} else {
glColorPointer(num_values, get_numeric_type(numeric_type),
stride, client_pointer + start);
}
glEnableClientState(GL_COLOR_ARRAY);
} else {
glDisableClientState(GL_COLOR_ARRAY);
@ -3737,6 +3802,54 @@ end_draw_primitives() {
report_my_gl_errors();
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::issue_memory_barrier
// Access: Public
// Description: Issues the given memory barriers, and clears the
// list of textures marked as incoherent for the given
// bits.
////////////////////////////////////////////////////////////////////
void CLP(GraphicsStateGuardian)::
issue_memory_barrier(GLbitfield barriers) {
#ifndef OPENGLES
if (!gl_enable_memory_barriers || _glMemoryBarrier == NULL) {
return;
}
if (GLCAT.is_debug()) {
GLCAT.debug() << "Issuing memory barriers:";
}
_glMemoryBarrier(barriers);
// Indicate that barriers no longer need to be issued for
// the relevant lists of textures.
if (barriers & GL_TEXTURE_FETCH_BARRIER_BIT) {
_textures_needing_fetch_barrier.clear();
GLCAT.debug(false) << " texture_fetch";
}
if (barriers & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) {
_textures_needing_image_access_barrier.clear();
GLCAT.debug(false) << " shader_image_access";
}
if (barriers & GL_TEXTURE_UPDATE_BARRIER_BIT) {
_textures_needing_update_barrier.clear();
GLCAT.debug(false) << " texture_update";
}
if (barriers & GL_FRAMEBUFFER_BARRIER_BIT) {
_textures_needing_framebuffer_barrier.clear();
GLCAT.debug(false) << " framebuffer";
}
GLCAT.debug(false) << "\n";
report_my_gl_errors();
#endif // OPENGLES
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::prepare_texture
// Access: Public, Virtual
@ -3783,11 +3896,9 @@ prepare_texture(Texture *tex, int view) {
break;
}
CLP(TextureContext) *gtc = new CLP(TextureContext)(_prepared_objects, tex, view);
glGenTextures(1, &gtc->_index);
CLP(TextureContext) *gtc = new CLP(TextureContext)(this, _prepared_objects, tex, view);
report_my_gl_errors();
apply_texture(gtc);
return gtc;
}
@ -3809,14 +3920,14 @@ prepare_texture(Texture *tex, int view) {
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
update_texture(TextureContext *tc, bool force) {
apply_texture(tc);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
if (gtc->was_image_modified() || !gtc->_already_applied) {
// If the texture image was modified, reload the texture. This
// means we also re-specify the properties for good measure.
specify_texture(gtc);
if (gtc->was_image_modified() || !gtc->_has_storage) {
// If the texture image was modified, reload the texture.
apply_texture(tc);
if (gtc->was_properties_modified()) {
specify_texture(gtc);
}
bool okflag = upload_texture(gtc, force);
if (!okflag) {
GLCAT.error()
@ -3827,6 +3938,7 @@ update_texture(TextureContext *tc, bool force) {
} else if (gtc->was_properties_modified()) {
// If only the properties have been modified, we don't necessarily
// need to reload the texture.
apply_texture(tc);
if (specify_texture(gtc)) {
// Actually, looks like the texture *does* need to be reloaded.
gtc->mark_needs_reload();
@ -3843,6 +3955,7 @@ update_texture(TextureContext *tc, bool force) {
gtc->mark_loaded();
}
}
gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru);
report_my_gl_errors();
@ -3860,11 +3973,6 @@ update_texture(TextureContext *tc, bool force) {
void CLP(GraphicsStateGuardian)::
release_texture(TextureContext *tc) {
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
glDeleteTextures(1, &gtc->_index);
report_my_gl_errors();
gtc->_index = 0;
delete gtc;
}
@ -4613,17 +4721,17 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
bool uses_mipmaps = tex->uses_mipmaps() && !gl_ignore_mipmaps;
if (uses_mipmaps) {
#ifndef OPENGLES_2
if (_supports_generate_mipmap) {
glTexParameteri(target, GL_GENERATE_MIPMAP, true);
} else {
#ifndef OPENGLES_2
if (_glGenerateMipmap == NULL) {
glTexParameteri(target, GL_GENERATE_MIPMAP, true);
}
#endif
} else {
// If we can't auto-generate mipmaps, do without mipmaps.
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
uses_mipmaps = false;
#ifndef OPENGLES_2
}
#endif
}
bool new_image = needs_reload || gtc->was_image_modified();
@ -4641,7 +4749,7 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
}
}
if (!gtc->_already_applied ||
if (!gtc->_has_storage ||
internal_format != gtc->_internal_format ||
uses_mipmaps != gtc->_uses_mipmaps ||
width != gtc->_width ||
@ -4652,6 +4760,18 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
new_image = true;
}
if (new_image && gtc->_immutable) {
gtc->reset_data();
glBindTexture(target, gtc->_index);
}
#ifndef OPENGLES
if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
// Make sure that any incoherent writes to this texture have been synced.
issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
#endif
if (z >= 0) {
if (new_image) {
// These won't be used because we pass a NULL image, but we still
@ -4675,7 +4795,11 @@ framebuffer_copy_to_texture(Texture *tex, int view, int z,
}
}
gtc->_already_applied = true;
if (uses_mipmaps && _glGenerateMipmap != NULL) {
_glGenerateMipmap(target);
}
gtc->_has_storage = true;
gtc->_uses_mipmaps = uses_mipmaps;
gtc->_internal_format = internal_format;
gtc->_width = width;
@ -4975,7 +5099,7 @@ do_issue_shade_model() {
void CLP(GraphicsStateGuardian)::
do_issue_shader(bool state_has_changed) {
#ifndef OPENGLES_1
CLP(ShaderContext) *context = 0;
ShaderContext *context = 0;
Shader *shader = (Shader *)(_target_shader->get_shader());
#ifdef OPENGLES_2
@ -4986,13 +5110,13 @@ do_issue_shader(bool state_has_changed) {
#endif
if (shader) {
context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
context = shader->prepare_now(get_prepared_objects(), this);
}
#ifdef OPENGLES_2
// If it failed, try applying the default shader.
if (shader != _default_shader && (context == 0 || !context->valid())) {
shader = _default_shader;
context = (CLP(ShaderContext) *)(shader->prepare_now(get_prepared_objects(), this));
context = shader->prepare_now(get_prepared_objects(), this);
}
#endif
@ -8421,6 +8545,7 @@ update_standard_texture_bindings() {
#endif
continue;
}
apply_texture(tc);
if (stage->involves_color_scale() && _color_scale_enabled) {
LColor color = stage->get_color();
@ -8659,6 +8784,8 @@ update_show_usage_texture_bindings(int show_stage_index) {
GLuint index;
glGenTextures(1, &index);
glBindTexture(GL_TEXTURE_2D, index);
//TODO: this could be a lot simpler with glTexStorage2D
// followed by a call to glClearTexImage.
upload_usage_texture(texture->get_x_size(), texture->get_y_size());
_usage_textures[key] = index;
@ -8730,7 +8857,7 @@ upload_usage_texture(int width, int height) {
}
glTexImage2D(GL_TEXTURE_2D, n, GL_RGBA, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, buffer);
GL_RGBA, GL_UNSIGNED_BYTE, buffer);
if (width == 1 && height == 1) {
// That was the last mipmap level.
break;
@ -9106,6 +9233,8 @@ do_issue_tex_gen() {
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
specify_texture(CLP(TextureContext) *gtc) {
nassertr(gtc->_handle == 0 /* can't modify tex with active handle */, false);
Texture *tex = gtc->get_texture();
GLenum target = get_texture_target(tex->get_texture_type());
@ -9153,13 +9282,10 @@ specify_texture(CLP(TextureContext) *gtc) {
if (!tex->might_have_ram_image()) {
// If it's a dynamically generated texture (that is, the RAM image
// isn't available so it didn't pass through the CPU), we should
// enable GL-generated mipmaps here if we can.
if (_supports_generate_mipmap) {
#ifndef OPENGLES_2
glTexParameteri(target, GL_GENERATE_MIPMAP, uses_mipmaps);
#endif
} else {
// Otherwise, don't try to use mipmaps.
// enable GL-generated mipmaps if we can.
if (!_supports_generate_mipmap) {
// However, if the GPU doesn't support mipmap generation, we
// have to turn it off.
uses_mipmaps = false;
}
}
@ -9169,13 +9295,6 @@ specify_texture(CLP(TextureContext) *gtc) {
glTexParameteri(target, GL_TEXTURE_MAG_FILTER,
get_texture_filter_type(magfilter, true));
#ifndef OPENGLES
if (!uses_mipmaps) {
// NVIDIA drivers complain if we don't do this.
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, 0);
}
#endif
// Set anisotropic filtering.
if (_supports_anisotropy) {
PN_stdfloat anisotropy = tex->get_effective_anisotropic_degree();
@ -9294,20 +9413,6 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
image_compression = Texture::CM_off;
}
if (GLCAT.is_debug()) {
if (image.is_null()) {
GLCAT.debug()
<< "Got NULL image: " << tex->get_name() << "\n";
}
}
/*
if (image.is_null()) {
// If we don't have an image, we can't upload.
return false;
}
*/
int mipmap_bias = 0;
int width = tex->get_x_size();
@ -9318,6 +9423,23 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
GLint external_format = get_external_image_format(tex);
GLenum component_type = get_component_type(tex->get_component_type());
if (GLCAT.is_debug()) {
if (image.is_null()) {
GLCAT.debug()
<< "loading texture with NULL image";
} else if (image_compression != Texture::CM_off) {
GLCAT.debug()
<< "loading pre-compressed texture";
} else if (is_compressed_format(internal_format)) {
GLCAT.debug()
<< "loading compressed texture";
} else {
GLCAT.debug()
<< "loading uncompressed texture";
}
GLCAT.debug(false) << " " << tex->get_name() << "\n";
}
// Ensure that the texture fits within the GL's specified limits.
// Need to split dimensions because of texture arrays
int max_dimension_x;
@ -9383,13 +9505,16 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
}
}
width = tex->get_expected_mipmap_x_size(mipmap_bias);
height = tex->get_expected_mipmap_y_size(mipmap_bias);
depth = tex->get_expected_mipmap_z_size(mipmap_bias);
if (mipmap_bias != 0) {
GLCAT.info()
<< "Reducing image " << tex->get_name()
<< " from " << width << " x " << height << " x " << depth << " to "
<< tex->get_expected_mipmap_x_size(mipmap_bias) << " x "
<< tex->get_expected_mipmap_y_size(mipmap_bias) << " x "
<< tex->get_expected_mipmap_z_size(mipmap_bias) << "\n";
<< " from " << tex->get_x_size() << " x " << tex->get_y_size()
<< " x " << tex->get_z_size() << " to "
<< width << " x " << height << " x " << depth << "\n";
}
}
@ -9416,17 +9541,145 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
GLenum target = get_texture_target(tex->get_texture_type());
bool uses_mipmaps = (tex->uses_mipmaps() && !gl_ignore_mipmaps) || gl_force_mipmaps;
#ifndef NDEBUG
if (gl_force_mipmaps) {
uses_mipmaps = true;
bool needs_reload = false;
if (!gtc->_has_storage ||
gtc->_uses_mipmaps != uses_mipmaps ||
gtc->_internal_format != internal_format ||
gtc->_width != width ||
gtc->_height != height ||
gtc->_depth != depth) {
// We need to reload a new GL Texture object.
needs_reload = true;
}
if (needs_reload && gtc->_immutable) {
GLCAT.warning() << "Attempt to modify texture with immutable storage, recreating texture.\n";
gtc->reset_data();
glBindTexture(target, gtc->_index);
}
if (needs_reload) {
gtc->_generate_mipmaps = false;
int num_levels = 1;
CPTA_uchar image = tex->get_ram_mipmap_image(mipmap_bias);
// Figure out whether mipmaps will be generated by the GPU or by
// Panda (or not at all), and how many mipmap levels should be created.
if (image.is_null()) {
if (uses_mipmaps) {
if (_supports_generate_mipmap) {
num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias;
gtc->_generate_mipmaps = true;
} else {
// If it can't, do without mipmaps.
num_levels = 1;
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
}
} else {
if (uses_mipmaps) {
num_levels = tex->get_num_ram_mipmap_images() - mipmap_bias;
if (num_levels <= 1) {
// No RAM mipmap levels available. Should we generate some?
if (!_supports_generate_mipmap || !driver_generate_mipmaps ||
image_compression != Texture::CM_off) {
// Yes, the GL can't or won't generate them, so we need to.
// Note that some drivers (nVidia) will *corrupt memory* if
// you ask them to generate mipmaps for a pre-compressed
// texture.
tex->generate_ram_mipmap_images();
num_levels = tex->get_num_ram_mipmap_images() - mipmap_bias;
}
}
if (num_levels <= 1) {
// We don't have mipmap levels in RAM. Ask the GL to generate
// them if it can.
if (_supports_generate_mipmap) {
num_levels = tex->get_expected_num_mipmap_levels() - mipmap_bias;
gtc->_generate_mipmaps = true;
} else {
// If it can't, do without mipmaps.
glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
num_levels = 1;
}
}
}
}
#ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL.
if (is_at_least_gl_version(1, 2)) {
// By the time we get here, we have a pretty good prediction for
// the number of mipmaps we're going to have, so tell the GL that's
// all it's going to get.
glTexParameteri(target, GL_TEXTURE_MAX_LEVEL, num_levels - 1);
}
#endif
bool success = true;
#ifndef OPENGLES_2
if (gtc->_generate_mipmaps && _glGenerateMipmap == NULL) {
// The old, deprecated way to generate mipmaps.
glTexParameteri(target, GL_GENERATE_MIPMAP, GL_TRUE);
}
#endif
GLenum target = get_texture_target(tex->get_texture_type());
// Allocate immutable storage for the texture, after which we can subload it.
// Pre-allocating storage using glTexStorage is more efficient than using glTexImage
// to load all of the individual images one by one later, but we are not allowed to
// change the texture size or number of mipmap levels after this point.
if (gl_immutable_texture_storage && _supports_tex_storage && !gtc->_has_storage) {
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "allocating storage for texture " << tex->get_name() << ", " << width
<< " x " << height << " x " << depth << ", mipmaps " << num_levels
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
}
switch (tex->get_texture_type()) {
case Texture::TT_1d_texture:
_glTexStorage1D(target, num_levels, internal_format, width);
break;
case Texture::TT_2d_texture:
case Texture::TT_cube_map:
_glTexStorage2D(target, num_levels, internal_format, width, height);
break;
case Texture::TT_3d_texture:
case Texture::TT_2d_texture_array:
_glTexStorage3D(target, num_levels, internal_format, width, height, depth);
break;
}
gtc->_has_storage = true;
gtc->_immutable = true;
gtc->_uses_mipmaps = uses_mipmaps;
gtc->_internal_format = internal_format;
gtc->_width = width;
gtc->_height = height;
gtc->_depth = depth;
needs_reload = false;
}
} else {
// Maybe we need to generate mipmaps on the CPU.
if (!image.is_null() && uses_mipmaps) {
if (tex->get_num_ram_mipmap_images() - mipmap_bias <= 1) {
// No RAM mipmap levels available. Should we generate some?
if (!_supports_generate_mipmap || !driver_generate_mipmaps ||
image_compression != Texture::CM_off) {
// Yes, the GL can't or won't generate them, so we need to.
// Note that some drivers (nVidia) will *corrupt memory* if
// you ask them to generate mipmaps for a pre-compressed
// texture.
tex->generate_ram_mipmap_images();
}
}
}
}
bool success = true;
if (tex->get_texture_type() == Texture::TT_cube_map) {
// A cube map must load six different 2-d images (which are stored
// as the six pages of the system ram image).
@ -9437,37 +9690,37 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
nassertr(target == GL_TEXTURE_CUBE_MAP, false);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
internal_format, external_format, component_type,
true, 0, image_compression);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
internal_format, external_format, component_type,
true, 1, image_compression);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
internal_format, external_format, component_type,
true, 2, image_compression);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
internal_format, external_format, component_type,
true, 3, image_compression);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
internal_format, external_format, component_type,
true, 4, image_compression);
success = success && upload_texture_image
(gtc, uses_mipmaps, mipmap_bias,
(gtc, needs_reload, uses_mipmaps, mipmap_bias,
GL_TEXTURE_CUBE_MAP, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
internal_format, external_format, component_type,
true, 5, image_compression);
@ -9475,20 +9728,32 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
} else {
// Any other kind of texture can be loaded all at once.
success = upload_texture_image
(gtc, uses_mipmaps, mipmap_bias, target, target,
internal_format, external_format, component_type,
false, 0, image_compression);
(gtc, needs_reload, uses_mipmaps, mipmap_bias, target,
target, internal_format, external_format,
component_type, false, 0, image_compression);
}
if (gtc->_generate_mipmaps && _glGenerateMipmap != NULL) {
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "generating mipmaps for texture " << tex->get_name() << ", "
<< width << " x " << height << " x " << depth
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
}
_glGenerateMipmap(target);
}
maybe_gl_finish();
if (success) {
gtc->_already_applied = true;
gtc->_uses_mipmaps = uses_mipmaps;
gtc->_internal_format = internal_format;
gtc->_width = width;
gtc->_height = height;
gtc->_depth = depth;
if (needs_reload) {
gtc->_has_storage = true;
gtc->_uses_mipmaps = uses_mipmaps;
gtc->_internal_format = internal_format;
gtc->_width = width;
gtc->_height = height;
gtc->_depth = depth;
}
if (!image.is_null()) {
gtc->update_data_size_bytes(get_texture_memory_size(tex));
@ -9539,7 +9804,7 @@ upload_texture(CLP(TextureContext) *gtc, bool force) {
// e.g. GL_TEXTURE_CUBE_MAP_POSITIVE_X.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
upload_texture_image(CLP(TextureContext) *gtc,
upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
bool uses_mipmaps, int mipmap_bias,
GLenum texture_target, GLenum page_target,
GLint internal_format,
@ -9566,111 +9831,40 @@ upload_texture_image(CLP(TextureContext) *gtc,
int height = tex->get_expected_mipmap_y_size(mipmap_bias);
int depth = tex->get_expected_mipmap_z_size(mipmap_bias);
if (GLCAT.is_debug()) {
if (image_compression != Texture::CM_off) {
GLCAT.debug()
<< "loading pre-compressed texture " << tex->get_name() << "\n";
} else if (is_compressed_format(internal_format)) {
GLCAT.debug()
<< "compressing texture " << tex->get_name() << "\n";
} else {
GLCAT.debug()
<< "loading uncompressed texture " << tex->get_name() << "\n";
}
GLCAT.debug()
<< "page_target " << hex << page_target << dec << "\n";
}
// Determine the number of images to upload.
int num_ram_mipmap_levels = 0;
bool load_ram_mipmaps = false;
if (image.is_null()) {
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "Not loading NULL image " << tex->get_name() << "\n";
}
if (uses_mipmaps) {
if (_supports_generate_mipmap) {
#ifndef OPENGLES_2
glTexParameteri(texture_target, GL_GENERATE_MIPMAP, true);
#endif
} else {
// If it can't, do without mipmaps.
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
uses_mipmaps = false;
}
}
} else {
num_ram_mipmap_levels = 1;
if (!image.is_null()) {
if (uses_mipmaps) {
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
if (num_ram_mipmap_levels == 1) {
// No RAM mipmap levels available. Should we generate some?
if (!_supports_generate_mipmap || !driver_generate_mipmaps ||
image_compression != Texture::CM_off) {
// Yes, the GL can't or won't generate them, so we need to.
// Note that some drivers (nVidia) will *corrupt memory* if
// you ask them to generate mipmaps for a pre-compressed
// texture.
tex->generate_ram_mipmap_images();
num_ram_mipmap_levels = tex->get_num_ram_mipmap_images();
}
}
if (num_ram_mipmap_levels != 1) {
// We will load the mipmap levels from RAM. Don't ask the GL to
// generate them.
#ifndef OPENGLES_2
if (_supports_generate_mipmap) {
glTexParameteri(texture_target, GL_GENERATE_MIPMAP, false);
}
#endif
load_ram_mipmaps = true;
} else {
// We don't have mipmap levels in RAM. Ask the GL to generate
// them if it can.
if (_supports_generate_mipmap) {
#ifndef OPENGLES_2
glTexParameteri(texture_target, GL_GENERATE_MIPMAP, true);
#endif
} else {
// If it can't, do without mipmaps.
glTexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
uses_mipmaps = false;
}
}
} else {
num_ram_mipmap_levels = 1;
}
}
int highest_level = 0;
#ifdef OPENGLES // OpenGL ES doesn't support texture subloads.
static const bool needs_reload = true;
#else
bool needs_reload = false;
if (!gtc->_already_applied ||
gtc->_uses_mipmaps != uses_mipmaps ||
gtc->_internal_format != internal_format ||
gtc->_width != width ||
gtc->_height != height ||
gtc->_depth != depth) {
// We need to reload a new GL Texture object.
needs_reload = true;
#ifndef OPENGLES
if (needs_reload || num_ram_mipmap_levels > 0) {
// Make sure that any incoherent writes to this texture have been synced.
if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
}
#endif
if (!needs_reload) {
// Try to subload the image over the existing GL Texture object,
// possibly saving on texture memory fragmentation.
if (GLCAT.is_debug()) {
GLCAT.debug()
<< "subloading existing texture object, " << width << " x " << height
<< " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
if (num_ram_mipmap_levels == 0) {
GLCAT.debug()
<< "not loading NULL image for tex " << tex->get_name() << ", " << width << " x " << height
<< " x " << depth << ", z = " << z << ", uses_mipmaps = " << uses_mipmaps << "\n";
} else {
GLCAT.debug()
<< "updating image data of texture " << tex->get_name() << ", " << width << " x " << height
<< " x " << depth << ", z = " << z << ", mipmaps " << num_ram_mipmap_levels
<< ", uses_mipmaps = " << uses_mipmaps << "\n";
}
}
for (int n = mipmap_bias; n < num_ram_mipmap_levels; ++n) {
@ -9777,8 +9971,6 @@ upload_texture_image(CLP(TextureContext) *gtc,
}
break;
}
highest_level = n;
}
// Did that fail? If it did, we'll immediately try again, this
@ -9793,7 +9985,6 @@ upload_texture_image(CLP(TextureContext) *gtc,
needs_reload = true;
}
}
#endif // OPENGLES
if (needs_reload) {
// Load the image up from scratch, creating a new GL Texture
@ -9805,7 +9996,16 @@ upload_texture_image(CLP(TextureContext) *gtc,
<< num_ram_mipmap_levels << ", uses_mipmaps = " << uses_mipmaps << "\n";
}
// If there is immutable storage, this is impossible to do, and we should
// not have gotten here at all.
nassertr(!gtc->_immutable, false);
if (num_ram_mipmap_levels == 0) {
if (GLCAT.is_debug()) {
GLCAT.debug()
<< " (initializing NULL image)\n";
}
if ((external_format == GL_DEPTH_STENCIL) && get_supports_depth_stencil()) {
#ifdef OPENGLES
component_type = GL_UNSIGNED_INT_24_8_OES;
@ -9844,6 +10044,12 @@ upload_texture_image(CLP(TextureContext) *gtc,
<< "No mipmap level " << n << " defined for " << tex->get_name()
<< "\n";
// No mipmap level n; stop here.
#ifndef OPENGLES
if (is_at_least_gl_version(1, 2)) {
// Tell the GL we have no more mipmaps for it to use.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, n - mipmap_bias);
}
#endif
break;
}
image_ptr = ptimage;
@ -9878,8 +10084,8 @@ upload_texture_image(CLP(TextureContext) *gtc,
case GL_TEXTURE_1D:
if (image_compression == Texture::CM_off) {
glTexImage1D(page_target, n - mipmap_bias, internal_format,
width, 0,
external_format, component_type, image_ptr);
width, 0,
external_format, component_type, image_ptr);
} else {
_glCompressedTexImage1D(page_target, n - mipmap_bias, external_format, width,
0, view_size, image_ptr);
@ -9932,15 +10138,13 @@ upload_texture_image(CLP(TextureContext) *gtc,
default:
if (image_compression == Texture::CM_off) {
glTexImage2D(page_target, n - mipmap_bias, internal_format,
width, height, 0,
external_format, component_type, image_ptr);
width, height, 0,
external_format, component_type, image_ptr);
} else {
_glCompressedTexImage2D(page_target, n - mipmap_bias, external_format, width, height,
0, view_size, image_ptr);
_glCompressedTexImage2D(page_target, n - mipmap_bias, external_format,
width, height, 0, view_size, image_ptr);
}
}
highest_level = n;
}
// Report the error message explicitly if the GL texture creation
@ -9951,29 +10155,11 @@ upload_texture_image(CLP(TextureContext) *gtc,
<< "GL texture creation failed for " << tex->get_name()
<< " : " << get_error_string(error_code) << "\n";
gtc->_already_applied = false;
gtc->_has_storage = false;
return false;
}
}
#ifndef OPENGLES // OpenGL ES doesn't have GL_TEXTURE_MAX_LEVEL.
if (is_at_least_gl_version(1, 2)) {
if (load_ram_mipmaps) {
// By the time we get here, we have successfully loaded a certain
// number of mipmap levels. Tell the GL that's all it's going to
// get.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, highest_level - mipmap_bias);
} else if (uses_mipmaps) {
// Since the mipmap levels were auto-generated and are therefore
// complete, make sure the GL doesn't remember some previous value
// for GL_TEXTURE_MAX_LEVEL from the above call--set it to the
// full count of mipmap levels.
glTexParameteri(texture_target, GL_TEXTURE_MAX_LEVEL, tex->get_expected_num_mipmap_levels() - mipmap_bias - 1);
}
}
#endif
report_my_gl_errors();
return true;
@ -10042,8 +10228,8 @@ upload_simple_texture(CLP(TextureContext) *gtc) {
#endif
glTexImage2D(GL_TEXTURE_2D, 0, internal_format,
width, height, 0,
external_format, component_type, image_ptr);
width, height, 0,
external_format, component_type, image_ptr);
gtc->mark_simple_loaded();
@ -10207,6 +10393,14 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
if (target == GL_NONE) {
return false;
}
#ifndef OPENGLES
// Make sure any incoherent writes to the texture have been synced.
if (gtc->needs_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT)) {
issue_memory_barrier(GL_TEXTURE_UPDATE_BARRIER_BIT);
}
#endif
glBindTexture(target, gtc->_index);
Texture *tex = gtc->get_texture();
@ -10424,6 +10618,7 @@ do_extract_texture_data(CLP(TextureContext) *gtc) {
#endif
#ifndef OPENGLES
case GL_R32I:
type = Texture::T_int;
format = Texture::F_r32i;
break;
#endif
@ -10656,6 +10851,7 @@ extract_texture_image(PTA_uchar &image, size_t &page_size,
nassertr(false, false);
return false;
#else
if (target == GL_TEXTURE_CUBE_MAP) {
// A cube map, compressed or uncompressed. This we must extract
// one page at a time.

View File

@ -134,6 +134,9 @@ typedef void (APIENTRYP PFNGLCURRENTPALETTEMATRIXOESPROC) (GLuint matrixpalettei
typedef void (APIENTRYP PFNGLLOADPALETTEFROMMODELVIEWMATRIXOESPROC) (void);
typedef void (APIENTRYP PFNGLMATRIXINDEXPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLWEIGHTPOINTEROESPROC) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer);
typedef void (APIENTRYP PFNGLTEXSTORAGE1DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width);
typedef void (APIENTRYP PFNGLTEXSTORAGE2DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
typedef void (APIENTRYP PFNGLTEXSTORAGE3DPROC) (GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
#ifndef OPENGLES_1
// GLSL shader functions
@ -177,12 +180,29 @@ typedef void (APIENTRYP PFNGLVERTEXATTRIBPOINTERPROC) (GLuint index, GLint size,
typedef void (APIENTRYP PFNGLPROGRAMPARAMETERIEXTPROC) (GLuint program, GLenum pname, GLint value);
typedef void (APIENTRYP PFNGLDRAWARRAYSINSTANCEDPROC) (GLenum mode, GLint first, GLsizei count, GLsizei primcount);
typedef void (APIENTRYP PFNGLDRAWELEMENTSINSTANCEDPROC) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices, GLsizei primcount);
typedef void (APIENTRYP PFNGLBINDTEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP PFNGLBINDIMAGETEXTUREPROC) (GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
typedef void (APIENTRYP PFNGLBINDIMAGETEXTURESPROC) (GLuint first, GLsizei count, const GLuint *textures);
typedef void (APIENTRYP PFNGLDISPATCHCOMPUTEPROC) (GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
typedef void (APIENTRYP PFNGLMEMORYBARRIERPROC) (GLbitfield barriers);
typedef void (APIENTRYP PFNGLGETPROGRAMBINARYPROC) (GLuint program, GLsizei bufsize, GLsizei *length, GLenum *binaryFormat, void *binary);
typedef void (APIENTRYP PFNGLGETINTERNALFORMATIVPROC) (GLenum target, GLenum internalformat, GLenum pname, GLsizei bufSize, GLint *params);
typedef GLuint64 (APIENTRYP PFNGLGETTEXTUREHANDLEPROC) (GLuint texture);
typedef GLuint64 (APIENTRYP PFNGLGETTEXTURESAMPLERHANDLEPROC) (GLuint texture, GLuint sampler);
typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
typedef void (APIENTRYP PFNGLMAKETEXTUREHANDLENONRESIDENTPROC) (GLuint64 handle);
typedef GLuint64 (APIENTRYP PFNGLGETIMAGEHANDLEPROC) (GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum format);
typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLERESIDENTPROC) (GLuint64 handle, GLenum access);
typedef void (APIENTRYP PFNGLMAKEIMAGEHANDLENONRESIDENTPROC) (GLuint64 handle);
typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64PROC) (GLint location, GLuint64 value);
typedef void (APIENTRYP PFNGLUNIFORMHANDLEUI64VPROC) (GLint location, GLsizei count, const GLuint64 *value);
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64PROC) (GLuint program, GLint location, GLuint64 value);
typedef void (APIENTRYP PFNGLPROGRAMUNIFORMHANDLEUI64VPROC) (GLuint program, GLint location, GLsizei count, const GLuint64 *values);
typedef GLboolean (APIENTRYP PFNGLISTEXTUREHANDLERESIDENTPROC) (GLuint64 handle);
typedef GLboolean (APIENTRYP PFNGLISIMAGEHANDLERESIDENTPROC) (GLuint64 handle);
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64PROC) (GLuint index, GLuint64EXT x);
typedef void (APIENTRYP PFNGLVERTEXATTRIBL1UI64VPROC) (GLuint index, const GLuint64EXT *v);
typedef void (APIENTRYP PFNGLGETVERTEXATTRIBLUI64VPROC) (GLuint index, GLenum pname, GLuint64EXT *params);
#endif // OPENGLES
#endif // __EDG__
@ -242,6 +262,8 @@ public:
bool force);
virtual void end_draw_primitives();
void issue_memory_barrier(GLbitfield barrier);
virtual TextureContext *prepare_texture(Texture *tex, int view);
virtual bool update_texture(TextureContext *tc, bool force);
virtual void release_texture(TextureContext *tc);
@ -448,7 +470,7 @@ protected:
bool specify_texture(CLP(TextureContext) *gtc);
bool apply_texture(TextureContext *tc);
bool upload_texture(CLP(TextureContext) *gtc, bool force);
bool upload_texture_image(CLP(TextureContext) *gtc,
bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload,
bool uses_mipmaps, int mipmap_bias,
GLenum texture_target, GLenum page_target,
GLint internal_format, GLint external_format,
@ -506,12 +528,12 @@ protected:
bool _vertex_blending_enabled;
#ifndef OPENGLES_1
PT(Shader) _current_shader;
CLP(ShaderContext) *_current_shader_context;
PT(Shader) _vertex_array_shader;
CLP(ShaderContext) *_vertex_array_shader_context;
PT(Shader) _texture_binding_shader;
CLP(ShaderContext) *_texture_binding_shader_context;
PT(Shader) _current_shader;
ShaderContext *_current_shader_context;
PT(Shader) _vertex_array_shader;
ShaderContext *_vertex_array_shader_context;
PT(Shader) _texture_binding_shader;
ShaderContext *_texture_binding_shader_context;
#endif
#ifdef OPENGLES_2
static PT(Shader) _default_shader;
@ -590,6 +612,11 @@ public:
PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
PFNGLCOPYTEXSUBIMAGE3DPROC _glCopyTexSubImage3D;
bool _supports_tex_storage;
PFNGLTEXSTORAGE1DPROC _glTexStorage1D;
PFNGLTEXSTORAGE2DPROC _glTexStorage2D;
PFNGLTEXSTORAGE3DPROC _glTexStorage3D;
PFNGLCOMPRESSEDTEXIMAGE1DPROC _glCompressedTexImage1D;
PFNGLCOMPRESSEDTEXIMAGE2DPROC _glCompressedTexImage2D;
PFNGLCOMPRESSEDTEXIMAGE3DPROC _glCompressedTexImage3D;
@ -600,6 +627,7 @@ public:
bool _supports_bgr;
bool _supports_rescale_normal;
bool _supports_packed_dabc;
bool _supports_multitexture;
PFNGLACTIVETEXTUREPROC _glActiveTexture;
@ -661,6 +689,7 @@ public:
PFNGLDRAWBUFFERSPROC _glDrawBuffers;
int _max_fb_samples;
bool _supports_viewport_arrays;
bool _supports_bindless_texture;
PFNGLGENQUERIESPROC _glGenQueries;
PFNGLBEGINQUERYPROC _glBeginQuery;
@ -714,6 +743,7 @@ public:
PFNGLPATCHPARAMETERIPROC _glPatchParameteri;
PFNGLDRAWARRAYSINSTANCEDPROC _glDrawArraysInstanced;
PFNGLDRAWELEMENTSINSTANCEDPROC _glDrawElementsInstanced;
PFNGLBINDTEXTURESPROC _glBindTextures;
PFNGLBINDIMAGETEXTUREPROC _glBindImageTexture;
PFNGLBINDIMAGETEXTURESPROC _glBindImageTextures;
PFNGLDISPATCHCOMPUTEPROC _glDispatchCompute;
@ -723,6 +753,11 @@ public:
PFNGLVIEWPORTARRAYVPROC _glViewportArrayv;
PFNGLSCISSORARRAYVPROC _glScissorArrayv;
PFNGLDEPTHRANGEARRAYVPROC _glDepthRangeArrayv;
PFNGLGETTEXTUREHANDLEPROC _glGetTextureHandle;
PFNGLMAKETEXTUREHANDLERESIDENTPROC _glMakeTextureHandleResident;
PFNGLMAKETEXTUREHANDLENONRESIDENTPROC _glMakeTextureHandleNonResident;
PFNGLUNIFORMHANDLEUI64PROC _glUniformHandleui64;
PFNGLUNIFORMHANDLEUI64VPROC _glUniformHandleui64v;
#endif // OPENGLES
GLenum _edge_clamp;
@ -740,6 +775,15 @@ public:
DeletedDisplayLists _deleted_display_lists;
DeletedDisplayLists _deleted_queries;
#ifndef OPENGLES
// Stores textures for which memory bariers should be issued.
typedef pset<TextureContext*> TextureSet;
TextureSet _textures_needing_fetch_barrier;
TextureSet _textures_needing_image_access_barrier;
TextureSet _textures_needing_update_barrier;
TextureSet _textures_needing_framebuffer_barrier;
#endif
//RenderState::SlotMask _inv_state_mask;
bool _check_errors;
@ -798,5 +842,3 @@ private:
};
#include "glGraphicsStateGuardian_src.I"

View File

@ -195,18 +195,12 @@ CLP(ShaderContext)::
CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext(s) {
_glgsg = glgsg;
_glsl_program = 0;
_glsl_vshader = 0;
_glsl_fshader = 0;
_glsl_gshader = 0;
_glsl_tcshader = 0;
_glsl_teshader = 0;
_glsl_cshader = 0;
_uses_standard_vertex_arrays = false;
nassertv(s->get_language() == Shader::SL_GLSL);
// We compile and analyze the shader here, instead of in shader.cxx, to avoid gobj getting a dependency on GL stuff.
if (!glsl_compile_shader()) {
if (!glsl_compile_and_link()) {
release_resources();
s->_error_flag = true;
return;
@ -344,6 +338,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
continue;
}
if (size > 7 && noprefix.substr(0, 7) == "Texture") {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = 0;
@ -376,7 +371,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
s->_mat_spec.push_back(bind);
continue;
} else if (noprefix == "Material.specular") {
bind._piece = Shader::SMP_row3;
bind._piece = Shader::SMP_row3x3;
s->_mat_spec.push_back(bind);
continue;
}
@ -463,6 +458,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_UNSIGNED_INT_SAMPLER_1D:
case GL_SAMPLER_1D_SHADOW:
case GL_SAMPLER_1D: {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = InternalName::make(param_name);
@ -475,6 +471,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_SAMPLER_2D_SHADOW:
#endif
case GL_SAMPLER_2D: {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = InternalName::make(param_name);
@ -487,6 +484,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_UNSIGNED_INT_SAMPLER_3D:
#endif
case GL_SAMPLER_3D: {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = InternalName::make(param_name);
@ -500,6 +498,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_SAMPLER_CUBE_SHADOW:
#endif
case GL_SAMPLER_CUBE: {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = InternalName::make(param_name);
@ -508,7 +507,11 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
s->_tex_spec.push_back(bind);
continue; }
#ifndef OPENGLES
case GL_INT_SAMPLER_2D_ARRAY:
case GL_UNSIGNED_INT_SAMPLER_2D_ARRAY:
case GL_SAMPLER_2D_ARRAY_SHADOW:
case GL_SAMPLER_2D_ARRAY: {
_glgsg->_glUniform1i(p, s->_tex_spec.size());
Shader::ShaderTexSpec bind;
bind._id = arg_id;
bind._name = InternalName::make(param_name);
@ -584,6 +587,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
}
bind._type = Shader::SPT_int;
bind._arg = InternalName::make(param_name);
bind._dim[0] = 1;
bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@ -611,6 +615,7 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
// bind once and then forget about it.
_glgsg->_glUniform1i(p, imgunitno++);
_glsl_img_inputs.push_back(InternalName::make(param_name));
_glsl_img_textures.push_back(NULL);
continue;
#endif
default:
@ -661,6 +666,23 @@ CLP(ShaderContext)(CLP(GraphicsStateGuardian) *glgsg, Shader *s) : ShaderContext
case GL_FLOAT_MAT3: bind._dim[1] = 9; break;
case GL_FLOAT_MAT4: bind._dim[1] = 16; break;
}
switch (param_type) {
case GL_BOOL:
case GL_BOOL_VEC2:
case GL_BOOL_VEC3:
case GL_BOOL_VEC4:
bind._type = Shader::SPT_unknown;
break;
case GL_INT:
case GL_INT_VEC2:
case GL_INT_VEC3:
case GL_INT_VEC4:
bind._type = Shader::SPT_int;
break;
default:
bind._type = Shader::SPT_float;
break;
}
bind._arg = InternalName::make(param_name);
bind._dim[0] = param_size;
bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs;
@ -783,52 +805,21 @@ release_resources() {
return;
}
if (_glsl_program != 0) {
if (_glsl_vshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_vshader);
}
if (_glsl_fshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_fshader);
}
if (_glsl_gshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_gshader);
}
if (_glsl_tcshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_tcshader);
}
if (_glsl_teshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_teshader);
}
if (_glsl_cshader != 0) {
_glgsg->_glDetachShader(_glsl_program, _glsl_cshader);
GLSLShaders::const_iterator it;
for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
_glgsg->_glDetachShader(_glsl_program, *it);
}
_glgsg->_glDeleteProgram(_glsl_program);
_glsl_program = 0;
}
if (_glsl_vshader != 0) {
_glgsg->_glDeleteShader(_glsl_vshader);
_glsl_vshader = 0;
}
if (_glsl_fshader != 0) {
_glgsg->_glDeleteShader(_glsl_fshader);
_glsl_fshader = 0;
}
if (_glsl_gshader != 0) {
_glgsg->_glDeleteShader(_glsl_gshader);
_glsl_gshader = 0;
}
if (_glsl_tcshader != 0) {
_glgsg->_glDeleteShader(_glsl_tcshader);
_glsl_tcshader = 0;
}
if (_glsl_teshader != 0) {
_glgsg->_glDeleteShader(_glsl_teshader);
_glsl_teshader = 0;
}
if (_glsl_cshader != 0) {
_glgsg->_glDeleteShader(_glsl_cshader);
_glsl_cshader = 0;
GLSLShaders::const_iterator it;
for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
_glgsg->_glDeleteShader(*it);
}
_glsl_shaders.clear();
_glgsg->report_my_gl_errors();
}
@ -890,32 +881,33 @@ issue_parameters(int altered) {
// Iterate through _ptr parameters
for (int i=0; i<(int)_shader->_ptr_spec.size(); i++) {
if(altered & (_shader->_ptr_spec[i]._dep[0] | _shader->_ptr_spec[i]._dep[1])) {
const Shader::ShaderPtrSpec& _ptr = _shader->_ptr_spec[i];
const Shader::ShaderPtrSpec& spec = _shader->_ptr_spec[i];
if (altered & (spec._dep[0] | spec._dep[1])) {
Shader::ShaderPtrData* ptr_data =
const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(_ptr));
const_cast< Shader::ShaderPtrData*>(_glgsg->fetch_ptr_parameter(spec));
if (ptr_data == NULL) { //the input is not contained in ShaderPtrData
release_resources();
return;
}
GLint p = _glsl_parameter_map[_shader->_ptr_spec[i]._id._seqno];
GLint p = _glsl_parameter_map[spec._id._seqno];
switch (ptr_data->_type) {
case Shader::SPT_float:
switch (_ptr._dim[1]) {
case 1: _glgsg->_glUniform1fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
case 2: _glgsg->_glUniform2fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
case 3: _glgsg->_glUniform3fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
case 4: _glgsg->_glUniform4fv(p, _ptr._dim[0], (float*)ptr_data->_ptr); continue;
case 9: _glgsg->_glUniformMatrix3fv(p, _ptr._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
case 16: _glgsg->_glUniformMatrix4fv(p, _ptr._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
switch (spec._dim[1]) {
case 1: _glgsg->_glUniform1fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
case 2: _glgsg->_glUniform2fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
case 3: _glgsg->_glUniform3fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
case 4: _glgsg->_glUniform4fv(p, spec._dim[0], (float*)ptr_data->_ptr); continue;
case 9: _glgsg->_glUniformMatrix3fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
case 16: _glgsg->_glUniformMatrix4fv(p, spec._dim[0], GL_FALSE, (float*)ptr_data->_ptr); continue;
}
case Shader::SPT_int:
switch (_ptr._dim[1]) {
case 1: _glgsg->_glUniform1iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
case 2: _glgsg->_glUniform2iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
case 3: _glgsg->_glUniform3iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
case 4: _glgsg->_glUniform4iv(p, _ptr._dim[0], (int*)ptr_data->_ptr); continue;
switch (spec._dim[1]) {
case 1: _glgsg->_glUniform1iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
case 2: _glgsg->_glUniform2iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
case 3: _glgsg->_glUniform3iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
case 4: _glgsg->_glUniform4iv(p, spec._dim[0], (int*)ptr_data->_ptr); continue;
}
case Shader::SPT_double:
GLCAT.error() << "Passing double-precision shader inputs to GLSL shaders is not currently supported\n";
@ -1002,7 +994,9 @@ disable_shader_vertex_arrays() {
////////////////////////////////////////////////////////////////////
bool CLP(ShaderContext)::
update_shader_vertex_arrays(ShaderContext *prev, bool force) {
if (prev) prev->disable_shader_vertex_arrays();
if (prev) {
prev->disable_shader_vertex_arrays();
}
if (!valid()) {
return true;
}
@ -1040,8 +1034,14 @@ update_shader_vertex_arrays(ShaderContext *prev, bool force) {
const GLint p = _glsl_parameter_map[_shader->_var_spec[i]._id._seqno];
_glgsg->_glEnableVertexAttribArray(p);
_glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
GL_TRUE, stride, client_pointer + start);
if (numeric_type == GeomEnums::NT_packed_dabc) {
_glgsg->_glVertexAttribPointer(p, GL_BGRA, GL_UNSIGNED_BYTE,
GL_TRUE, stride, client_pointer + start);
} else {
_glgsg->_glVertexAttribPointer(p, num_values, _glgsg->get_numeric_type(numeric_type),
GL_TRUE, stride, client_pointer + start);
}
}
}
}
@ -1062,14 +1062,28 @@ disable_shader_texture_bindings() {
return;
}
#ifndef OPENGLES_2
for (int i=0; i<(int)_shader->_tex_spec.size(); i++) {
if (_shader->_tex_spec[i]._name == 0) {
_glgsg->_glActiveTexture(GL_TEXTURE0 + _shader->_tex_spec[i]._stage);
} else {
_glgsg->_glActiveTexture(GL_TEXTURE0 + _shader->_tex_spec[i]._stage + _stage_offset);
for (int i = 0; i < _shader->_tex_spec.size(); ++i) {
#ifndef OPENGLES
// Check if bindless was used, if so, there's nothing to unbind.
if (_glgsg->_supports_bindless_texture) {
GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
if (_glsl_uniform_handles.count(p) > 0) {
continue;
}
}
if (_glgsg->_supports_multi_bind) {
// There are non-bindless textures to unbind, and we're lazy,
// so let's go and unbind everything after this point using one
// multi-bind call, and then break out of the loop.
_glgsg->_glBindTextures(i, _shader->_tex_spec.size() - i, NULL);
break;
}
#endif
_glgsg->_glActiveTexture(GL_TEXTURE0 + i);
#ifndef OPENGLES
glBindTexture(GL_TEXTURE_1D, 0);
#endif // OPENGLES
@ -1087,22 +1101,29 @@ disable_shader_texture_bindings() {
if (_glgsg->_supports_cube_map) {
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
}
// This is probably faster - but maybe not as safe?
// cgGLDisableTextureParameter(p);
}
#endif // OPENGLES_2
_stage_offset = 0;
#ifndef OPENGLES
// Now unbind all the image units. Not sure if we *have* to do this.
int num_image_units = min(_glsl_img_inputs.size(), (size_t)_glgsg->_max_image_units);
if (_glgsg->_supports_multi_bind) {
_glgsg->_glBindImageTextures(0, num_image_units, NULL);
if (num_image_units > 0) {
if (_glgsg->_supports_multi_bind) {
_glgsg->_glBindImageTextures(0, num_image_units, NULL);
} else {
for (int i = 0; i < num_image_units; ++i) {
_glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
} else {
for (int i = 0; i < num_image_units; ++i) {
_glgsg->_glBindImageTexture(i, 0, 0, GL_FALSE, 0, GL_READ_ONLY, GL_R8);
}
}
if (gl_enable_memory_barriers) {
for (int i = 0; i < num_image_units; ++i) {
// We don't distinguish between read-only and read-write/write-only
// image access, so we have to assume that the shader wrote to it.
_glsl_img_textures[i]->mark_incoherent();
_glsl_img_textures[i] = NULL;
}
}
}
#endif
@ -1132,6 +1153,8 @@ update_shader_texture_bindings(ShaderContext *prev) {
}
#ifndef OPENGLES
GLbitfield barriers = 0;
// First bind all the 'image units'; a bit of an esoteric OpenGL feature right now.
int num_image_units = min(_glsl_img_inputs.size(), (size_t)_glgsg->_max_image_units);
@ -1152,8 +1175,14 @@ update_shader_texture_bindings(ShaderContext *prev) {
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
if (gtc != (TextureContext*)NULL) {
_glsl_img_textures[i] = gtc;
gl_tex = gtc->_index;
_glgsg->update_texture(gtc, true);
if (gtc->needs_barrier(GL_SHADER_IMAGE_ACCESS_BARRIER_BIT)) {
barriers |= GL_SHADER_IMAGE_ACCESS_BARRIER_BIT;
}
}
}
@ -1185,28 +1214,26 @@ update_shader_texture_bindings(ShaderContext *prev) {
// filtered TextureAttrib in _target_texture.
const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot()));
nassertv(texattrib != (TextureAttrib *)NULL);
_stage_offset = texattrib->get_num_on_stages();
for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) {
InternalName *id = _shader->_tex_spec[i]._name;
const InternalName *id = _shader->_tex_spec[i]._name;
int texunit = _shader->_tex_spec[i]._stage;
if (id != 0) {
texunit += _stage_offset;
}
Texture *tex = 0;
Texture *tex = NULL;
int view = _glgsg->get_current_tex_view_offset();
if (id != 0) {
if (id != NULL) {
const ShaderInput *input = _glgsg->_target_shader->get_shader_input(id);
tex = input->get_texture();
} else {
if (_shader->_tex_spec[i]._stage >= texattrib->get_num_on_stages()) {
if (texunit >= texattrib->get_num_on_stages()) {
continue;
}
TextureStage *stage = texattrib->get_on_stage(_shader->_tex_spec[i]._stage);
TextureStage *stage = texattrib->get_on_stage(texunit);
tex = texattrib->get_on_texture(stage);
view += stage->get_tex_view_offset();
}
if (_shader->_tex_spec[i]._suffix != 0) {
// The suffix feature is inefficient. It is a temporary hack.
if (tex == 0) {
@ -1218,27 +1245,64 @@ update_shader_texture_bindings(ShaderContext *prev) {
continue;
}
_glgsg->_glActiveTexture(GL_TEXTURE0 + texunit);
TextureContext *tc = tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg);
if (tc == (TextureContext*)NULL) {
continue;
}
GLenum target = _glgsg->get_texture_target(tex->get_texture_type());
if (target == GL_NONE) {
// Unsupported texture mode.
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tex->prepare_now(view, _glgsg->_prepared_objects, _glgsg));
if (gtc == NULL) {
continue;
}
GLint p = _glsl_parameter_map[_shader->_tex_spec[i]._id._seqno];
_glgsg->_glUniform1i(p, texunit);
if (!_glgsg->update_texture(tc, false)) {
#ifndef OPENGLES
// If it was recently written to, we will have to issue a memory barrier soon.
if (gtc->needs_barrier(GL_TEXTURE_FETCH_BARRIER_BIT)) {
barriers |= GL_TEXTURE_FETCH_BARRIER_BIT;
}
// Try bindless texturing first, if supported.
if (gl_use_bindless_texture && _glgsg->_supports_bindless_texture) {
// We demand the real texture, since we won't be able
// to change the texture properties after this point.
if (!_glgsg->update_texture(gtc, true)) {
continue;
}
GLuint64 handle = gtc->get_handle();
if (handle != 0) {
gtc->make_handle_resident();
gtc->set_active(true);
// Check if we have already specified this texture handle.
// If so, no need to call glUniformHandle again.
pmap<GLint, GLuint64>::const_iterator it;
it = _glsl_uniform_handles.find(p);
if (it != _glsl_uniform_handles.end() && it->second == handle) {
// Already specified.
continue;
} else {
_glgsg->_glUniformHandleui64(p, handle);
_glsl_uniform_handles[p] = handle;
}
continue;
}
}
#endif
// Bindless texturing wasn't supported or didn't work, so
// let's just bind the texture normally.
_glgsg->_glActiveTexture(GL_TEXTURE0 + i);
if (!_glgsg->update_texture(gtc, false)) {
continue;
}
_glgsg->apply_texture(gtc);
}
#ifndef OPENGLES
if (barriers != 0) {
// Issue a memory barrier.
_glgsg->issue_memory_barrier(barriers);
}
#endif
_glgsg->report_my_gl_errors();
}
@ -1248,7 +1312,7 @@ update_shader_texture_bindings(ShaderContext *prev) {
// Description: This subroutine prints the infolog for a shader.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
glsl_report_shader_errors(unsigned int shader) {
glsl_report_shader_errors(GLuint shader) {
char *info_log;
GLint length = 0;
GLint num_chars = 0;
@ -1271,7 +1335,7 @@ glsl_report_shader_errors(unsigned int shader) {
// Description: This subroutine prints the infolog for a program.
////////////////////////////////////////////////////////////////////
void CLP(ShaderContext)::
glsl_report_program_errors(unsigned int program) {
glsl_report_program_errors(GLuint program) {
char *info_log;
GLint length = 0;
GLint num_chars = 0;
@ -1289,13 +1353,13 @@ glsl_report_program_errors(unsigned int program) {
}
////////////////////////////////////////////////////////////////////
// Function: Shader::glsl_compile_entry_point
// Function: Shader::glsl_compile_shader
// Access: Private
// Description:
////////////////////////////////////////////////////////////////////
unsigned int CLP(ShaderContext)::
glsl_compile_entry_point(Shader::ShaderType type) {
unsigned int handle = 0;
bool CLP(ShaderContext)::
glsl_compile_shader(Shader::ShaderType type) {
GLuint handle = 0;
switch (type) {
case Shader::ST_vertex:
handle = _glgsg->_glCreateShader(GL_VERTEX_SHADER);
@ -1327,8 +1391,10 @@ glsl_compile_entry_point(Shader::ShaderType type) {
#endif
}
if (!handle) {
GLCAT.error()
<< "Could not create a GLSL shader of the requested type.\n";
_glgsg->report_my_gl_errors();
return 0;
return false;
}
string text_str = _shader->get_text(type);
@ -1345,79 +1411,68 @@ glsl_compile_entry_point(Shader::ShaderType type) {
glsl_report_shader_errors(handle);
_glgsg->_glDeleteShader(handle);
_glgsg->report_my_gl_errors();
return 0;
return false;
}
return handle;
_glgsg->_glAttachShader(_glsl_program, handle);
_glsl_shaders.push_back(handle);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Shader::glsl_compile_shader
// Function: Shader::glsl_compile_and_link
// Access: Private
// Description: This subroutine compiles a GLSL shader.
////////////////////////////////////////////////////////////////////
bool CLP(ShaderContext)::
glsl_compile_shader() {
glsl_compile_and_link() {
_glsl_shaders.clear();
_glsl_program = _glgsg->_glCreateProgram();
if (!_glsl_program) return false;
if (!_glsl_program) {
return false;
}
bool valid = true;
if (!_shader->get_text(Shader::ST_vertex).empty()) {
_glsl_vshader = glsl_compile_entry_point(Shader::ST_vertex);
if (!_glsl_vshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_vshader);
valid &= glsl_compile_shader(Shader::ST_vertex);
}
if (!_shader->get_text(Shader::ST_fragment).empty()) {
_glsl_fshader = glsl_compile_entry_point(Shader::ST_fragment);
if (!_glsl_fshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_fshader);
valid &= glsl_compile_shader(Shader::ST_fragment);
}
if (!_shader->get_text(Shader::ST_geometry).empty()) {
_glsl_gshader = glsl_compile_entry_point(Shader::ST_geometry);
if (!_glsl_gshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_gshader);
#ifdef OPENGLES
nassertr(false, false); // OpenGL ES has no geometry shaders.
#else
// Set the vertex output limit to the maximum
if (!_shader->get_text(Shader::ST_geometry).empty()) {
valid &= glsl_compile_shader(Shader::ST_geometry);
// Set the vertex output limit to the maximum.
// This is slow, but it is probably reasonable to require
// the user to override this in his shader using layout().
nassertr(_glgsg->_glProgramParameteri != NULL, false);
GLint max_vertices;
glGetIntegerv(GL_MAX_GEOMETRY_OUTPUT_VERTICES, &max_vertices);
_glgsg->_glProgramParameteri(_glsl_program, GL_GEOMETRY_VERTICES_OUT_ARB, max_vertices);
#endif
}
#endif
if (!_shader->get_text(Shader::ST_tess_control).empty()) {
_glsl_tcshader = glsl_compile_entry_point(Shader::ST_tess_control);
if (!_glsl_tcshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_tcshader);
valid &= glsl_compile_shader(Shader::ST_tess_control);
}
if (!_shader->get_text(Shader::ST_tess_evaluation).empty()) {
_glsl_teshader = glsl_compile_entry_point(Shader::ST_tess_evaluation);
if (!_glsl_teshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_teshader);
valid &= glsl_compile_shader(Shader::ST_tess_evaluation);
}
if (!_shader->get_text(Shader::ST_compute).empty()) {
_glsl_cshader = glsl_compile_entry_point(Shader::ST_compute);
if (!_glsl_cshader) return false;
_glgsg->_glAttachShader(_glsl_program, _glsl_cshader);
valid &= glsl_compile_shader(Shader::ST_compute);
}
// There might be warnings. Only report them for one shader program.
if (_glsl_vshader != 0) {
glsl_report_shader_errors(_glsl_vshader);
} else if (_glsl_fshader != 0) {
glsl_report_shader_errors(_glsl_fshader);
} else if (_glsl_gshader != 0) {
glsl_report_shader_errors(_glsl_gshader);
} else if (_glsl_tcshader != 0) {
glsl_report_shader_errors(_glsl_tcshader);
} else if (_glsl_teshader != 0) {
glsl_report_shader_errors(_glsl_teshader);
// There might be warnings, so report those.
GLSLShaders::const_iterator it;
for (it = _glsl_shaders.begin(); it != _glsl_shaders.end(); ++it) {
glsl_report_shader_errors(*it);
}
// If we requested to retrieve the shader, we should indicate that before linking.
@ -1454,7 +1509,7 @@ glsl_compile_shader() {
_glgsg->_glGetProgramBinary(_glsl_program, length, &num_bytes, &format, (void*)binary);
pofstream s;
s.open(filename, ios::out | ios::binary);
s.open(filename, ios::out | ios::binary | ios::trunc);
s.write(binary, num_bytes);
s.close();

View File

@ -50,26 +50,33 @@ public:
private:
GLuint _glsl_program;
GLuint _glsl_vshader;
GLuint _glsl_fshader;
GLuint _glsl_gshader;
GLuint _glsl_tcshader;
GLuint _glsl_teshader;
GLuint _glsl_cshader;
typedef pvector<GLuint> GLSLShaders;
GLSLShaders _glsl_shaders;
pvector <GLint> _glsl_parameter_map;
//struct ParamContext {
// CPT(InternalName) _name;
// GLint _location;
// GLsizei _count;
// WPT(ParamValue) _value;
// UpdateSeq _updated;
//};
//typedef pvector<ParamContext> ParamContexts;
//ParamContexts _params;
pvector<GLint> _glsl_parameter_map;
pmap<GLint, GLuint64> _glsl_uniform_handles;
pvector<CPT(InternalName)> _glsl_img_inputs;
pvector<CLP(TextureContext)*> _glsl_img_textures;
int _stage_offset;
CLP(GraphicsStateGuardian) *_glgsg;
bool _uses_standard_vertex_arrays;
void glsl_report_shader_errors(unsigned int shader);
void glsl_report_program_errors(unsigned int program);
unsigned int glsl_compile_entry_point(Shader::ShaderType type);
bool glsl_compile_shader();
void glsl_report_shader_errors(GLuint shader);
void glsl_report_program_errors(GLuint program);
bool glsl_compile_shader(Shader::ShaderType type);
bool glsl_compile_and_link();
bool parse_and_set_short_hand_shader_vars(Shader::ShaderArgId &arg_id, Shader *s);
void release_resources();

View File

@ -19,12 +19,20 @@
// Description:
////////////////////////////////////////////////////////////////////
INLINE CLP(TextureContext)::
CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex, int view) :
CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo, Texture *tex, int view) :
TextureContext(pgo, tex, view)
{
_index = 0;
_already_applied = false;
_glgsg = glgsg;
glGenTextures(1, &_index);
_handle = 0;
_needs_barrier = false;
_has_storage = false;
_immutable = false;
_uses_mipmaps = false;
_generate_mipmaps = false;
_internal_format = 0;
_width = 0;
_height = 0;

View File

@ -16,6 +16,23 @@
TypeHandle CLP(TextureContext)::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: CLP(TextureContext)::Denstructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
CLP(TextureContext)::
~CLP(TextureContext)() {
if (gl_enable_memory_barriers) {
_glgsg->_textures_needing_fetch_barrier.erase(this);
_glgsg->_textures_needing_image_access_barrier.erase(this);
_glgsg->_textures_needing_update_barrier.erase(this);
_glgsg->_textures_needing_framebuffer_barrier.erase(this);
}
glDeleteTextures(1, &_index);
_index = 0;
}
////////////////////////////////////////////////////////////////////
// Function: GLTextureContext::evict_lru
@ -35,7 +52,16 @@ TypeHandle CLP(TextureContext)::_type_handle;
void CLP(TextureContext)::
evict_lru() {
dequeue_lru();
reset_data();
if (_handle != 0) {
if (_handle_resident) {
_glgsg->_glMakeTextureHandleNonResident(_handle);
}
_handle_resident = false;
} else {
reset_data();
}
update_data_size_bytes(0);
mark_unloaded();
}
@ -48,6 +74,10 @@ evict_lru() {
////////////////////////////////////////////////////////////////////
void CLP(TextureContext)::
reset_data() {
if (_handle != 0 && _handle_resident) {
_glgsg->_glMakeTextureHandleNonResident(_handle);
}
// Free the texture resources.
glDeleteTextures(1, &_index);
@ -55,5 +85,102 @@ reset_data() {
// re-load the texture later.
glGenTextures(1, &_index);
_already_applied = false;
_handle = 0;
_handle_resident = false;
_needs_barrier = false;
_has_storage = false;
_immutable = false;
#ifndef OPENGLES
// Mark the texture as coherent.
if (gl_enable_memory_barriers) {
_glgsg->_textures_needing_fetch_barrier.erase(this);
_glgsg->_textures_needing_image_access_barrier.erase(this);
_glgsg->_textures_needing_update_barrier.erase(this);
_glgsg->_textures_needing_framebuffer_barrier.erase(this);
}
#endif
}
////////////////////////////////////////////////////////////////////
// Function: GLTextureContext::make_handle_resident
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
void CLP(TextureContext)::
make_handle_resident() {
if (_handle != 0) {
if (!_handle_resident) {
_glgsg->_glMakeTextureHandleResident(_handle);
_handle_resident = true;
}
set_resident(true);
}
}
////////////////////////////////////////////////////////////////////
// Function: CLP(TextureContext)::get_handle
// Access: Public
// Description: Returns a handle for this texture. Once this has
// been created, the texture data may still be updated,
// but its properties may not.
////////////////////////////////////////////////////////////////////
INLINE GLuint64 CLP(TextureContext)::
get_handle() {
#ifdef OPENGLES
return 0;
#else
if (!_glgsg->_supports_bindless_texture) {
return false;
}
if (_handle == 0) {
_handle = _glgsg->_glGetTextureHandle(_index);
}
_immutable = true;
return _handle;
#endif
}
#ifndef OPENGLES
////////////////////////////////////////////////////////////////////
// Function: GLTextureContext::needs_barrier
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
bool CLP(TextureContext)::
needs_barrier(GLbitfield barrier) {
if (!gl_enable_memory_barriers) {
return false;
}
return (((barrier & GL_TEXTURE_FETCH_BARRIER_BIT) &&
_glgsg->_textures_needing_fetch_barrier.count(this)))
|| (((barrier & GL_SHADER_IMAGE_ACCESS_BARRIER_BIT) &&
_glgsg->_textures_needing_image_access_barrier.count(this)))
|| (((barrier & GL_TEXTURE_UPDATE_BARRIER_BIT) &&
_glgsg->_textures_needing_update_barrier.count(this)))
|| (((barrier & GL_FRAMEBUFFER_BARRIER_BIT) &&
_glgsg->_textures_needing_framebuffer_barrier.count(this)));
}
////////////////////////////////////////////////////////////////////
// Function: GLTextureContext::mark_incoherent
// Access: Public
// Description: Mark a texture as needing a memory barrier, since
// a non-coherent write just happened to it.
////////////////////////////////////////////////////////////////////
void CLP(TextureContext)::
mark_incoherent() {
if (!gl_enable_memory_barriers) {
return;
}
_glgsg->_textures_needing_fetch_barrier.insert(this);
_glgsg->_textures_needing_image_access_barrier.insert(this);
_glgsg->_textures_needing_update_barrier.insert(this);
_glgsg->_textures_needing_framebuffer_barrier.insert(this);
}
#endif // OPENGLES

View File

@ -16,32 +16,60 @@
#include "textureContext.h"
#include "deletedChain.h"
class CLP(GraphicsStateGuardian);
////////////////////////////////////////////////////////////////////
// Class : GLTextureContext
// Description :
////////////////////////////////////////////////////////////////////
class EXPCL_GL CLP(TextureContext) : public TextureContext {
public:
INLINE CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex, int view);
INLINE CLP(TextureContext)(CLP(GraphicsStateGuardian) *glgsg,
PreparedGraphicsObjects *pgo,
Texture *tex, int view);
ALLOC_DELETED_CHAIN(CLP(TextureContext));
virtual ~CLP(TextureContext)();
virtual void evict_lru();
void reset_data();
void make_handle_resident();
GLuint64 get_handle();
#ifdef OPENGLES
CONSTEXPR bool needs_barrier(GLbitfield barrier) { return false; };
#else
bool needs_barrier(GLbitfield barrier);
void mark_incoherent();
#endif
// This is the GL "name" of the texture object.
GLuint _index;
// This is the bindless "handle" to the texture object.
GLuint64 _handle;
bool _handle_resident;
// This is true if the texture was recently written to in a
// non-coherent way, and Panda may have to call glMemoryBarrier
// for the results of this write to become visible.
bool _needs_barrier;
// These are the parameters that we specified with the last
// glTexImage2D() call. If none of these have changed, we can
// reload the texture image with a glTexSubImage2D().
bool _already_applied;
// glTexImage2D() or glTexStorage2D() call. If none of these have
// changed, we can reload the texture image with a glTexSubImage2D().
bool _has_storage;
bool _immutable;
bool _uses_mipmaps;
bool _generate_mipmaps;
GLint _internal_format;
GLsizei _width;
GLsizei _height;
GLsizei _depth;
GLenum _target;
CLP(GraphicsStateGuardian) *_glgsg;
public:
static TypeHandle get_class_type() {
return _type_handle;

View File

@ -208,6 +208,34 @@ ConfigVariableBool gl_dump_compiled_shaders
"programs to disk with a filename like glsl_program0.dump "
"into the current directory."));
ConfigVariableBool gl_immutable_texture_storage
("gl-immutable-texture-storage", true,
PRC_DESC("This configures Panda to pre-allocate immutable storage "
"for each texture. This improves runtime performance, but "
"changing the size or type of a texture will be slower."));
ConfigVariableBool gl_use_bindless_texture
("gl-use-bindless-texture", false,
PRC_DESC("Set this to let Panda use OpenGL's bindless texture "
"extension for all textures passed to shaders, for improved "
"performance. This is an experimental feature and comes "
"with a few caveats; for one, it requires that all sampler "
"uniforms have a layout(bindless_sampler) qualifier, and "
"it also requires that the texture properties are not "
"modified after the texture handle has been initialized."));
ConfigVariableBool gl_enable_memory_barriers
("gl-enable-memory-barriers", true,
PRC_DESC("If this is set, Panda will make sure that every write "
"to an image using an image2D (et al) binding will cause "
"Panda to issue a memory barrier before the next use of "
"said texture, to ensure that all reads and writes are "
"properly synchronized. This may not be strictly necessary "
"when using the 'coherent' qualifier, but Panda has no "
"way to detect whether you are using those. Turning "
"this off may give a slight performance increase, but you "
"have to know what you're doing."));
extern ConfigVariableBool gl_parallel_arrays;
void CLP(init_classes)() {

View File

@ -67,6 +67,9 @@ extern ConfigVariableBool gl_force_flush;
extern ConfigVariableBool gl_separate_specular_color;
extern ConfigVariableBool gl_cube_map_seamless;
extern ConfigVariableBool gl_dump_compiled_shaders;
extern ConfigVariableBool gl_immutable_texture_storage;
extern ConfigVariableBool gl_use_bindless_texture;
extern ConfigVariableBool gl_enable_memory_barriers;
extern EXPCL_GL void CLP(init_classes)();