Add gsg::update_texture()

This commit is contained in:
David Rose 2008-08-25 22:58:58 +00:00
parent 189626a483
commit 8c2e657f15
18 changed files with 292 additions and 98 deletions

View File

@ -414,6 +414,27 @@ prepare_texture(Texture *) {
return (TextureContext *)NULL;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::update_texture
// Access: Public, Virtual
// Description: Ensures that the current Texture data is refreshed
// onto the GSG. This means updating the texture
// properties and/or re-uploading the texture image, if
// necessary. This should only be called within the
// draw thread.
//
// If force is true, this function will not return until
// the texture has been fully uploaded. If force is
// false, the function may choose to upload a simple
// version of the texture instead, if the texture is not
// fully resident (and if get_incomplete_render() is
// true).
////////////////////////////////////////////////////////////////////
bool GraphicsStateGuardian::
update_texture(TextureContext *, bool) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GraphicsStateGuardian::release_texture
// Access: Public, Virtual

View File

@ -170,6 +170,7 @@ public:
virtual SceneSetup *get_scene() const;
virtual TextureContext *prepare_texture(Texture *tex);
virtual bool update_texture(TextureContext *tc, bool force);
virtual void release_texture(TextureContext *tc);
virtual bool extract_texture_data(Texture *tex);

View File

@ -2637,6 +2637,50 @@ prepare_texture(Texture *tex) {
return gtc;
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::update_texture
// Access: Public, Virtual
// Description: Ensures that the current Texture data is refreshed
// onto the GSG. This means updating the texture
// properties and/or re-uploading the texture image, if
// necessary. This should only be called within the
// draw thread.
//
// If force is true, this function will not return until
// the texture has been fully uploaded. If force is
// false, the function may choose to upload a simple
// version of the texture instead, if the texture is not
// fully resident (and if get_incomplete_render() is
// true).
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
update_texture(TextureContext *tc, bool force) {
apply_texture(tc);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
if (gtc->was_image_modified()) {
// If the texture image was modified, reload the texture. This
// means we also re-specify the properties for good measure.
specify_texture(gtc->get_texture());
bool okflag = upload_texture(gtc, force);
if (!okflag) {
GLCAT.error()
<< "Could not load " << *gtc->get_texture() << "\n";
return false;
}
} else if (gtc->was_properties_modified()) {
// If only the properties have been modified, we don't necessarily
// need to reload the texture.
specify_texture(gtc->get_texture());
gtc->mark_loaded();
}
report_my_gl_errors();
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GLGraphicsStateGuardian::release_texture
// Access: Public, Virtual
@ -3275,18 +3319,44 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
nassertr(tc != (TextureContext *)NULL, false);
apply_texture(tc);
CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
if (z >= 0) {
// Copy to a cube map face. This doesn't seem to work too well
// with CopyTexSubImage2D, so we always use CopyTexImage2D.
GLP(CopyTexImage2D)(GL_TEXTURE_CUBE_MAP_POSITIVE_X + z, 0,
get_internal_image_format(tex),
xo, yo, w, h, 0);
} else {
GLP(CopyTexSubImage2D)(GL_TEXTURE_2D, 0, 0, 0, xo, yo, w, h);
apply_texture(gtc);
specify_texture(tex);
GLenum target = get_texture_target(tex->get_texture_type());
GLint internal_format = get_internal_image_format(tex);
bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
if (uses_mipmaps) {
if (_supports_generate_mipmap) {
GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, true);
} else {
// If we can't auto-generate mipmaps, do without mipmaps.
GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
uses_mipmaps = false;
}
}
bool new_image = gtc->was_image_modified();
if (z >= 0) {
// Copy to a cube map face.
target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + z;
// Cube map faces seem to have trouble with CopyTexSubImage, so we
// always reload the image.
new_image = true;
}
if (new_image) {
// We have to create a new image.
GLP(CopyTexImage2D)(target, 0, internal_format, xo, yo, w, h, 0);
} else {
// We can overlay the existing image.
GLP(CopyTexSubImage2D)(target, 0, 0, 0, xo, yo, w, h);
}
gtc->mark_loaded();
report_my_gl_errors();
// Force reload of texture state, since we've just monkeyed with it.
@ -6186,7 +6256,7 @@ update_standard_texture_bindings() {
}
GLP(Enable)(target);
if (!apply_texture(tc)) {
if (!update_texture(tc, false)) {
GLP(Disable)(target);
break;
}
@ -6755,24 +6825,6 @@ apply_texture(TextureContext *tc) {
}
GLP(BindTexture)(target, gtc->_index);
if (gtc->was_image_modified()) {
// If the texture image was modified, reload the texture. This
// means we also re-specify the properties for good measure.
specify_texture(gtc->get_texture());
bool okflag = upload_texture(gtc);
if (!okflag) {
GLCAT.error()
<< "Could not load " << *gtc->get_texture() << "\n";
return false;
}
} else if (gtc->was_properties_modified()) {
// If only the properties have been modified, we don't necessarily
// need to reload the texture.
specify_texture(gtc->get_texture());
gtc->mark_loaded();
}
report_my_gl_errors();
return true;
}
@ -6787,10 +6839,10 @@ apply_texture(TextureContext *tc) {
// the texture has no image.
////////////////////////////////////////////////////////////////////
bool CLP(GraphicsStateGuardian)::
upload_texture(CLP(TextureContext) *gtc) {
upload_texture(CLP(TextureContext) *gtc, bool force) {
Texture *tex = gtc->get_texture();
if (_incomplete_render) {
if (_incomplete_render && !force) {
bool has_image = _supports_compressed_texture ? tex->has_ram_image() : tex->has_uncompressed_ram_image();
if (!has_image && tex->might_have_ram_image() &&
tex->has_simple_ram_image() &&
@ -6827,6 +6879,13 @@ upload_texture(CLP(TextureContext) *gtc) {
image_compression = Texture::CM_off;
}
/*
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();

View File

@ -143,6 +143,7 @@ public:
INLINE bool draw_display_list(GeomContext *gc);
virtual TextureContext *prepare_texture(Texture *tex);
virtual bool update_texture(TextureContext *tc, bool force);
virtual void release_texture(TextureContext *tc);
virtual bool extract_texture_data(Texture *tex);
@ -324,7 +325,7 @@ protected:
void do_auto_rescale_normal();
void specify_texture(Texture *tex);
bool apply_texture(TextureContext *tc);
bool upload_texture(CLP(TextureContext) *gtc);
bool upload_texture(CLP(TextureContext) *gtc, bool force);
bool upload_texture_image(CLP(TextureContext) *gtc,
bool uses_mipmaps, int mipmap_bias,
GLenum texture_target, GLenum page_target,

View File

@ -1214,7 +1214,8 @@ begin_frame(GraphicsStateGuardianBase *gsg, Thread *current_thread) {
qti != _enqueued_textures.end();
++qti) {
Texture *tex = (*qti);
tex->prepare_now(this, gsg);
TextureContext *tc = tex->prepare_now(this, gsg);
gsg->update_texture(tc, true);
}
_enqueued_textures.clear();

View File

@ -133,6 +133,7 @@ public:
#endif
virtual TextureContext *prepare_texture(Texture *tex)=0;
virtual bool update_texture(TextureContext *tc, bool force)=0;
virtual void release_texture(TextureContext *tc)=0;
virtual bool extract_texture_data(Texture *tex)=0;

View File

@ -352,6 +352,35 @@ safe_to_combine() const {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: GeomNode::r_prepare_scene
// Access: Protected, Virtual
// Description: The recursive implementation of prepare_scene().
// Don't call this directly; call
// PandaNode::prepare_scene() or
// NodePath::prepare_scene() instead.
////////////////////////////////////////////////////////////////////
void GeomNode::
r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects) {
int num_geoms = get_num_geoms();
for (int i = 0; i < num_geoms; i++) {
CPT(RenderState) geom_state = state->compose(get_geom_state(i));
const RenderAttrib *attrib =
geom_state->get_attrib(TextureAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const TextureAttrib *ta;
DCAST_INTO_V(ta, attrib);
Texture *texture = ta->get_texture();
if (texture != (Texture *)NULL) {
texture->prepare(prepared_objects);
}
}
}
PandaNode::r_prepare_scene(state, prepared_objects);
}
////////////////////////////////////////////////////////////////////
// Function: GeomNode::combine_with

View File

@ -59,6 +59,9 @@ public:
virtual bool safe_to_flatten() const;
virtual bool safe_to_combine() const;
virtual void r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects);
PUBLISHED:
INLINE void set_preserved(bool value);
INLINE bool get_preserved() const;

View File

@ -5752,10 +5752,8 @@ void NodePath::
prepare_scene(GraphicsStateGuardianBase *gsg) {
nassertv_always(!is_empty());
PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
CPT(RenderState) net_state = get_net_state();
r_prepare_scene(node(), net_state, prepared_objects);
node()->prepare_scene(gsg, net_state);
}
////////////////////////////////////////////////////////////////////
@ -7009,46 +7007,3 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
r_find_all_materials(child, next_state, materials);
}
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::r_prepare_scene
// Access: Private
// Description: The recursive implementation of prepare_scene.
////////////////////////////////////////////////////////////////////
void NodePath::
r_prepare_scene(PandaNode *node, const RenderState *state,
PreparedGraphicsObjects *prepared_objects) {
if (node->is_geom_node()) {
GeomNode *gnode;
DCAST_INTO_V(gnode, node);
/*
Not implemented yet in pgraph. Maybe we don't need this anyway.
if (retained_mode) {
gnode->prepare(gsg);
}
*/
int num_geoms = gnode->get_num_geoms();
for (int i = 0; i < num_geoms; i++) {
CPT(RenderState) geom_state = state->compose(gnode->get_geom_state(i));
const RenderAttrib *attrib =
geom_state->get_attrib(TextureAttrib::get_class_type());
if (attrib != (const RenderAttrib *)NULL) {
const TextureAttrib *ta;
DCAST_INTO_V(ta, attrib);
Texture *texture = ta->get_texture();
if (texture != (Texture *)NULL) {
texture->prepare(prepared_objects);
}
}
}
}
int num_children = node->get_num_children();
for (int i = 0; i < num_children; i++) {
PandaNode *child = node->get_child(i);
CPT(RenderState) child_state = state->compose(child->get_state());
r_prepare_scene(child, child_state, prepared_objects);
}
}

View File

@ -913,9 +913,6 @@ private:
void r_find_all_materials(PandaNode *node, const RenderState *state,
Materials &materials) const;
void r_prepare_scene(PandaNode *node, const RenderState *state,
PreparedGraphicsObjects *prepared_objects);
PT(NodePathComponent) _head;
int _backup_key;
ErrorType _error_type;

View File

@ -27,6 +27,7 @@
#include "pStatTimer.h"
#include "config_mathutil.h"
#include "reMutexHolder.h"
#include "graphicsStateGuardianBase.h"
// This category is just temporary for debugging convenience.
NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
@ -2105,6 +2106,27 @@ get_off_clip_planes(Thread *current_thread) const {
return cdata->_off_clip_planes;
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::prepare_scene
// Access: Published
// Description: Walks through the scene graph beginning at this node,
// and does whatever initialization is required to
// render the scene properly with the indicated GSG. It
// is not strictly necessary to call this, since the GSG
// will initialize itself when the scene is rendered,
// but this may take some of the overhead away from that
// process.
//
// In particular, this will ensure that textures within
// the scene are loaded in texture memory, and display
// lists are built up from static geometry.
////////////////////////////////////////////////////////////////////
void PandaNode::
prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state) {
PreparedGraphicsObjects *prepared_objects = gsg->get_prepared_objects();
r_prepare_scene(net_state, prepared_objects);
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::output
// Access: Published, Virtual
@ -2661,6 +2683,25 @@ r_copy_children(const PandaNode *from, PandaNode::InstanceMap &inst_map,
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::r_prepare_scene
// Access: Public, Virtual
// Description: The recursive implementation of prepare_scene().
// Don't call this directly; call
// PandaNode::prepare_scene() or
// NodePath::prepare_scene() instead.
////////////////////////////////////////////////////////////////////
void PandaNode::
r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects) {
int num_children = get_num_children();
for (int i = 0; i < num_children; i++) {
PandaNode *child = get_child(i);
CPT(RenderState) child_state = state->compose(child->get_state());
child->r_prepare_scene(child_state, prepared_objects);
}
}
////////////////////////////////////////////////////////////////////
// Function: PandaNode::set_cull_callback
// Access: Protected

View File

@ -60,6 +60,7 @@ class Light;
class FactoryParams;
class AccumulatedAttribs;
class GeomTransformer;
class GraphicsStateGuardianBase;
////////////////////////////////////////////////////////////////////
// Class : PandaNode
@ -239,6 +240,8 @@ PUBLISHED:
CollideMask get_net_collide_mask(Thread *current_thread = Thread::get_current_thread()) const;
CPT(RenderAttrib) get_off_clip_planes(Thread *current_thread = Thread::get_current_thread()) const;
void prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *net_state);
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
@ -314,6 +317,10 @@ protected:
void set_cull_callback();
public:
virtual void r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects);
protected:
// This is a base class of CData, defined below. It contains just
// the protected (not private) part of CData that will be needed by

View File

@ -335,6 +335,30 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
bdata->_internal_bounds_stale = false;
}
////////////////////////////////////////////////////////////////////
// Function: PGItem::r_prepare_scene
// Access: Protected, Virtual
// Description: The recursive implementation of prepare_scene().
// Don't call this directly; call
// PandaNode::prepare_scene() or
// NodePath::prepare_scene() instead.
////////////////////////////////////////////////////////////////////
void PGItem::
r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects) {
StateDefs::iterator di;
for (di = _state_defs.begin(); di != _state_defs.end(); ++di) {
NodePath &root = (*di)._root;
if (!root.is_empty()) {
PandaNode *child = root.node();
CPT(RenderState) child_state = state->compose(child->get_state());
child->r_prepare_scene(child_state, prepared_objects);
}
}
PandaNode::r_prepare_scene(state, prepared_objects);
}
////////////////////////////////////////////////////////////////////
// Function: PGItem::xform
// Access: Public, Virtual

View File

@ -68,6 +68,9 @@ protected:
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
Thread *current_thread) const;
virtual void r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects);
public:
virtual void xform(const LMatrix4f &mat);
bool activate_region(const LMatrix4f &transform, int sort,

View File

@ -649,6 +649,28 @@ compute_internal_bounds(PandaNode::BoundsData *bdata, int pipeline_stage,
bdata->_internal_bounds_stale = false;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::r_prepare_scene
// Access: Protected, Virtual
// Description: The recursive implementation of prepare_scene().
// Don't call this directly; call
// PandaNode::prepare_scene() or
// NodePath::prepare_scene() instead.
////////////////////////////////////////////////////////////////////
void TextNode::
r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects) {
check_rebuild();
PandaNode *child = _internal_geom;
if (child != (PandaNode *)NULL) {
CPT(RenderState) child_state = state->compose(child->get_state());
child->r_prepare_scene(child_state, prepared_objects);
}
PandaNode::r_prepare_scene(state, prepared_objects);
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::do_rebuild
// Access: Private

View File

@ -242,6 +242,9 @@ public:
virtual void compute_internal_bounds(BoundsData *bdata, int pipeline_stage,
Thread *current_thread) const;
virtual void r_prepare_scene(const RenderState *state,
PreparedGraphicsObjects *prepared_objects);
private:
INLINE void invalidate_no_measure();
INLINE void invalidate_with_measure();

View File

@ -1468,6 +1468,47 @@ prepare_texture(Texture *tex) {
return gtc;
}
////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::update_texture
// Access: Public, Virtual
// Description: Ensures that the current Texture data is refreshed
// onto the GSG. This means updating the texture
// properties and/or re-uploading the texture image, if
// necessary. This should only be called within the
// draw thread.
//
// If force is true, this function will not return until
// the texture has been fully uploaded. If force is
// false, the function may choose to upload a simple
// version of the texture instead, if the texture is not
// fully resident (and if get_incomplete_render() is
// true).
////////////////////////////////////////////////////////////////////
bool TinyGraphicsStateGuardian::
update_texture(TextureContext *tc, bool force) {
apply_texture(tc);
TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
GLTexture *gltex = &gtc->_gltex;
if (gtc->was_image_modified() || gltex->num_levels == 0) {
// If the texture image was modified, reload the texture.
bool okflag = upload_texture(gtc);
if (!okflag) {
tinydisplay_cat.error()
<< "Could not load " << *gtc->get_texture() << "\n";
return false;
}
}
gtc->enqueue_lru(&_textures_lru);
_c->current_texture = gltex;
_c->zb->current_texture = gltex->levels;
return true;
}
////////////////////////////////////////////////////////////////////
// Function: TinyGraphicsStateGuardian::release_texture
// Access: Public, Virtual
@ -1874,7 +1915,7 @@ do_issue_texture() {
}
// Then, turn on the current texture mode.
if (!apply_texture(tc)) {
if (!update_texture(tc, false)) {
return;
}
@ -1981,22 +2022,6 @@ apply_texture(TextureContext *tc) {
TinyTextureContext *gtc = DCAST(TinyTextureContext, tc);
gtc->set_active(true);
GLTexture *gltex = &gtc->_gltex;
if (gtc->was_image_modified() || gltex->num_levels == 0) {
// If the texture image was modified, reload the texture.
bool okflag = upload_texture(gtc);
if (!okflag) {
tinydisplay_cat.error()
<< "Could not load " << *gtc->get_texture() << "\n";
return false;
}
}
gtc->enqueue_lru(&_textures_lru);
_c->current_texture = gltex;
_c->zb->current_texture = gltex->levels;
return true;
}

View File

@ -85,6 +85,7 @@ public:
const TransformState *transform);
virtual TextureContext *prepare_texture(Texture *tex);
virtual bool update_texture(TextureContext *tc, bool force);
virtual void release_texture(TextureContext *tc);
virtual void do_issue_light();