mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
chunk-a-time vertex compression
This commit is contained in:
parent
6ae6a86eba
commit
6d25ba7710
@ -19,6 +19,18 @@
|
|||||||
#include "pnotify.h"
|
#include "pnotify.h"
|
||||||
#include "config_express.h"
|
#include "config_express.h"
|
||||||
|
|
||||||
|
#if !defined(USE_MEMORY_NOWRAPPERS)
|
||||||
|
// Define functions that hook zlib into panda's memory allocation system.
|
||||||
|
static void *
|
||||||
|
do_zlib_alloc(voidpf opaque, uInt items, uInt size) {
|
||||||
|
return PANDA_MALLOC_ARRAY(items * size);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
do_zlib_free(voidpf opaque, voidpf address) {
|
||||||
|
PANDA_FREE_ARRAY(address);
|
||||||
|
}
|
||||||
|
#endif !USE_MEMORY_NOWRAPPERS
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: ZStreamBuf::Constructor
|
// Function: ZStreamBuf::Constructor
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -70,8 +82,13 @@ open_read(istream *source, bool owns_source) {
|
|||||||
|
|
||||||
_z_source.next_in = Z_NULL;
|
_z_source.next_in = Z_NULL;
|
||||||
_z_source.avail_in = 0;
|
_z_source.avail_in = 0;
|
||||||
|
#ifdef USE_MEMORY_NOWRAPPERS
|
||||||
_z_source.zalloc = Z_NULL;
|
_z_source.zalloc = Z_NULL;
|
||||||
_z_source.zfree = Z_NULL;
|
_z_source.zfree = Z_NULL;
|
||||||
|
#else
|
||||||
|
_z_source.zalloc = (alloc_func)&do_zlib_alloc;
|
||||||
|
_z_source.zfree = (free_func)&do_zlib_free;
|
||||||
|
#endif
|
||||||
_z_source.opaque = Z_NULL;
|
_z_source.opaque = Z_NULL;
|
||||||
_z_source.msg = "no error message";
|
_z_source.msg = "no error message";
|
||||||
|
|
||||||
@ -116,8 +133,13 @@ open_write(ostream *dest, bool owns_dest, int compression_level) {
|
|||||||
_dest = dest;
|
_dest = dest;
|
||||||
_owns_dest = owns_dest;
|
_owns_dest = owns_dest;
|
||||||
|
|
||||||
|
#ifdef USE_MEMORY_NOWRAPPERS
|
||||||
_z_dest.zalloc = Z_NULL;
|
_z_dest.zalloc = Z_NULL;
|
||||||
_z_dest.zfree = Z_NULL;
|
_z_dest.zfree = Z_NULL;
|
||||||
|
#else
|
||||||
|
_z_dest.zalloc = (alloc_func)&do_zlib_alloc;
|
||||||
|
_z_dest.zfree = (free_func)&do_zlib_free;
|
||||||
|
#endif
|
||||||
_z_dest.opaque = Z_NULL;
|
_z_dest.opaque = Z_NULL;
|
||||||
_z_dest.msg = "no error message";
|
_z_dest.msg = "no error message";
|
||||||
|
|
||||||
|
@ -80,6 +80,20 @@ PStatCollector VertexDataPage::_thread_wait_pcollector("Wait:Idle");
|
|||||||
PStatCollector VertexDataPage::_alloc_pages_pcollector("System memory:MMap:Vertex data");
|
PStatCollector VertexDataPage::_alloc_pages_pcollector("System memory:MMap:Vertex data");
|
||||||
|
|
||||||
TypeHandle VertexDataPage::_type_handle;
|
TypeHandle VertexDataPage::_type_handle;
|
||||||
|
TypeHandle VertexDataPage::DeflatePage::_type_handle;
|
||||||
|
|
||||||
|
#if defined(HAVE_ZLIB) && !defined(USE_MEMORY_NOWRAPPERS)
|
||||||
|
// Define functions that hook zlib into panda's memory allocation system.
|
||||||
|
static void *
|
||||||
|
do_zlib_alloc(voidpf opaque, uInt items, uInt size) {
|
||||||
|
return PANDA_MALLOC_ARRAY(items * size);
|
||||||
|
}
|
||||||
|
static void
|
||||||
|
do_zlib_free(voidpf opaque, voidpf address) {
|
||||||
|
PANDA_FREE_ARRAY(address);
|
||||||
|
}
|
||||||
|
#endif // HAVE_ZLIB && !USE_MEMORY_NOWRAPPERS
|
||||||
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: VertexDataPage::Book Constructor
|
// Function: VertexDataPage::Book Constructor
|
||||||
@ -356,6 +370,7 @@ make_resident() {
|
|||||||
gobj_cat.error()
|
gobj_cat.error()
|
||||||
<< "Couldn't expand: zlib error " << result << "\n";
|
<< "Couldn't expand: zlib error " << result << "\n";
|
||||||
nassert_raise("zlib error");
|
nassert_raise("zlib error");
|
||||||
|
memset(new_data, 0, new_allocated_size);
|
||||||
}
|
}
|
||||||
nassertv(dest_len == _uncompressed_size);
|
nassertv(dest_len == _uncompressed_size);
|
||||||
|
|
||||||
@ -396,28 +411,96 @@ make_compressed() {
|
|||||||
#ifdef HAVE_ZLIB
|
#ifdef HAVE_ZLIB
|
||||||
PStatTimer timer(_vdata_compress_pcollector);
|
PStatTimer timer(_vdata_compress_pcollector);
|
||||||
|
|
||||||
// According to the zlib manual, we need to provide this much
|
DeflatePage *page = new DeflatePage;
|
||||||
// buffer to the compress algorithm: 0.1% bigger plus twelve
|
DeflatePage *head = page;
|
||||||
// bytes.
|
|
||||||
uLongf buffer_size = _uncompressed_size + ((_uncompressed_size + 999) / 1000) + 12;
|
|
||||||
Bytef *buffer = (Bytef *)alloca(buffer_size);
|
|
||||||
|
|
||||||
int result = compress2(buffer, &buffer_size,
|
z_stream z_dest;
|
||||||
_page_data, _uncompressed_size,
|
#ifdef USE_MEMORY_NOWRAPPERS
|
||||||
vertex_data_compression_level);
|
z_dest.zalloc = Z_NULL;
|
||||||
if (result != Z_OK) {
|
z_dest.zfree = Z_NULL;
|
||||||
gobj_cat.error()
|
#else
|
||||||
<< "Couldn't compress: zlib error " << result << "\n";
|
z_dest.zalloc = (alloc_func)&do_zlib_alloc;
|
||||||
|
z_dest.zfree = (free_func)&do_zlib_free;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
z_dest.opaque = Z_NULL;
|
||||||
|
z_dest.msg = "no error message";
|
||||||
|
|
||||||
|
int result = deflateInit(&z_dest, vertex_data_compression_level);
|
||||||
|
if (result < 0) {
|
||||||
nassert_raise("zlib error");
|
nassert_raise("zlib error");
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
Thread::consider_yield();
|
||||||
|
|
||||||
size_t new_allocated_size = round_up(buffer_size);
|
z_dest.next_in = (Bytef *)(char *)_page_data;
|
||||||
|
z_dest.avail_in = _uncompressed_size;
|
||||||
|
size_t output_size = 0;
|
||||||
|
|
||||||
|
// Compress the data into one or more individual pages. We have
|
||||||
|
// to compress it page-at-a-time, since we're not really sure how
|
||||||
|
// big the result will be (so we can't easily pre-allocate a
|
||||||
|
// buffer).
|
||||||
|
int flush = 0;
|
||||||
|
result = 0;
|
||||||
|
while (result != Z_STREAM_END) {
|
||||||
|
unsigned char *start_out = (page->_buffer + page->_used_size);
|
||||||
|
z_dest.next_out = (Bytef *)start_out;
|
||||||
|
z_dest.avail_out = (size_t)deflate_page_size - page->_used_size;
|
||||||
|
if (z_dest.avail_out == 0) {
|
||||||
|
DeflatePage *new_page = new DeflatePage;
|
||||||
|
page->_next = new_page;
|
||||||
|
page = new_page;
|
||||||
|
start_out = page->_buffer;
|
||||||
|
z_dest.next_out = (Bytef *)start_out;
|
||||||
|
z_dest.avail_out = deflate_page_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
result = deflate(&z_dest, flush);
|
||||||
|
if (result < 0 && result != Z_BUF_ERROR) {
|
||||||
|
nassert_raise("zlib error");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
size_t bytes_produced = (size_t)((unsigned char *)z_dest.next_out - start_out);
|
||||||
|
page->_used_size += bytes_produced;
|
||||||
|
nassertv(page->_used_size <= deflate_page_size);
|
||||||
|
output_size += bytes_produced;
|
||||||
|
if (bytes_produced == 0) {
|
||||||
|
// If we ever produce no bytes, then start flushing the output.
|
||||||
|
flush = Z_FINISH;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::consider_yield();
|
||||||
|
}
|
||||||
|
nassertv(z_dest.avail_in == 0);
|
||||||
|
|
||||||
|
result = deflateEnd(&z_dest);
|
||||||
|
nassertv(result == Z_OK);
|
||||||
|
|
||||||
|
// Now we know how big the result will be. Allocate a buffer, and
|
||||||
|
// copy the data from the various pages.
|
||||||
|
|
||||||
|
size_t new_allocated_size = round_up(output_size);
|
||||||
unsigned char *new_data = alloc_page_data(new_allocated_size);
|
unsigned char *new_data = alloc_page_data(new_allocated_size);
|
||||||
memcpy(new_data, buffer, buffer_size);
|
|
||||||
|
|
||||||
|
size_t copied_size = 0;
|
||||||
|
unsigned char *p = new_data;
|
||||||
|
page = head;
|
||||||
|
while (page != NULL) {
|
||||||
|
memcpy(p, page->_buffer, page->_used_size);
|
||||||
|
copied_size += page->_used_size;
|
||||||
|
p += page->_used_size;
|
||||||
|
DeflatePage *next = page->_next;
|
||||||
|
delete page;
|
||||||
|
page = next;
|
||||||
|
}
|
||||||
|
nassertv(copied_size == output_size);
|
||||||
|
|
||||||
|
// Now free the original, uncompressed data, and put this new
|
||||||
|
// compressed buffer in its place.
|
||||||
free_page_data(_page_data, _allocated_size);
|
free_page_data(_page_data, _allocated_size);
|
||||||
_page_data = new_data;
|
_page_data = new_data;
|
||||||
_size = buffer_size;
|
_size = output_size;
|
||||||
_allocated_size = new_allocated_size;
|
_allocated_size = new_allocated_size;
|
||||||
|
|
||||||
if (gobj_cat.is_debug()) {
|
if (gobj_cat.is_debug()) {
|
||||||
|
@ -165,11 +165,38 @@ private:
|
|||||||
size_t _block_size;
|
size_t _block_size;
|
||||||
|
|
||||||
//Mutex _lock; // Inherited from SimpleAllocator. Protects above members.
|
//Mutex _lock; // Inherited from SimpleAllocator. Protects above members.
|
||||||
|
|
||||||
RamClass _pending_ram_class; // Protected by _tlock.
|
RamClass _pending_ram_class; // Protected by _tlock.
|
||||||
|
|
||||||
VertexDataBook *_book; // never changes.
|
VertexDataBook *_book; // never changes.
|
||||||
|
|
||||||
|
enum { deflate_page_size = 1024 };
|
||||||
|
|
||||||
|
// We build up a temporary linked list of these while deflating
|
||||||
|
// (compressing) the vertex data in-memory.
|
||||||
|
class DeflatePage {
|
||||||
|
public:
|
||||||
|
DeflatePage() {
|
||||||
|
_used_size = 0;
|
||||||
|
_next = NULL;
|
||||||
|
}
|
||||||
|
ALLOC_DELETED_CHAIN(DeflatePage);
|
||||||
|
|
||||||
|
unsigned char _buffer[deflate_page_size];
|
||||||
|
size_t _used_size;
|
||||||
|
DeflatePage *_next;
|
||||||
|
|
||||||
|
public:
|
||||||
|
static TypeHandle get_class_type() {
|
||||||
|
return _type_handle;
|
||||||
|
}
|
||||||
|
static void init_type() {
|
||||||
|
register_type(_type_handle, "VertexDataPage::DeflatePage");
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static TypeHandle _type_handle;
|
||||||
|
};
|
||||||
|
|
||||||
static SimpleLru _resident_lru;
|
static SimpleLru _resident_lru;
|
||||||
static SimpleLru _compressed_lru;
|
static SimpleLru _compressed_lru;
|
||||||
static SimpleLru _disk_lru;
|
static SimpleLru _disk_lru;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user