diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index ccdb5eca8f..5766fee8db 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -1240,6 +1240,9 @@ end_frame(Thread *current_thread) { _texture_state_pcollector.flush_level(); _transform_state_pcollector.flush_level(); _draw_primitive_pcollector.flush_level(); + + // Evict any textures and/or vbuffers that exceed our texture memory. + _prepared_objects->_graphics_memory_lru.begin_epoch(); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/dxgsg8/config_dxgsg8.cxx b/panda/src/dxgsg8/config_dxgsg8.cxx index 3489c324dc..8f93af0a0c 100644 --- a/panda/src/dxgsg8/config_dxgsg8.cxx +++ b/panda/src/dxgsg8/config_dxgsg8.cxx @@ -84,8 +84,6 @@ ConfigVariableBool dx_ignore_mipmaps // if this is set, more accurate but more expensive fog computations are performed ConfigVariableBool dx_use_rangebased_fog ("dx-use-rangebased-fog", false); -ConfigVariableBool dx_force_16bpptextures -("dx-force-16bpptextures", false); ConfigVariableBool dx_no_dithering ("dx-no-dithering", false); ConfigVariableBool dx_force_16bpp_zbuffer diff --git a/panda/src/dxgsg8/config_dxgsg8.h b/panda/src/dxgsg8/config_dxgsg8.h index fede31074c..8980c1c75b 100644 --- a/panda/src/dxgsg8/config_dxgsg8.h +++ b/panda/src/dxgsg8/config_dxgsg8.h @@ -39,7 +39,6 @@ extern ConfigVariableBool dx_broken_max_index; extern ConfigVariableBool dx_ignore_mipmaps; extern ConfigVariableBool dx_mipmap_everything; extern ConfigVariableBool dx_show_transforms; -extern ConfigVariableBool dx_force_16bpptextures; extern ConfigVariableBool dx_no_dithering; extern ConfigVariableBool dx_force_anisotropic_filtering; extern ConfigVariableBool dx_force_16bpp_zbuffer; diff --git a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx index e6dbec7da3..f5aa5aa7e2 100644 --- a/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx +++ b/panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx @@ -277,6 +277,7 @@ update_texture(TextureContext *tc, bool force) { return false; } } + dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); return true; } @@ -427,6 +428,7 @@ apply_vertex_buffer(VertexBufferContext *vbc, dvbc->set_active(true); } } + dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); HRESULT hr = _d3d_device->SetVertexShader(dvbc->_fvf); #ifndef NDEBUG @@ -524,6 +526,7 @@ apply_index_buffer(IndexBufferContext *ibc, dibc->set_active(true); } } + dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); return true; } @@ -1572,7 +1575,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, SAFE_RELEASE(render_target); SAFE_RELEASE(tex_level_0); - if (!okflag) { + if (okflag) { + dtc->mark_loaded(); + dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); + + } else { // The copy failed. Fall back to copying it to RAM and back. // Terribly slow, but what are you going to do? return do_framebuffer_copy_to_ram(tex, z, dr, rb, true); diff --git a/panda/src/dxgsg8/dxIndexBufferContext8.cxx b/panda/src/dxgsg8/dxIndexBufferContext8.cxx index b07dd994c9..51b9745dd7 100644 --- a/panda/src/dxgsg8/dxIndexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxIndexBufferContext8.cxx @@ -51,6 +51,39 @@ DXIndexBufferContext8:: } } +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext8::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXIndexBufferContext8:: +evict_lru() { + dequeue_lru(); + + if (_ibuffer != NULL) { + if (dxgsg8_cat.is_debug()) { + dxgsg8_cat.debug() + << "deleting index buffer " << _ibuffer << "\n"; + } + + RELEASE(_ibuffer, dxgsg8, "index buffer", RELEASE_ONCE); + _ibuffer = NULL; + } + + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXIndexBufferContext8::create_ibuffer // Access: Public diff --git a/panda/src/dxgsg8/dxIndexBufferContext8.h b/panda/src/dxgsg8/dxIndexBufferContext8.h index 0b7ad124d0..8322463800 100644 --- a/panda/src/dxgsg8/dxIndexBufferContext8.h +++ b/panda/src/dxgsg8/dxIndexBufferContext8.h @@ -29,6 +29,8 @@ public: DXIndexBufferContext8(PreparedGraphicsObjects *pgo, GeomPrimitive *data); virtual ~DXIndexBufferContext8(); + virtual void evict_lru(); + void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader); bool upload_data(const GeomPrimitivePipelineReader *reader, bool force); diff --git a/panda/src/dxgsg8/dxTextureContext8.cxx b/panda/src/dxgsg8/dxTextureContext8.cxx index 0eb702d437..75a42209d8 100644 --- a/panda/src/dxgsg8/dxTextureContext8.cxx +++ b/panda/src/dxgsg8/dxTextureContext8.cxx @@ -57,6 +57,35 @@ DXTextureContext8:: delete_texture(); } +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext8::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXTextureContext8:: +evict_lru() { + if (get_texture()->get_render_to_texture()) { + // Don't evict the result of render-to-texture. + mark_used_lru(); + return; + } + + dequeue_lru(); + delete_texture(); + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXTextureContext8::create_texture // Access: Public @@ -308,17 +337,49 @@ create_texture(DXScreenData &scrn) { // D3DXCheckTextureRequirements(), but it wouldn't handle all my // specialized low-memory cases perfectly -#define CONVTYPE_STMT - -#define CHECK_FOR_FMT(FMT, CONV) \ +#define CHECK_FOR_FMT(FMT) \ if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \ - CONVTYPE_STMT; \ target_pixel_format = D3DFMT_##FMT; \ goto found_matching_format; } + if (texture_stored_compressed){ + // if the texture is already compressed, we need to choose the + // corresponding format, otherwise we might end up + // cross-compressing from e.g. DXT5 to DXT3 + switch (compression_mode){ + case Texture::CM_dxt1: + CHECK_FOR_FMT(DXT1); + break; + case Texture::CM_dxt2: + CHECK_FOR_FMT(DXT2); + break; + case Texture::CM_dxt3: + CHECK_FOR_FMT(DXT3); + break; + case Texture::CM_dxt4: + CHECK_FOR_FMT(DXT4); + break; + case Texture::CM_dxt5: + CHECK_FOR_FMT(DXT5); + break; + } + // if we can't support the texture's compressed image, we can't + // load the texture. + goto error_exit; + } + + if (compress_texture) { + if (num_alpha_bits <= 1) { + CHECK_FOR_FMT(DXT1); + } else if (num_alpha_bits <= 4) { + CHECK_FOR_FMT(DXT3); + } else { + CHECK_FOR_FMT(DXT5); + } + } + // handle each target bitdepth separately. might be less confusing - // to reorg by num_color_channels (input type, rather than desired - // 1st target) + // to reorg by num_color_channels (input type) switch (target_bpp) { // IMPORTANT NOTE: @@ -329,37 +390,8 @@ create_texture(DXScreenData &scrn) { if (!((num_color_channels == 3) || (num_color_channels == 4))) break; //bail - if (!dx_force_16bpptextures) { - if (compress_texture) { - if (texture_stored_compressed){ - // if the texture is already compressed, we need to choose the corresponding format, - // otherwise we might end up cross-compressing from e.g. DXT5 to DXT3 - switch (compression_mode){ - case Texture::CM_dxt2: - CHECK_FOR_FMT(DXT2, Conv32toDXT2); - break; - case Texture::CM_dxt3: - CHECK_FOR_FMT(DXT3, Conv32toDXT3); - break; - case Texture::CM_dxt4: - CHECK_FOR_FMT(DXT4, Conv32toDXT4); - break; - case Texture::CM_dxt5: - CHECK_FOR_FMT(DXT5, Conv32toDXT5); - break; - } - // if no compressed format matches, just fall trhough to pick a different format - } - else - CHECK_FOR_FMT(DXT3, Conv32toDXT3); - } - if (num_color_channels == 4) { - CHECK_FOR_FMT(A8R8G8B8, Conv32to32); - } else { - CHECK_FOR_FMT(A8R8G8B8, Conv24to32); - } - } - + CHECK_FOR_FMT(A8R8G8B8); + if (num_alpha_bits>0) { nassertr(num_color_channels == 4, false); @@ -377,16 +409,13 @@ create_texture(DXScreenData &scrn) { // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify // 32->16 conversion. This should be true on most cards. -#ifndef FORCE_16bpp_1555 - if (num_alpha_bits == 1) -#endif - { - CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); - } + if (num_alpha_bits == 1) { + CHECK_FOR_FMT(A1R5G5B5); + } // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); - CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); + CHECK_FOR_FMT(A4R4G4B4); + CHECK_FOR_FMT(A1R5G5B5); // At this point, bail. Don't worry about converting to // non-alpha formats yet, I think this will be a very rare case. @@ -395,11 +424,11 @@ create_texture(DXScreenData &scrn) { // convert 3 or 4 channel to closest 16bpp color fmt if (num_color_channels == 3) { - CHECK_FOR_FMT(R5G6B5, Conv24to16_4444); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else { - CHECK_FOR_FMT(R5G6B5, Conv32to16_4444); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } } break; @@ -407,23 +436,19 @@ create_texture(DXScreenData &scrn) { case 24: nassertr(num_color_channels == 3, false); - if (compress_texture) { - CHECK_FOR_FMT(DXT1, Conv24toDXT1); - } - - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(R8G8B8, Conv24to24); - - // no 24-bit fmt. look for 32 bit fmt (note: this is - // memory-hogging choice instead I could look for - // memory-conserving 16-bit fmt). - - CHECK_FOR_FMT(X8R8G8B8, Conv24to32); - } + CHECK_FOR_FMT(R8G8B8); + + // no 24-bit fmt. look for 32 bit fmt (note: this is + // memory-hogging choice instead I could look for + // memory-conserving 16-bit fmt). + + CHECK_FOR_FMT(X8R8G8B8); + CHECK_FOR_FMT(A8R8G8B8); // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) - CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); + CHECK_FOR_FMT(A1R5G5B5); break; case 16: @@ -431,22 +456,16 @@ create_texture(DXScreenData &scrn) { nassertr(num_alpha_bits > 0, false); nassertr(num_color_channels == 2, false); - CHECK_FOR_FMT(A8L8, ConvLum16to16); + CHECK_FOR_FMT(A8L8); + CHECK_FOR_FMT(A8R8G8B8); - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8, ConvLum16to32); + if (num_alpha_bits == 1) { + CHECK_FOR_FMT(A1R5G5B5); } -#ifndef FORCE_16bpp_1555 - if (num_alpha_bits == 1) -#endif - { - CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); - } - // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444); - CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); + CHECK_FOR_FMT(A4R4G4B4); + CHECK_FOR_FMT(A1R5G5B5); } else { nassertr((num_color_channels == 3)||(num_color_channels == 4), false); // look for compatible 16bit fmts, if none then give up @@ -454,13 +473,13 @@ create_texture(DXScreenData &scrn) { switch(num_alpha_bits) { case 0: if (num_color_channels == 3) { - CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else { nassertr(num_color_channels == 4, false); // it could be 4 if user asks us to throw away the alpha channel - CHECK_FOR_FMT(R5G6B5, Conv32to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } break; case 1: @@ -469,13 +488,13 @@ create_texture(DXScreenData &scrn) { // could use 32bpp ARGB. fail if this particular fmt not // avail. nassertr(num_color_channels == 4, false); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(X1R5G5B5); break; case 4: // app specifically requests 4-4-4-4 F_rgba4 case, as opposed // to F_rgba, which could use 32bpp ARGB nassertr(num_color_channels == 4, false); - CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); + CHECK_FOR_FMT(A4R4G4B4); break; default: nassertr(false, false); // problem in get_bits_per_pixel()? @@ -488,16 +507,14 @@ create_texture(DXScreenData &scrn) { nassertr(num_color_channels == 1, false); // look for native lum fmt first - CHECK_FOR_FMT(L8, ConvLum8to8); - CHECK_FOR_FMT(L8, ConvLum8to16_A8L8); + CHECK_FOR_FMT(L8); + CHECK_FOR_FMT(L8); - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(R8G8B8, ConvLum8to24); - CHECK_FOR_FMT(X8R8G8B8, ConvLum8to32); - } + CHECK_FOR_FMT(R8G8B8); + CHECK_FOR_FMT(X8R8G8B8); - CHECK_FOR_FMT(R5G6B5, ConvLum8to16_0565); - CHECK_FOR_FMT(X1R5G5B5, ConvLum8to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else if (num_alpha_bits == 8) { // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. @@ -507,13 +524,9 @@ create_texture(DXScreenData &scrn) { // model we need somehow (is it that voodoo assumes color is // white? isnt that what we do in ConvAlpha8to32 anyway?) - CHECK_FOR_FMT(A8L8, ConvAlpha8to16_A8L8); - - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8, ConvAlpha8to32); - } - - CHECK_FOR_FMT(A4R4G4B4, ConvAlpha8to16_4444); + CHECK_FOR_FMT(A8L8); + CHECK_FOR_FMT(A8R8G8B8); + CHECK_FOR_FMT(A4R4G4B4); } break; @@ -1506,7 +1519,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn) { int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture? if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) { dxgsg8_cat.debug() - << "Using pre-calculated mipmap levels for texture " << tex->get_name(); + << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n"; for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) { hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format); @@ -1781,10 +1794,10 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) { return 24; case Texture::F_rgba8: case Texture::F_rgba: + *alphbits = 8; + return 32; case Texture::F_rgbm: - if (format == Texture::F_rgbm) // does this make any sense? - *alphbits = 1; - else *alphbits = 8; + *alphbits = 1; return 32; case Texture::F_rgb12: return 36; diff --git a/panda/src/dxgsg8/dxTextureContext8.h b/panda/src/dxgsg8/dxTextureContext8.h index 8a8a1c7d80..26bac4fe63 100644 --- a/panda/src/dxgsg8/dxTextureContext8.h +++ b/panda/src/dxgsg8/dxTextureContext8.h @@ -28,6 +28,8 @@ public: DXTextureContext8(PreparedGraphicsObjects *pgo, Texture *tex); virtual ~DXTextureContext8(); + virtual void evict_lru(); + bool create_texture(DXScreenData &scrn); bool create_simple_texture(DXScreenData &scrn); void delete_texture(); diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.cxx b/panda/src/dxgsg8/dxVertexBufferContext8.cxx index 2f705b1813..dbabf0de46 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.cxx +++ b/panda/src/dxgsg8/dxVertexBufferContext8.cxx @@ -177,6 +177,39 @@ DXVertexBufferContext8:: } } +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext8::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXVertexBufferContext8:: +evict_lru() { + dequeue_lru(); + + if (_vbuffer != NULL) { + if (dxgsg8_cat.is_debug()) { + dxgsg8_cat.debug() + << "deleting vertex buffer " << _vbuffer << "\n"; + } + + RELEASE(_vbuffer, dxgsg8, "vertex buffer", RELEASE_ONCE); + _vbuffer = NULL; + } + + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXVertexBufferContext8::create_vbuffer // Access: Public diff --git a/panda/src/dxgsg8/dxVertexBufferContext8.h b/panda/src/dxgsg8/dxVertexBufferContext8.h index e68800cac6..44d85ce73d 100644 --- a/panda/src/dxgsg8/dxVertexBufferContext8.h +++ b/panda/src/dxgsg8/dxVertexBufferContext8.h @@ -29,6 +29,8 @@ public: DXVertexBufferContext8(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data); virtual ~DXVertexBufferContext8(); + virtual void evict_lru(); + void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader); bool upload_data(const GeomVertexArrayDataHandle *reader, bool force); diff --git a/panda/src/dxgsg9/config_dxgsg9.cxx b/panda/src/dxgsg9/config_dxgsg9.cxx index 8220da0406..0cf3505968 100755 --- a/panda/src/dxgsg9/config_dxgsg9.cxx +++ b/panda/src/dxgsg9/config_dxgsg9.cxx @@ -87,8 +87,6 @@ ConfigVariableBool dx_ignore_mipmaps // if this is set, more accurate but more expensive fog computations are performed ConfigVariableBool dx_use_rangebased_fog ("dx-use-rangebased-fog", false); -ConfigVariableBool dx_force_16bpptextures -("dx-force-16bpptextures", false); ConfigVariableBool dx_no_dithering ("dx-no-dithering", false); ConfigVariableBool dx_force_16bpp_zbuffer diff --git a/panda/src/dxgsg9/config_dxgsg9.h b/panda/src/dxgsg9/config_dxgsg9.h index d268058bb3..7e91f8add7 100755 --- a/panda/src/dxgsg9/config_dxgsg9.h +++ b/panda/src/dxgsg9/config_dxgsg9.h @@ -38,7 +38,6 @@ extern ConfigVariableBool dx_broken_max_index; extern ConfigVariableBool dx_ignore_mipmaps; extern ConfigVariableBool dx_mipmap_everything; extern ConfigVariableBool dx_show_transforms; -extern ConfigVariableBool dx_force_16bpptextures; extern ConfigVariableBool dx_no_dithering; extern ConfigVariableBool dx_force_anisotropic_filtering; extern ConfigVariableBool dx_force_16bpp_zbuffer; diff --git a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx index a3c7366169..22070687c0 100755 --- a/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx +++ b/panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx @@ -335,10 +335,10 @@ update_texture(TextureContext *tc, bool force) { Texture *tex = tc->get_texture(); dxgsg9_cat.error() << "Unable to re-create texture " << *tex << endl; - cerr << "b\n"; return false; } } + dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); return true; } @@ -525,6 +525,7 @@ apply_vertex_buffer(VertexBufferContext *vbc, set_stream_source = true; } } + dvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); if (shader_context == 0) { // FVF MODE @@ -735,6 +736,7 @@ apply_index_buffer(IndexBufferContext *ibc, dibc->set_active(true); } } + dibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); return true; } @@ -2243,7 +2245,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, SAFE_RELEASE(render_target); SAFE_RELEASE(tex_level_0); - if (!okflag) { + if (okflag) { + dtc->mark_loaded(); + dtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); + + } else { // The copy failed. Fall back to copying it to RAM and back. // Terribly slow, but what are you going to do? return do_framebuffer_copy_to_ram(tex, z, dr, rb, true); diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.cxx b/panda/src/dxgsg9/dxIndexBufferContext9.cxx index 0c7151a4d3..232b8c9b04 100755 --- a/panda/src/dxgsg9/dxIndexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxIndexBufferContext9.cxx @@ -54,6 +54,29 @@ DXIndexBufferContext9:: } } +//////////////////////////////////////////////////////////////////// +// Function: DXIndexBufferContext9::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXIndexBufferContext9:: +evict_lru() { + dequeue_lru(); + free_ibuffer(); + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXIndexBufferContext9::free_ibuffer // Access: Public diff --git a/panda/src/dxgsg9/dxIndexBufferContext9.h b/panda/src/dxgsg9/dxIndexBufferContext9.h index a0cf4e96d0..de07201441 100755 --- a/panda/src/dxgsg9/dxIndexBufferContext9.h +++ b/panda/src/dxgsg9/dxIndexBufferContext9.h @@ -29,6 +29,8 @@ public: DXIndexBufferContext9(PreparedGraphicsObjects *pgo, GeomPrimitive *data); virtual ~DXIndexBufferContext9(); + virtual void evict_lru(); + void free_ibuffer(); void allocate_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader); void create_ibuffer(DXScreenData &scrn, const GeomPrimitivePipelineReader *reader); diff --git a/panda/src/dxgsg9/dxTextureContext9.cxx b/panda/src/dxgsg9/dxTextureContext9.cxx index eaa07ed8f5..7f994cf002 100755 --- a/panda/src/dxgsg9/dxTextureContext9.cxx +++ b/panda/src/dxgsg9/dxTextureContext9.cxx @@ -68,6 +68,35 @@ DXTextureContext9:: delete_texture(); } +//////////////////////////////////////////////////////////////////// +// Function: DXTextureContext9::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXTextureContext9:: +evict_lru() { + if (get_texture()->get_render_to_texture()) { + // Don't evict the result of render-to-texture. + mark_used_lru(); + return; + } + + dequeue_lru(); + delete_texture(); + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXTextureContext9::create_texture // Access: Public @@ -318,14 +347,47 @@ create_texture(DXScreenData &scrn) { // D3DXCheckTextureRequirements(), but it wouldn't handle all my // specialized low-memory cases perfectly -#define CONVTYPE_STMT - -#define CHECK_FOR_FMT(FMT, CONV) \ +#define CHECK_FOR_FMT(FMT) \ if (scrn._supported_tex_formats_mask & FMT##_FLAG) { \ - CONVTYPE_STMT; \ target_pixel_format = D3DFMT_##FMT; \ goto found_matching_format; } + if (texture_stored_compressed){ + // if the texture is already compressed, we need to choose the + // corresponding format, otherwise we might end up + // cross-compressing from e.g. DXT5 to DXT3 + switch (compression_mode){ + case Texture::CM_dxt1: + CHECK_FOR_FMT(DXT1); + break; + case Texture::CM_dxt2: + CHECK_FOR_FMT(DXT2); + break; + case Texture::CM_dxt3: + CHECK_FOR_FMT(DXT3); + break; + case Texture::CM_dxt4: + CHECK_FOR_FMT(DXT4); + break; + case Texture::CM_dxt5: + CHECK_FOR_FMT(DXT5); + break; + } + // if we can't support the texture's compressed image, we can't + // load the texture. + goto error_exit; + } + + if (compress_texture) { + if (num_alpha_bits <= 1) { + CHECK_FOR_FMT(DXT1); + } else if (num_alpha_bits <= 4) { + CHECK_FOR_FMT(DXT3); + } else { + CHECK_FOR_FMT(DXT5); + } + } + // handle each target bitdepth separately. might be less confusing // to reorg by num_color_channels (input type, rather than desired // 1st target) @@ -359,36 +421,7 @@ create_texture(DXScreenData &scrn) { if (!((num_color_channels == 3) || (num_color_channels == 4))) break; //bail - if (!dx_force_16bpptextures) { - if (compress_texture) { - if (texture_stored_compressed){ - // if the texture is already compressed, we need to choose the corresponding format, - // otherwise we might end up cross-compressing from e.g. DXT5 to DXT3 - switch (compression_mode){ - case Texture::CM_dxt2: - CHECK_FOR_FMT(DXT2, Conv32toDXT2); - break; - case Texture::CM_dxt3: - CHECK_FOR_FMT(DXT3, Conv32toDXT3); - break; - case Texture::CM_dxt4: - CHECK_FOR_FMT(DXT4, Conv32toDXT4); - break; - case Texture::CM_dxt5: - CHECK_FOR_FMT(DXT5, Conv32toDXT5); - break; - } - // if no compressed format matches, just fall trhough to pick a different format - } - else - CHECK_FOR_FMT(DXT3, Conv32toDXT3); - } - if (num_color_channels == 4) { - CHECK_FOR_FMT(A8R8G8B8, Conv32to32); - } else { - CHECK_FOR_FMT(A8R8G8B8, Conv24to32); - } - } + CHECK_FOR_FMT(A8R8G8B8); if (num_alpha_bits>0) { nassertr(num_color_channels == 4, false); @@ -407,16 +440,13 @@ create_texture(DXScreenData &scrn) { // assume ALPHAMASK is x8000 and RGBMASK is x7fff to simplify // 32->16 conversion. This should be true on most cards. -#ifndef FORCE_16bpp_1555 - if (num_alpha_bits == 1) -#endif - { - CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); + if (num_alpha_bits == 1) { + CHECK_FOR_FMT(A1R5G5B5); } // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); - CHECK_FOR_FMT(A1R5G5B5, Conv32to16_1555); + CHECK_FOR_FMT(A4R4G4B4); + CHECK_FOR_FMT(A1R5G5B5); // At this point, bail. Don't worry about converting to // non-alpha formats yet, I think this will be a very rare case. @@ -425,11 +455,11 @@ create_texture(DXScreenData &scrn) { // convert 3 or 4 channel to closest 16bpp color fmt if (num_color_channels == 3) { - CHECK_FOR_FMT(R5G6B5, Conv24to16_4444); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else { - CHECK_FOR_FMT(R5G6B5, Conv32to16_4444); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } } break; @@ -437,24 +467,19 @@ create_texture(DXScreenData &scrn) { case 24: nassertr(num_color_channels == 3, false); - if (compress_texture) { - CHECK_FOR_FMT(DXT1, Conv24toDXT1); - } + CHECK_FOR_FMT(R8G8B8); - if (!dx_force_16bpptextures) { -// if (!(want_16bit_rgb_textures || dx_force_16bpptextures)) { - CHECK_FOR_FMT(R8G8B8, Conv24to24); + // no 24-bit fmt. look for 32 bit fmt (note: this is + // memory-hogging choice instead I could look for + // memory-conserving 16-bit fmt). - // no 24-bit fmt. look for 32 bit fmt (note: this is - // memory-hogging choice instead I could look for - // memory-conserving 16-bit fmt). - - CHECK_FOR_FMT(X8R8G8B8, Conv24to32); - } + CHECK_FOR_FMT(X8R8G8B8); + CHECK_FOR_FMT(A8R8G8B8); // no 24-bit or 32 fmt. look for 16 bit fmt (higher res 565 1st) - CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); + CHECK_FOR_FMT(A1R5G5B5); break; case 16: @@ -462,22 +487,16 @@ create_texture(DXScreenData &scrn) { nassertr(num_alpha_bits > 0, false); nassertr(num_color_channels == 2, false); - CHECK_FOR_FMT(A8L8, ConvLum16to16); + CHECK_FOR_FMT(A8L8); + CHECK_FOR_FMT(A8R8G8B8); - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8, ConvLum16to32); - } - -#ifndef FORCE_16bpp_1555 - if (num_alpha_bits == 1) -#endif - { - CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); + if (num_alpha_bits == 1) { + CHECK_FOR_FMT(A1R5G5B5); } // normally prefer 4444 due to better alpha channel resolution - CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444); - CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555); + CHECK_FOR_FMT(A4R4G4B4); + CHECK_FOR_FMT(A1R5G5B5); } else { nassertr((num_color_channels == 3)||(num_color_channels == 4), false); // look for compatible 16bit fmts, if none then give up @@ -485,13 +504,13 @@ create_texture(DXScreenData &scrn) { switch(num_alpha_bits) { case 0: if (num_color_channels == 3) { - CHECK_FOR_FMT(R5G6B5, Conv24to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else { nassertr(num_color_channels == 4, false); // it could be 4 if user asks us to throw away the alpha channel - CHECK_FOR_FMT(R5G6B5, Conv32to16_0565); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } break; case 1: @@ -500,13 +519,13 @@ create_texture(DXScreenData &scrn) { // could use 32bpp ARGB. fail if this particular fmt not // avail. nassertr(num_color_channels == 4, false); - CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555); + CHECK_FOR_FMT(X1R5G5B5); break; case 4: // app specifically requests 4-4-4-4 F_rgba4 case, as opposed // to F_rgba, which could use 32bpp ARGB nassertr(num_color_channels == 4, false); - CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444); + CHECK_FOR_FMT(A4R4G4B4); break; default: nassertr(false, false); // problem in get_bits_per_pixel()? @@ -519,16 +538,14 @@ create_texture(DXScreenData &scrn) { nassertr(num_color_channels == 1, false); // look for native lum fmt first - CHECK_FOR_FMT(L8, ConvLum8to8); - CHECK_FOR_FMT(L8, ConvLum8to16_A8L8); + CHECK_FOR_FMT(L8); + CHECK_FOR_FMT(L8); - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(R8G8B8, ConvLum8to24); - CHECK_FOR_FMT(X8R8G8B8, ConvLum8to32); - } + CHECK_FOR_FMT(R8G8B8); + CHECK_FOR_FMT(X8R8G8B8); - CHECK_FOR_FMT(R5G6B5, ConvLum8to16_0565); - CHECK_FOR_FMT(X1R5G5B5, ConvLum8to16_X555); + CHECK_FOR_FMT(R5G6B5); + CHECK_FOR_FMT(X1R5G5B5); } else if (num_alpha_bits == 8) { // look for 16bpp A8L8, else 32-bit ARGB, else 16-4444. @@ -538,13 +555,9 @@ create_texture(DXScreenData &scrn) { // model we need somehow (is it that voodoo assumes color is // white? isnt that what we do in ConvAlpha8to32 anyway?) - CHECK_FOR_FMT(A8L8, ConvAlpha8to16_A8L8); - - if (!dx_force_16bpptextures) { - CHECK_FOR_FMT(A8R8G8B8, ConvAlpha8to32); - } - - CHECK_FOR_FMT(A4R4G4B4, ConvAlpha8to16_4444); + CHECK_FOR_FMT(A8L8); + CHECK_FOR_FMT(A8R8G8B8); + CHECK_FOR_FMT(A4R4G4B4); } break; @@ -1739,7 +1752,7 @@ fill_d3d_texture_pixels(DXScreenData &scrn) { int miplevel_count = _d3d_2d_texture->GetLevelCount(); // what if it's not a 2d texture? if (miplevel_count <= tex->get_num_loadable_ram_mipmap_images()) { dxgsg9_cat.debug() - << "Using pre-calculated mipmap levels for texture " << tex->get_name(); + << "Using pre-calculated mipmap levels for texture " << tex->get_name() << "\n"; for (int mip_level = 1; mip_level < miplevel_count; ++mip_level) { hr = fill_d3d_texture_mipmap_pixels(mip_level, di, source_format); @@ -2031,10 +2044,10 @@ get_bits_per_pixel(Texture::Format format, int *alphbits) { return 24; case Texture::F_rgba8: case Texture::F_rgba: + *alphbits = 8; + return 32; case Texture::F_rgbm: - if (format == Texture::F_rgbm) // does this make any sense? - *alphbits = 1; - else *alphbits = 8; + *alphbits = 1; return 32; case Texture::F_rgb12: return 36; diff --git a/panda/src/dxgsg9/dxTextureContext9.h b/panda/src/dxgsg9/dxTextureContext9.h index 3410b2d1b9..785825c123 100755 --- a/panda/src/dxgsg9/dxTextureContext9.h +++ b/panda/src/dxgsg9/dxTextureContext9.h @@ -30,6 +30,8 @@ public: DXTextureContext9(PreparedGraphicsObjects *pgo, Texture *tex); virtual ~DXTextureContext9(); + virtual void evict_lru(); + bool create_texture(DXScreenData &scrn); bool create_simple_texture(DXScreenData &scrn); void delete_texture(); diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.cxx b/panda/src/dxgsg9/dxVertexBufferContext9.cxx index 5b10007106..d276c129c6 100755 --- a/panda/src/dxgsg9/dxVertexBufferContext9.cxx +++ b/panda/src/dxgsg9/dxVertexBufferContext9.cxx @@ -305,6 +305,29 @@ DXVertexBufferContext9:: } } +//////////////////////////////////////////////////////////////////// +// Function: DXVertexBufferContext9::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void DXVertexBufferContext9:: +evict_lru() { + dequeue_lru(); + free_vbuffer(); + update_data_size_bytes(0); + mark_unloaded(); +} + //////////////////////////////////////////////////////////////////// // Function: DXVertexBufferContext9::free_vbuffer // Access: Public diff --git a/panda/src/dxgsg9/dxVertexBufferContext9.h b/panda/src/dxgsg9/dxVertexBufferContext9.h index d9c094db81..d59cce715e 100755 --- a/panda/src/dxgsg9/dxVertexBufferContext9.h +++ b/panda/src/dxgsg9/dxVertexBufferContext9.h @@ -29,6 +29,8 @@ public: DXVertexBufferContext9(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data, DXScreenData &scrn); virtual ~DXVertexBufferContext9(); + virtual void evict_lru(); + void free_vbuffer(); void allocate_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader); void create_vbuffer(DXScreenData &scrn, const GeomVertexArrayDataHandle *reader, string name); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 83c589026d..f88627b14e 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -2676,6 +2676,7 @@ update_texture(TextureContext *tc, bool force) { specify_texture(gtc->get_texture()); gtc->mark_loaded(); } + gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); report_my_gl_errors(); return true; @@ -2814,7 +2815,7 @@ record_deleted_display_list(GLuint index) { VertexBufferContext *CLP(GraphicsStateGuardian):: prepare_vertex_buffer(GeomVertexArrayData *data) { if (_supports_buffers) { - CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(_prepared_objects, data); + CLP(VertexBufferContext) *gvbc = new CLP(VertexBufferContext)(this, _prepared_objects, data); _glGenBuffers(1, &gvbc->_index); if (GLCAT.is_debug() && CLP(debug_buffers)) { @@ -2881,6 +2882,7 @@ apply_vertex_buffer(VertexBufferContext *vbc, gvbc->mark_loaded(reader); } + gvbc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); maybe_gl_finish(); report_my_gl_errors(); @@ -2998,7 +3000,7 @@ setup_array_data(const unsigned char *&client_pointer, IndexBufferContext *CLP(GraphicsStateGuardian):: prepare_index_buffer(GeomPrimitive *data) { if (_supports_buffers) { - CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(_prepared_objects, data); + CLP(IndexBufferContext) *gibc = new CLP(IndexBufferContext)(this, _prepared_objects, data); _glGenBuffers(1, &gibc->_index); if (GLCAT.is_debug() && CLP(debug_buffers)) { @@ -3067,6 +3069,7 @@ apply_index_buffer(IndexBufferContext *ibc, } gibc->mark_loaded(reader); } + gibc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); maybe_gl_finish(); report_my_gl_errors(); @@ -3356,6 +3359,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, } gtc->mark_loaded(); + gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); report_my_gl_errors(); diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 9a56ab7650..7ec0b183ae 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -533,6 +533,8 @@ public: private: static TypeHandle _type_handle; + friend class CLP(VertexBufferContext); + friend class CLP(IndexBufferContext); friend class CLP(ShaderContext); friend class CLP(GraphicsBuffer); friend class CLP(OcclusionQueryContext); diff --git a/panda/src/glstuff/glIndexBufferContext_src.I b/panda/src/glstuff/glIndexBufferContext_src.I index 825113ecca..d962419ce6 100644 --- a/panda/src/glstuff/glIndexBufferContext_src.I +++ b/panda/src/glstuff/glIndexBufferContext_src.I @@ -19,8 +19,11 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE CLP(IndexBufferContext):: -CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, GeomPrimitive *data) : - IndexBufferContext(pgo, data) +CLP(IndexBufferContext)(CLP(GraphicsStateGuardian) *glgsg, + PreparedGraphicsObjects *pgo, + GeomPrimitive *data) : + IndexBufferContext(pgo, data), + _glgsg(glgsg) { _index = 0; } diff --git a/panda/src/glstuff/glIndexBufferContext_src.cxx b/panda/src/glstuff/glIndexBufferContext_src.cxx index 2d58cb3a89..8111a06dd3 100644 --- a/panda/src/glstuff/glIndexBufferContext_src.cxx +++ b/panda/src/glstuff/glIndexBufferContext_src.cxx @@ -13,3 +13,43 @@ //////////////////////////////////////////////////////////////////// TypeHandle CLP(IndexBufferContext)::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: GLIndexBufferContext::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void CLP(IndexBufferContext):: +evict_lru() { + dequeue_lru(); + + // Make sure the buffer is unbound before we delete it. + if (_glgsg->_current_ibuffer_index == _index) { + if (GLCAT.is_debug() && CLP(debug_buffers)) { + GLCAT.debug() + << "unbinding index buffer\n"; + } + _glgsg->_glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + _glgsg->_current_ibuffer_index = 0; + } + + // Free the buffer. + _glgsg->_glDeleteBuffers(1, &_index); + + // We still need a valid index number, though, in case we want to + // re-load the buffer later. + _glgsg->_glGenBuffers(1, &_index); + + update_data_size_bytes(0); + mark_unloaded(); +} diff --git a/panda/src/glstuff/glIndexBufferContext_src.h b/panda/src/glstuff/glIndexBufferContext_src.h index 4df7d8f85a..960ff05e9d 100644 --- a/panda/src/glstuff/glIndexBufferContext_src.h +++ b/panda/src/glstuff/glIndexBufferContext_src.h @@ -23,10 +23,15 @@ //////////////////////////////////////////////////////////////////// class EXPCL_GL CLP(IndexBufferContext) : public IndexBufferContext { public: - INLINE CLP(IndexBufferContext)(PreparedGraphicsObjects *pgo, + INLINE CLP(IndexBufferContext)(CLP(GraphicsStateGuardian) *glgsg, + PreparedGraphicsObjects *pgo, GeomPrimitive *data); ALLOC_DELETED_CHAIN(CLP(IndexBufferContext)); + virtual void evict_lru(); + + CLP(GraphicsStateGuardian) *_glgsg; + // This is the GL "name" of the data object. GLuint _index; diff --git a/panda/src/glstuff/glTextureContext_src.cxx b/panda/src/glstuff/glTextureContext_src.cxx index 42f8065996..690465394f 100644 --- a/panda/src/glstuff/glTextureContext_src.cxx +++ b/panda/src/glstuff/glTextureContext_src.cxx @@ -15,3 +15,35 @@ #include "pnotify.h" TypeHandle CLP(TextureContext)::_type_handle; + + +//////////////////////////////////////////////////////////////////// +// Function: GLTextureContext::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void CLP(TextureContext):: +evict_lru() { + dequeue_lru(); + + // Free the texture resources. + GLP(DeleteTextures)(1, &_index); + + // We still need a valid index number, though, in case we want to + // re-load the texture later. + GLP(GenTextures)(1, &_index); + + _already_applied = false; + update_data_size_bytes(0); + mark_unloaded(); +} diff --git a/panda/src/glstuff/glTextureContext_src.h b/panda/src/glstuff/glTextureContext_src.h index 0428945bee..c65a3d21d1 100644 --- a/panda/src/glstuff/glTextureContext_src.h +++ b/panda/src/glstuff/glTextureContext_src.h @@ -25,6 +25,8 @@ public: INLINE CLP(TextureContext)(PreparedGraphicsObjects *pgo, Texture *tex); ALLOC_DELETED_CHAIN(CLP(TextureContext)); + virtual void evict_lru(); + // This is the GL "name" of the texture object. GLuint _index; diff --git a/panda/src/glstuff/glVertexBufferContext_src.I b/panda/src/glstuff/glVertexBufferContext_src.I index 259436c53b..3cc7dd67a3 100644 --- a/panda/src/glstuff/glVertexBufferContext_src.I +++ b/panda/src/glstuff/glVertexBufferContext_src.I @@ -19,8 +19,11 @@ // Description: //////////////////////////////////////////////////////////////////// INLINE CLP(VertexBufferContext):: -CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) : - VertexBufferContext(pgo, data) +CLP(VertexBufferContext)(CLP(GraphicsStateGuardian) *glgsg, + PreparedGraphicsObjects *pgo, + GeomVertexArrayData *data) : + VertexBufferContext(pgo, data), + _glgsg(glgsg) { _index = 0; } diff --git a/panda/src/glstuff/glVertexBufferContext_src.cxx b/panda/src/glstuff/glVertexBufferContext_src.cxx index 47054fb9ba..1323f8dffc 100644 --- a/panda/src/glstuff/glVertexBufferContext_src.cxx +++ b/panda/src/glstuff/glVertexBufferContext_src.cxx @@ -13,3 +13,43 @@ //////////////////////////////////////////////////////////////////// TypeHandle CLP(VertexBufferContext)::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: GLVertexBufferContext::evict_lru +// Access: Public, Virtual +// Description: Evicts the page from the LRU. Called internally when +// the LRU determines that it is full. May also be +// called externally when necessary to explicitly evict +// the page. +// +// It is legal for this method to either evict the page +// as requested, do nothing (in which case the eviction +// will be requested again at the next epoch), or +// requeue itself on the tail of the queue (in which +// case the eviction will be requested again much +// later). +//////////////////////////////////////////////////////////////////// +void CLP(VertexBufferContext):: +evict_lru() { + dequeue_lru(); + + // Make sure the buffer is unbound before we delete it. + if (_glgsg->_current_vbuffer_index == _index) { + if (GLCAT.is_debug() && CLP(debug_buffers)) { + GLCAT.debug() + << "unbinding vertex buffer\n"; + } + _glgsg->_glBindBuffer(GL_ARRAY_BUFFER, 0); + _glgsg->_current_vbuffer_index = 0; + } + + // Free the buffer. + _glgsg->_glDeleteBuffers(1, &_index); + + // We still need a valid index number, though, in case we want to + // re-load the buffer later. + _glgsg->_glGenBuffers(1, &_index); + + update_data_size_bytes(0); + mark_unloaded(); +} diff --git a/panda/src/glstuff/glVertexBufferContext_src.h b/panda/src/glstuff/glVertexBufferContext_src.h index 009c59f400..a9806fd154 100644 --- a/panda/src/glstuff/glVertexBufferContext_src.h +++ b/panda/src/glstuff/glVertexBufferContext_src.h @@ -16,6 +16,8 @@ #include "vertexBufferContext.h" #include "deletedChain.h" +class CLP(GraphicsStateGuardian); + //////////////////////////////////////////////////////////////////// // Class : GLVertexBufferContext // Description : Caches a GeomVertexArrayData on the GL as a buffer @@ -23,10 +25,15 @@ //////////////////////////////////////////////////////////////////// class EXPCL_GL CLP(VertexBufferContext) : public VertexBufferContext { public: - INLINE CLP(VertexBufferContext)(PreparedGraphicsObjects *pgo, + INLINE CLP(VertexBufferContext)(CLP(GraphicsStateGuardian) *glgsg, + PreparedGraphicsObjects *pgo, GeomVertexArrayData *data); ALLOC_DELETED_CHAIN(CLP(VertexBufferContext)); + virtual void evict_lru(); + + CLP(GraphicsStateGuardian) *_glgsg; + // This is the GL "name" of the data object. GLuint _index; diff --git a/panda/src/gobj/config_gobj.cxx b/panda/src/gobj/config_gobj.cxx index c336ed8407..d1d3daf0cf 100644 --- a/panda/src/gobj/config_gobj.cxx +++ b/panda/src/gobj/config_gobj.cxx @@ -374,6 +374,19 @@ ConfigVariableInt vertex_data_page_threads "is 0, this work will be done in the main thread, which may " "introduce occasional random chugs in rendering.")); +ConfigVariableInt graphics_memory_limit +("graphics-memory-limit", -1, + PRC_DESC("This is a default limit that is imposed on each GSG at " + "GSG creation time. It limits the total amount of graphics " + "memory, including texture memory and vertex buffer memory, " + "that will be consumed by the GSG, regardless of whether the " + "hardware claims to provide more graphics memory than this. " + "It is useful to put a ceiling on graphics memory consumed, since " + "some drivers seem to allow the application to consume more " + "memory than the hardware can realistically support. " + "Set this to -1 to have no limit other than the normal " + "hardware-imposed limit.")); + ConfigureFn(config_gobj) { BufferContext::init_type(); Geom::init_type(); diff --git a/panda/src/gobj/config_gobj.h b/panda/src/gobj/config_gobj.h index cb55ee011d..c6784265d9 100644 --- a/panda/src/gobj/config_gobj.h +++ b/panda/src/gobj/config_gobj.h @@ -92,6 +92,7 @@ extern EXPCL_PANDA_GOBJ ConfigVariableFilename vertex_save_file_directory; extern EXPCL_PANDA_GOBJ ConfigVariableString vertex_save_file_prefix; extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_small_size; extern EXPCL_PANDA_GOBJ ConfigVariableInt vertex_data_page_threads; +extern EXPCL_PANDA_GOBJ ConfigVariableInt graphics_memory_limit; #endif diff --git a/panda/src/gobj/indexBufferContext.I b/panda/src/gobj/indexBufferContext.I index 6836a2aa8c..0c3f199272 100644 --- a/panda/src/gobj/indexBufferContext.I +++ b/panda/src/gobj/indexBufferContext.I @@ -21,6 +21,7 @@ INLINE IndexBufferContext:: IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data) : BufferContext(&pgo->_ibuffer_residency), + SimpleLruPage(0), _data(data) { } @@ -72,6 +73,18 @@ was_modified(const GeomPrimitivePipelineReader *reader) const { return get_modified() != reader->get_modified(); } +//////////////////////////////////////////////////////////////////// +// Function: IndexBufferContext::update_data_size_bytes +// Access: Public +// Description: Should be called (usually by a derived class) when +// the on-card size of this object has changed. +//////////////////////////////////////////////////////////////////// +INLINE void IndexBufferContext:: +update_data_size_bytes(size_t new_data_size_bytes) { + BufferContext::update_data_size_bytes(new_data_size_bytes); + SimpleLruPage::set_lru_size(new_data_size_bytes); +} + //////////////////////////////////////////////////////////////////// // Function: IndexBufferContext::mark_loaded // Access: Public @@ -89,3 +102,15 @@ mark_loaded(const GeomPrimitivePipelineReader *reader) { // Assume the buffer is now resident. set_resident(true); } + +//////////////////////////////////////////////////////////////////// +// Function: IndexBufferContext::mark_unloaded +// Access: Public +// Description: Should be called after the buffer has been forced +// out of graphics memory. +//////////////////////////////////////////////////////////////////// +INLINE void IndexBufferContext:: +mark_unloaded() { + update_modified(UpdateSeq::old()); + set_resident(false); +} diff --git a/panda/src/gobj/indexBufferContext.h b/panda/src/gobj/indexBufferContext.h index 8c520aaedd..e810a40bb2 100644 --- a/panda/src/gobj/indexBufferContext.h +++ b/panda/src/gobj/indexBufferContext.h @@ -20,6 +20,7 @@ #include "bufferContext.h" #include "geomPrimitive.h" #include "preparedGraphicsObjects.h" +#include "simpleLru.h" //////////////////////////////////////////////////////////////////// // Class : IndexBufferContext @@ -32,7 +33,7 @@ // allocate a vertex buffer for the array. OpenGL can // create a buffer object. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_GOBJ IndexBufferContext : public BufferContext { +class EXPCL_PANDA_GOBJ IndexBufferContext : public BufferContext, public SimpleLruPage { public: INLINE IndexBufferContext(PreparedGraphicsObjects *pgo, GeomPrimitive *data); @@ -44,7 +45,9 @@ PUBLISHED: INLINE bool was_modified(const GeomPrimitivePipelineReader *reader) const; public: + INLINE void update_data_size_bytes(size_t new_data_size_bytes); INLINE void mark_loaded(const GeomPrimitivePipelineReader *reader); + INLINE void mark_unloaded(); private: // This cannot be a PT(GeomPrimitive), because the data and diff --git a/panda/src/gobj/preparedGraphicsObjects.I b/panda/src/gobj/preparedGraphicsObjects.I index 355418df49..d29a62b346 100644 --- a/panda/src/gobj/preparedGraphicsObjects.I +++ b/panda/src/gobj/preparedGraphicsObjects.I @@ -25,6 +25,38 @@ get_name() const { return _name; } +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::set_graphics_memory_limit +// Access: Public +// Description: Sets an artificial cap on graphics memory that +// will be imposed on this GSG. +// +// This limits the total amount of graphics memory, +// including texture memory and vertex buffer memory, +// that will be consumed by the GSG, regardless of +// whether the hardware claims to provide more graphics +// memory than this. It is useful to put a ceiling on +// graphics memory consumed, since some drivers seem to +// allow the application to consume more memory than the +// hardware can realistically support. +//////////////////////////////////////////////////////////////////// +INLINE void PreparedGraphicsObjects:: +set_graphics_memory_limit(size_t limit) { + _graphics_memory_lru.set_max_size(limit); +} + +//////////////////////////////////////////////////////////////////// +// Function: PreparedGraphicsObjects::get_graphics_memory_limit +// Access: Public +// Description: Returns the artificial cap on graphics memory that +// will be imposed on this GSG. See +// set_graphics_memory_limit(). +//////////////////////////////////////////////////////////////////// +INLINE size_t PreparedGraphicsObjects:: +get_graphics_memory_limit() const { + return _graphics_memory_lru.get_max_size(); +} + //////////////////////////////////////////////////////////////////// // Function: PreparedGraphicsObjects::release_all // Access: Public diff --git a/panda/src/gobj/preparedGraphicsObjects.cxx b/panda/src/gobj/preparedGraphicsObjects.cxx index 7cd8a4a9e2..63d1c027dc 100644 --- a/panda/src/gobj/preparedGraphicsObjects.cxx +++ b/panda/src/gobj/preparedGraphicsObjects.cxx @@ -24,6 +24,7 @@ #include "reMutexHolder.h" #include "geomContext.h" #include "shaderContext.h" +#include "config_gobj.h" int PreparedGraphicsObjects::_name_index = 0; @@ -40,7 +41,8 @@ PreparedGraphicsObjects() : _index_buffer_cache_size(0), _texture_residency(_name, "texture"), _vbuffer_residency(_name, "vbuffer"), - _ibuffer_residency(_name, "ibuffer") + _ibuffer_residency(_name, "ibuffer"), + _graphics_memory_lru("graphics_memory_lru", graphics_memory_limit) { // GLGSG will turn this flag on. This is a temporary hack to // disable this feature for DX8/DX9 for now, until we work out the diff --git a/panda/src/gobj/preparedGraphicsObjects.h b/panda/src/gobj/preparedGraphicsObjects.h index 41993a365a..4ec56db61f 100644 --- a/panda/src/gobj/preparedGraphicsObjects.h +++ b/panda/src/gobj/preparedGraphicsObjects.h @@ -62,6 +62,9 @@ public: PUBLISHED: INLINE const string &get_name() const; + INLINE void set_graphics_memory_limit(size_t limit); + INLINE size_t get_graphics_memory_limit() const; + INLINE void release_all(); INLINE int get_num_queued() const; INLINE int get_num_prepared() const; @@ -196,6 +199,8 @@ public: BufferResidencyTracker _vbuffer_residency; BufferResidencyTracker _ibuffer_residency; + SimpleLru _graphics_memory_lru; + public: // This is only public as a temporary hack. Don't mess with it // unless you know what you're doing. diff --git a/panda/src/gobj/simpleLru.I b/panda/src/gobj/simpleLru.I index 568be1a40d..2d71911bc6 100644 --- a/panda/src/gobj/simpleLru.I +++ b/panda/src/gobj/simpleLru.I @@ -50,7 +50,7 @@ set_max_size(size_t max_size) { MutexHolder holder(_global_lock); _max_size = max_size; if (_total_size > _max_size) { - do_evict(); + do_evict_to(_max_size, false); } } @@ -63,7 +63,22 @@ INLINE void SimpleLru:: consider_evict() { MutexHolder holder(_global_lock); if (_total_size > _max_size) { - do_evict(); + do_evict_to(_max_size, false); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: SimpleLru::evict_to +// Access: Published +// Description: Evicts a sequence of objects until the queue fits +// within the indicated target size, regardless of its +// normal max size. +//////////////////////////////////////////////////////////////////// +INLINE void SimpleLru:: +evict_to(size_t target_size) { + MutexHolder holder(_global_lock); + if (_total_size > target_size) { + do_evict_to(target_size, true); } } diff --git a/panda/src/gobj/simpleLru.cxx b/panda/src/gobj/simpleLru.cxx index 5b96a8a4f4..df2794f794 100644 --- a/panda/src/gobj/simpleLru.cxx +++ b/panda/src/gobj/simpleLru.cxx @@ -114,14 +114,15 @@ count_active_size() const { } //////////////////////////////////////////////////////////////////// -// Function: SimpleLru::do_evict +// Function: SimpleLru::do_evict_to // Access: Private -// Description: Evicts pages until the LRU is within tolerance. -// Assumes the lock is already held. Does not evict -// "active" pages that were added within this epoch. +// Description: Evicts pages until the LRU is within the indicated +// size. Assumes the lock is already held. If +// hard_evict is false, does not evict "active" pages +// that were added within this epoch. //////////////////////////////////////////////////////////////////// void SimpleLru:: -do_evict() { +do_evict_to(size_t target_size, bool hard_evict) { if (_next == this) { // Nothing in the queue. return; @@ -134,7 +135,7 @@ do_evict() { // Now walk through the list. SimpleLruPage *node = (SimpleLruPage *)_next; - while (_total_size > _max_size) { + while (_total_size > target_size) { SimpleLruPage *next = (SimpleLruPage *)node->_next; // We must release the lock while we call evict_lru(). @@ -146,7 +147,7 @@ do_evict() { // If we reach the original tail of the list, stop. return; } - if (node == _active_marker) { + if (!hard_evict && node == _active_marker) { // Also stop if we reach the active marker. Nodes beyond this // were added within this epoch. return; diff --git a/panda/src/gobj/simpleLru.h b/panda/src/gobj/simpleLru.h index 43d83cca40..1b7ee0a4cb 100644 --- a/panda/src/gobj/simpleLru.h +++ b/panda/src/gobj/simpleLru.h @@ -38,13 +38,14 @@ PUBLISHED: size_t count_active_size() const; INLINE void consider_evict(); + INLINE void evict_to(size_t target_size); INLINE void begin_epoch(); public: static Mutex &_global_lock; private: - void do_evict(); + void do_evict_to(size_t target_size, bool hard_evict); bool do_validate_size(); size_t _total_size; diff --git a/panda/src/gobj/textureContext.I b/panda/src/gobj/textureContext.I index b6c273391a..f37eac86f5 100644 --- a/panda/src/gobj/textureContext.I +++ b/panda/src/gobj/textureContext.I @@ -21,6 +21,7 @@ INLINE TextureContext:: TextureContext(PreparedGraphicsObjects *pgo, Texture *tex) : BufferContext(&pgo->_texture_residency), + SimpleLruPage(0), _texture(tex) { } @@ -84,6 +85,18 @@ was_simple_image_modified() const { return _simple_image_modified != _texture->get_simple_image_modified(); } +//////////////////////////////////////////////////////////////////// +// Function: TextureContext::update_data_size_bytes +// Access: Public +// Description: Should be called (usually by a derived class) when +// the on-card size of this object has changed. +//////////////////////////////////////////////////////////////////// +INLINE void TextureContext:: +update_data_size_bytes(size_t new_data_size_bytes) { + BufferContext::update_data_size_bytes(new_data_size_bytes); + SimpleLruPage::set_lru_size(new_data_size_bytes); +} + //////////////////////////////////////////////////////////////////// // Function: TextureContext::mark_loaded // Access: Public @@ -117,3 +130,19 @@ mark_simple_loaded() { // The texture's not exactly resident now, but some part of it is. set_resident(true); } + +//////////////////////////////////////////////////////////////////// +// Function: TextureContext::mark_unloaded +// Access: Public +// Description: Should be called after the texture has been forced +// out of texture memory. +//////////////////////////////////////////////////////////////////// +INLINE void TextureContext:: +mark_unloaded() { + _properties_modified = UpdateSeq::old(); + _image_modified = UpdateSeq::old(); + _simple_image_modified = UpdateSeq::old(); + update_modified(UpdateSeq::old()); + + set_resident(false); +} diff --git a/panda/src/gobj/textureContext.h b/panda/src/gobj/textureContext.h index 2c26d4449d..8343249603 100644 --- a/panda/src/gobj/textureContext.h +++ b/panda/src/gobj/textureContext.h @@ -20,6 +20,7 @@ #include "bufferContext.h" #include "texture.h" #include "preparedGraphicsObjects.h" +#include "simpleLru.h" //////////////////////////////////////////////////////////////////// // Class : TextureContext @@ -34,7 +35,7 @@ // texture and store it here. The texture stores all of // these handles internally. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_GOBJ TextureContext : public BufferContext { +class EXPCL_PANDA_GOBJ TextureContext : public BufferContext, public SimpleLruPage { public: INLINE TextureContext(PreparedGraphicsObjects *pgo, Texture *tex); @@ -47,8 +48,10 @@ PUBLISHED: INLINE bool was_simple_image_modified() const; public: + INLINE void update_data_size_bytes(size_t new_data_size_bytes); INLINE void mark_loaded(); INLINE void mark_simple_loaded(); + INLINE void mark_unloaded(); private: // This cannot be a PT(Texture), because the texture and the GSG diff --git a/panda/src/gobj/vertexBufferContext.I b/panda/src/gobj/vertexBufferContext.I index 8c5a04fc03..91e5094a32 100644 --- a/panda/src/gobj/vertexBufferContext.I +++ b/panda/src/gobj/vertexBufferContext.I @@ -21,6 +21,7 @@ INLINE VertexBufferContext:: VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data) : BufferContext(&pgo->_vbuffer_residency), + SimpleLruPage(0), _data(data) { } @@ -72,6 +73,18 @@ was_modified(const GeomVertexArrayDataHandle *reader) const { return get_modified() != reader->get_modified(); } +//////////////////////////////////////////////////////////////////// +// Function: VertexBufferContext::update_data_size_bytes +// Access: Public +// Description: Should be called (usually by a derived class) when +// the on-card size of this object has changed. +//////////////////////////////////////////////////////////////////// +INLINE void VertexBufferContext:: +update_data_size_bytes(size_t new_data_size_bytes) { + BufferContext::update_data_size_bytes(new_data_size_bytes); + SimpleLruPage::set_lru_size(new_data_size_bytes); +} + //////////////////////////////////////////////////////////////////// // Function: VertexBufferContext::mark_loaded // Access: Public @@ -89,3 +102,15 @@ mark_loaded(const GeomVertexArrayDataHandle *reader) { // Assume the buffer is now resident. set_resident(true); } + +//////////////////////////////////////////////////////////////////// +// Function: VertexBufferContext::mark_unloaded +// Access: Public +// Description: Should be called after the buffer has been forced +// out of graphics memory. +//////////////////////////////////////////////////////////////////// +INLINE void VertexBufferContext:: +mark_unloaded() { + update_modified(UpdateSeq::old()); + set_resident(false); +} diff --git a/panda/src/gobj/vertexBufferContext.h b/panda/src/gobj/vertexBufferContext.h index ea5b4e1ad0..b2550fbbbe 100644 --- a/panda/src/gobj/vertexBufferContext.h +++ b/panda/src/gobj/vertexBufferContext.h @@ -20,6 +20,7 @@ #include "bufferContext.h" #include "geomVertexArrayData.h" #include "preparedGraphicsObjects.h" +#include "simpleLru.h" //////////////////////////////////////////////////////////////////// // Class : VertexBufferContext @@ -32,7 +33,7 @@ // allocate a vertex buffer for the array. OpenGL can // create a buffer object. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA_GOBJ VertexBufferContext : public BufferContext { +class EXPCL_PANDA_GOBJ VertexBufferContext : public BufferContext, public SimpleLruPage { public: INLINE VertexBufferContext(PreparedGraphicsObjects *pgo, GeomVertexArrayData *data); @@ -45,7 +46,9 @@ PUBLISHED: INLINE bool was_modified(const GeomVertexArrayDataHandle *reader) const; public: + INLINE void update_data_size_bytes(size_t new_data_size_bytes); INLINE void mark_loaded(const GeomVertexArrayDataHandle *reader); + INLINE void mark_unloaded(); private: // This cannot be a PT(GeomVertexArrayData), because the data and diff --git a/panda/src/tinydisplay/config_tinydisplay.cxx b/panda/src/tinydisplay/config_tinydisplay.cxx index 19a6b309ba..7a036d83d3 100644 --- a/panda/src/tinydisplay/config_tinydisplay.cxx +++ b/panda/src/tinydisplay/config_tinydisplay.cxx @@ -79,16 +79,6 @@ ConfigVariableInt osx_mouse_wheel_scale PRC_DESC("Specify the number of units to spin the Mac mouse wheel to " "represent a single wheel_up or wheel_down message.")); -ConfigVariableInt td_texture_ram -("td-texture-ram", -1, - PRC_DESC("This specifies the maximum amount of RAM to devote to keeping " - "textures resident with the tinydisplay software renderer. When " - "this limit is exceeded, textures over the limit that have not " - "been rendered within the current frame will be evicted. " - "(Textures will not be evicted while they are still in the " - "frame, even if this means this limit remains exceeded.) " - "Set it to -1 for no limit.")); - ConfigVariableBool td_ignore_mipmaps ("td-ignore-mipmaps", false, PRC_DESC("Configure this true to disable use of mipmaps on the " diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx index dbbaa61dda..b0a9f8993f 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.cxx @@ -50,8 +50,7 @@ PStatCollector TinyGraphicsStateGuardian::_pixel_count_smooth_perspective_pcolle TinyGraphicsStateGuardian:: TinyGraphicsStateGuardian(GraphicsPipe *pipe, TinyGraphicsStateGuardian *share_with) : - GraphicsStateGuardian(CS_yup_right, pipe), - _textures_lru("textures_lru", td_texture_ram) + GraphicsStateGuardian(CS_yup_right, pipe) { _current_frame_buffer = NULL; _aux_frame_buffer = NULL; @@ -466,9 +465,6 @@ end_frame(Thread *current_thread) { _pixel_count_flat_perspective_pcollector.flush_level(); _pixel_count_smooth_perspective_pcollector.flush_level(); #endif // DO_PSTATS - - // Evict any textures that exceed our texture memory. - _textures_lru.begin_epoch(); } @@ -1274,7 +1270,7 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, gtc->update_data_size_bytes(gltex->xsize * gltex->ysize * 4); gtc->mark_loaded(); - gtc->enqueue_lru(&_textures_lru); + gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); return true; } @@ -1501,7 +1497,7 @@ update_texture(TextureContext *tc, bool force) { return false; } } - gtc->enqueue_lru(&_textures_lru); + gtc->enqueue_lru(&_prepared_objects->_graphics_memory_lru); _c->current_texture = gltex; _c->zb->current_texture = gltex->levels; diff --git a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h index 8ba9244233..edb05814a5 100644 --- a/panda/src/tinydisplay/tinyGraphicsStateGuardian.h +++ b/panda/src/tinydisplay/tinyGraphicsStateGuardian.h @@ -145,8 +145,6 @@ private: bool _texture_replace; bool _filled_flat; - SimpleLru _textures_lru; - CPT(TransformState) _scissor_mat; // Used during being_draw_primitives() .. end_draw_primitives(). diff --git a/panda/src/tinydisplay/tinyTextureContext.I b/panda/src/tinydisplay/tinyTextureContext.I index 1aca32efd5..04701cd434 100644 --- a/panda/src/tinydisplay/tinyTextureContext.I +++ b/panda/src/tinydisplay/tinyTextureContext.I @@ -20,7 +20,7 @@ //////////////////////////////////////////////////////////////////// INLINE TinyTextureContext:: TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex) : - TextureContext(pgo, tex), SimpleLruPage(0) + TextureContext(pgo, tex) { _gltex.num_levels = 0; _gltex.allocated_buffer = NULL; @@ -36,16 +36,3 @@ INLINE TinyTextureContext:: ~TinyTextureContext() { nassertv(_gltex.num_levels == 0 && _gltex.allocated_buffer == NULL && _gltex.total_bytecount == 0); } - -//////////////////////////////////////////////////////////////////// -// Function: TinyTextureContext::update_data_size_bytes -// Access: Public -// Description: This is overloaded (non-virtually) to update both the -// BufferContext and the LRU page with the same -// information. -//////////////////////////////////////////////////////////////////// -INLINE void TinyTextureContext:: -update_data_size_bytes(size_t new_data_size_bytes) { - TextureContext::update_data_size_bytes(new_data_size_bytes); - SimpleLruPage::set_lru_size(new_data_size_bytes); -} diff --git a/panda/src/tinydisplay/tinyTextureContext.cxx b/panda/src/tinydisplay/tinyTextureContext.cxx index 44c726b640..3addd211ff 100644 --- a/panda/src/tinydisplay/tinyTextureContext.cxx +++ b/panda/src/tinydisplay/tinyTextureContext.cxx @@ -48,5 +48,6 @@ evict_lru() { nassertv(gltex->num_levels == 0); } - set_resident(false); + update_data_size_bytes(0); + mark_unloaded(); } diff --git a/panda/src/tinydisplay/tinyTextureContext.h b/panda/src/tinydisplay/tinyTextureContext.h index 9516939951..6ab6166d9c 100644 --- a/panda/src/tinydisplay/tinyTextureContext.h +++ b/panda/src/tinydisplay/tinyTextureContext.h @@ -18,21 +18,19 @@ #include "pandabase.h" #include "textureContext.h" #include "deletedChain.h" -#include "simpleLru.h" #include "zgl.h" //////////////////////////////////////////////////////////////////// // Class : TinyTextureContext // Description : //////////////////////////////////////////////////////////////////// -class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext, public SimpleLruPage { +class EXPCL_TINYDISPLAY TinyTextureContext : public TextureContext { public: INLINE TinyTextureContext(PreparedGraphicsObjects *pgo, Texture *tex); ALLOC_DELETED_CHAIN(TinyTextureContext); INLINE ~TinyTextureContext(); - INLINE void update_data_size_bytes(size_t new_data_size_bytes); virtual void evict_lru(); GLTexture _gltex;