00001 /*************************************************************************** 00002 *cr 00003 *cr (C) Copyright 1995-2019 The Board of Trustees of the 00004 *cr University of Illinois 00005 *cr All Rights Reserved 00006 *cr 00007 ***************************************************************************/ 00008 /*************************************************************************** 00009 * RCS INFORMATION: 00010 * 00011 * $RCSfile: VMDDisplayList.C,v $ 00012 * $Author: johns $ $Locker: $ $State: Exp $ 00013 * $Revision: 1.42 $ $Date: 2020年12月12日 22:54:24 $ 00014 * 00015 ***************************************************************************/ 00022 #include "VMDDisplayList.h" 00023 #include "VMDApp.h" 00024 #include "Matrix4.h" 00025 #include "Inform.h" 00026 00027 // required word size alignment in bytes, 16 bytes is large enough for 00028 // all currently known systems. 00029 #define ALLOC_ALIGNMENT 16 00030 #define ALLOC_ALIGNMASK (ALLOC_ALIGNMENT - 1) 00031 00032 // Initial number of bytes in the display list memory block; not allocated 00033 // until the list receives its first command. 00034 00035 // Typical "empty" representations need about 64 bytes to hold their 00036 // initial material on, line thickness and resolution parameters. 00037 #define BASE_DISPLAYLIST_SIZE 64 00038 00039 // once the representation goes past being empty, it's likely going to need 00040 // a lot more space in subsequent allocations, so the next growth step is 00041 // much bigger to reduce the total number of calls without creating too much 00042 // memory fragmentation for simple representations. 00043 #define GROWN_DISPLAYLIST_SIZE 16384 00044 00045 void *VMDDisplayList::operator new(size_t n) { 00046 return vmd_alloc(n); 00047 } 00048 00049 void VMDDisplayList::operator delete(void *p, size_t) { 00050 vmd_dealloc(p); 00051 } 00052 00053 VMDDisplayList::VMDDisplayList() { 00054 materialtag = 0; 00055 serial=0; 00056 cacheskip=0; 00057 pbc = PBC_NONE; 00058 npbc = 1; 00059 instanceset = INSTANCE_ALL; 00060 instances.clear(); 00061 00062 // Begin with no memory allocated for the pool; many display lists, 00063 // like those for DrawMolecule, DrawForce, and MoleculeGraphics, spend 00064 // their whole lives with no commands, so it's wasteful to allocate 00065 // anything for them. 00066 // 00067 // XXX In fact, DrawForce and MoleculeGraphics are creating single-element 00068 // display lists that contain nothing but DMATERIALON. This should be 00069 // fixed; better might even be to not create these Displayables at all 00070 // until/unless they are needed. 00071 listsize = 0; 00072 poolsize = 0; 00073 poolused = 0; 00074 pool = NULL; 00075 } 00076 00077 VMDDisplayList::~VMDDisplayList() { 00078 if (pool) vmd_dealloc(pool); 00079 } 00080 00081 void *VMDDisplayList::append(int code, long size) { 00082 unsigned long neededBytes = (sizeof(CommandHeader) + size + ALLOC_ALIGNMASK) & ~(ALLOC_ALIGNMASK); 00083 if (neededBytes + poolused > poolsize) { 00084 unsigned long newsize; 00085 if (!pool) { 00086 newsize = (neededBytes < BASE_DISPLAYLIST_SIZE) ? 00087 BASE_DISPLAYLIST_SIZE : neededBytes; 00088 } else { 00089 newsize = (unsigned long) (1.2f * (poolsize + neededBytes)); 00090 if (newsize < GROWN_DISPLAYLIST_SIZE) 00091 newsize = GROWN_DISPLAYLIST_SIZE; 00092 } 00093 //printf("bumping displist size from %d to %d to handle %d from cmd %d\n", poolsize, newsize, size, code); 00094 char *tmp = (char *) vmd_resize_alloc(pool, poolused, newsize); 00095 // check for failed allocations 00096 if (!tmp) { 00097 msgErr << "Failed to increase display list memory pool size, system out of memory" << sendmsg; 00098 msgErr << " Previous pool size: " << ((unsigned long) (poolsize / (1024*1024))) << "MB" << sendmsg; 00099 msgErr << " Requested pool size: " << ((unsigned long) (newsize / (1024*1024))) << "MB" << sendmsg; 00100 return NULL; 00101 } 00102 poolsize = newsize; 00103 pool = tmp; 00104 } 00105 // store header and size of header + data into pool 00106 CommandHeader *header = (CommandHeader *)(pool + poolused); 00107 poolused += neededBytes; 00108 00109 header->code = code; 00110 header->size = neededBytes; 00111 00112 // return pointer to data following header 00113 ++listsize; 00114 return header+1; 00115 } 00116 00117 void VMDDisplayList::reset_and_free(unsigned long newserial) { 00118 // if we used less than 1/4 of the total pool size, trim the pool 00119 // back to empty so that we don't hog memory. 00120 if (poolsize > BASE_DISPLAYLIST_SIZE && 00121 poolused / (float)poolsize < 0.25f) { 00122 vmd_dealloc(pool); 00123 pool = NULL; 00124 poolsize = 0; 00125 } 00126 poolused = 0; 00127 listsize = 0; 00128 serial = newserial; 00129 } 00130 00131 int VMDDisplayList::set_clip_normal(int i, const float *normal) { 00132 if (i < 0 || i >= VMD_MAX_CLIP_PLANE) return 0; 00133 float length = norm(normal); 00134 if (!length) return 0; 00135 clipplanes[i].normal[0] = normal[0]/length; 00136 clipplanes[i].normal[1] = normal[1]/length; 00137 clipplanes[i].normal[2] = normal[2]/length; 00138 return 1; 00139 } 00140 00141 int VMDDisplayList::set_clip_center(int i, const float *center) { 00142 if (i < 0 || i >= VMD_MAX_CLIP_PLANE) return 0; 00143 clipplanes[i].center[0] = center[0]; 00144 clipplanes[i].center[1] = center[1]; 00145 clipplanes[i].center[2] = center[2]; 00146 return 1; 00147 } 00148 00149 int VMDDisplayList::set_clip_color(int i, const float *color) { 00150 if (i < 0 || i >= VMD_MAX_CLIP_PLANE) return 0; 00151 clipplanes[i].color[0] = color[0]; 00152 clipplanes[i].color[1] = color[1]; 00153 clipplanes[i].color[2] = color[2]; 00154 return 1; 00155 } 00156 00157 int VMDDisplayList::set_clip_status(int i, int mode) { 00158 if (i < 0 || i >= VMD_MAX_CLIP_PLANE) return 0; 00159 clipplanes[i].mode = mode; 00160 return 1; 00161 } 00162 00163 int VMDDisplayList::get_clip_status(int i, int &mode) { 00164 if (i < 0 || i >= VMD_MAX_CLIP_PLANE) return 0; 00165 mode = clipplanes[i].mode; 00166 return 1; 00167 } 00168