graphics-memory-limit

This commit is contained in:
David Rose 2008-08-29 23:03:53 +00:00
parent d9b8296fc8
commit a8ec068c05
49 changed files with 691 additions and 265 deletions

View File

@ -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();
}
////////////////////////////////////////////////////////////////////

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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);

View File

@ -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();

View File

@ -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);

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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();
}

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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);
}
}

View File

@ -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;

View File

@ -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;

View File

@ -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);
}

View File

@ -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

View File

@ -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);
}

View File

@ -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

View File

@ -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 "

View File

@ -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;

View File

@ -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().

View File

@ -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);
}

View File

@ -48,5 +48,6 @@ evict_lru() {
nassertv(gltex->num_levels == 0);
}
set_resident(false);
update_data_size_bytes(0);
mark_unloaded();
}

View File

@ -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;