aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--engines/tinsel/dialogs.cpp13
-rw-r--r--engines/tinsel/handle.cpp36
-rw-r--r--engines/tinsel/heapmem.cpp59
-rw-r--r--engines/tinsel/heapmem.h5
-rw-r--r--engines/tinsel/tinsel.cpp2
5 files changed, 67 insertions, 48 deletions
diff --git a/engines/tinsel/dialogs.cpp b/engines/tinsel/dialogs.cpp
index c5686378c5..1b318e69c2 100644
--- a/engines/tinsel/dialogs.cpp
+++ b/engines/tinsel/dialogs.cpp
@@ -5526,7 +5526,10 @@ void RegisterIcons(void *cptr, int num) {
if (TinselV0) {
// In Tinsel 0, the INV_OBJECT structure doesn't have an attributes field, so we
// need to 'unpack' the source structures into the standard Tinsel v1/v2 format
- invObjects = (INV_OBJECT *)MemoryAllocFixed(numObjects * sizeof(INV_OBJECT));
+ MEM_NODE *node = MemoryAllocFixed(numObjects * sizeof(INV_OBJECT));
+ assert(node);
+ invObjects = (INV_OBJECT *)MemoryDeref(node);
+ assert(invObjects);
byte *srcP = (byte *)cptr;
INV_OBJECT *destP = (INV_OBJECT *)invObjects;
@@ -5537,12 +5540,14 @@ void RegisterIcons(void *cptr, int num) {
} else if (TinselV2) {
if (invFilms == NULL) {
// First time - allocate memory
- invFilms = (SCNHANDLE *)MemoryAllocFixed(numObjects * sizeof(SCNHANDLE));
+ MEM_NODE *node = MemoryAllocFixed(numObjects * sizeof(SCNHANDLE));
+ assert(node);
+ invFilms = (SCNHANDLE *)MemoryDeref(node);
+ if (invFilms == NULL)
+ error(NO_MEM, "inventory scripts");
memset(invFilms, 0, numObjects * sizeof(SCNHANDLE));
}
- if (invFilms == NULL)
- error(NO_MEM, "inventory scripts");
// Add defined permanent conversation icons
// and store all the films separately
diff --git a/engines/tinsel/handle.cpp b/engines/tinsel/handle.cpp
index 04b4b2fc60..b7e81dc4ca 100644
--- a/engines/tinsel/handle.cpp
+++ b/engines/tinsel/handle.cpp
@@ -51,7 +51,6 @@ struct MEMHANDLE {
char szName[12]; ///< file name of graphics file
int32 filesize; ///< file size and flags
MEM_NODE *_node; ///< memory node for the graphics
- uint8 *_ptr; ///< start of data for fixed blocks (i.e., preloaded data)
uint32 flags2;
};
@@ -129,7 +128,6 @@ void SetupHandleTable(void) {
// The pointer should always be NULL. We don't
// need to read that from the file.
handleTable[i]._node = NULL;
- handleTable[i]._ptr = NULL;
f.seek(4, SEEK_CUR);
// For Discworld 2, read in the flags2 field
handleTable[i].flags2 = t2Flag ? f.readUint32LE() : 0;
@@ -153,11 +151,10 @@ void SetupHandleTable(void) {
for (i = 0, pH = handleTable; i < numHandles; i++, pH++) {
if (pH->filesize & fPreload) {
// allocate a fixed memory node for permanent files
- pH->_ptr = (uint8 *)MemoryAllocFixed((pH->filesize & FSIZE_MASK));
- pH->_node = NULL;
+ pH->_node = MemoryAllocFixed((pH->filesize & FSIZE_MASK));
// make sure memory allocated
- assert(pH->_ptr);
+ assert(pH->_node);
// load the data
LoadFile(pH);
@@ -165,16 +162,14 @@ void SetupHandleTable(void) {
#ifdef BODGE
else if ((pH->filesize & FSIZE_MASK) == 8) {
pH->_node = NULL;
- pH->_ptr = NULL;
}
#endif
else {
// allocate a discarded memory node for other files
pH->_node = MemoryNoAlloc();
- pH->_ptr = NULL;
// make sure memory allocated
- assert(pH->_node || pH->_ptr);
+ assert(pH->_node);
}
}
}
@@ -297,13 +292,8 @@ void LoadFile(MEMHANDLE *pH) {
int bytes;
uint8 *addr;
- if (pH->filesize & fPreload)
- // preload - no need to lock the memory
- addr = pH->_ptr;
- else {
- // discardable - lock the memory
- addr = (uint8 *)MemoryLock(pH->_node);
- }
+ // lock the memory
+ addr = (uint8 *)MemoryLock(pH->_node);
// make sure address is valid
assert(addr);
@@ -313,10 +303,8 @@ void LoadFile(MEMHANDLE *pH) {
// close the file
f.close();
- if ((pH->filesize & fPreload) == 0) {
- // discardable - unlock the memory
- MemoryUnlock(pH->_node);
- }
+ // discardable - unlock the memory
+ MemoryUnlock(pH->_node);
// set the loaded flag
pH->filesize |= fLoaded;
@@ -347,8 +335,7 @@ byte *LockMem(SCNHANDLE offset) {
pH = handleTable + handle;
if (pH->filesize & fPreload) {
- // permanent files are already loaded
- return pH->_ptr + (offset & OFFSETMASK);
+ // permanent files are already loaded, nothing to be done
} else if (handle == cdPlayHandle) {
// Must be in currently loaded/loadable range
if (offset < cdBaseHandle || offset >= cdTopHandle)
@@ -365,8 +352,7 @@ byte *LockMem(SCNHANDLE offset) {
MemoryTouch(pH->_node);
}
- return MemoryDeref(pH->_node) + ((offset - cdBaseHandle) & OFFSETMASK);
-
+ offset -= cdBaseHandle;
} else {
// may have been discarded, make sure memory is allocated
MemoryReAlloc(pH->_node, pH->filesize & FSIZE_MASK);
@@ -382,9 +368,9 @@ byte *LockMem(SCNHANDLE offset) {
// make sure address is valid
assert(pH->filesize & fLoaded);
}
-
- return MemoryDeref(pH->_node) + (offset & OFFSETMASK);
}
+
+ return MemoryDeref(pH->_node) + (offset & OFFSETMASK);
}
/**
diff --git a/engines/tinsel/heapmem.cpp b/engines/tinsel/heapmem.cpp
index 5f32888f6e..31a8b97377 100644
--- a/engines/tinsel/heapmem.cpp
+++ b/engines/tinsel/heapmem.cpp
@@ -69,6 +69,9 @@ static int numNodes;
static int maxNodes;
#endif
+// list of all fixed memory nodes
+MEM_NODE s_fixedMnodesList[5];
+
// the mnode heap sentinel
static MEM_NODE heapSentinel;
@@ -79,7 +82,7 @@ static MEM_NODE *AllocMemNode(void);
/**
* Initialises the memory manager.
*/
-void MemoryInit(void) {
+void MemoryInit() {
MEM_NODE *pNode;
#ifdef DEBUG
@@ -98,6 +101,9 @@ void MemoryInit(void) {
// null the last mnode
mnodeList[NUM_MNODES - 1].pNext = NULL;
+ // clear list of fixed memory nodes
+ memset(s_fixedMnodesList, 0, sizeof(s_fixedMnodesList));
+
// allocates a big chunk of memory
uint32 size = MemoryPoolSize[0];
if (TinselVersion == TINSEL_V1) size = MemoryPoolSize[1];
@@ -128,9 +134,27 @@ void MemoryInit(void) {
// flag sentinel as locked
heapSentinel.flags = DWM_LOCKED | DWM_SENTINEL;
+
+ // store the start of the master data block in the sentinel
+ heapSentinel.pBaseAddr = mem;
}
/**
+ * Deinitialises the memory manager.
+ */
+void MemoryDeinit() {
+ MEM_NODE *pNode = s_fixedMnodesList;
+ for (int i = 0; i < ARRAYSIZE(s_fixedMnodesList); ++i, ++pNode) {
+ free(pNode->pBaseAddr);
+ pNode->pBaseAddr = 0;
+ }
+
+ // free memory used for the memory pool
+ free(heapSentinel.pBaseAddr);
+}
+
+
+/**
* Allocate a mnode from the free list.
*/
static MEM_NODE *AllocMemNode(void) {
@@ -362,18 +386,31 @@ MEM_NODE *MemoryNoAlloc() {
/**
* Allocate a fixed block of data.
- * @note For now, we simply malloc it!
- * @todo We really should keep a list of the allocated pointers,
+ * @todo We really should keep track of the allocated pointers,
* so that we can discard them later on, when the engine quits.
*/
-void *MemoryAllocFixed(long size) {
+MEM_NODE *MemoryAllocFixed(long size) {
#ifdef SCUMM_NEED_ALIGNMENT
const int alignPadding = sizeof(void*) - 1;
size = (size + alignPadding) & ~alignPadding; //round up to nearest multiple of sizeof(void*), this ensures the addresses that are returned are alignment-safe.
#endif
- return malloc(size);
+ // Search for a free entry in s_fixedMnodesList
+ MEM_NODE *pNode = s_fixedMnodesList;
+ for (int i = 0; i < ARRAYSIZE(s_fixedMnodesList); ++i, ++pNode) {
+ if (!pNode->pBaseAddr) {
+ pNode->pNext = 0;
+ pNode->pPrev = 0;
+ pNode->pBaseAddr = (byte *)malloc(size);
+ pNode->size = size;
+ pNode->lruTime = DwGetCurrentTime();
+ pNode->flags = DWM_USED;
+ return pNode;
+ }
+ }
+
+ return 0;
}
@@ -429,9 +466,6 @@ void MemoryDiscard(MEM_NODE *pMemNode) {
* @param pMemNode Node of the memory object
*/
void *MemoryLock(MEM_NODE *pMemNode) {
- // validate mnode pointer
- assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1);
-
// make sure memory object is not already locked
assert((pMemNode->flags & DWM_LOCKED) == 0);
@@ -497,9 +531,6 @@ void MemoryReAlloc(MEM_NODE *pMemNode, long size) {
* @param pMemNode Node of the memory object
*/
void MemoryUnlock(MEM_NODE *pMemNode) {
- // validate mnode pointer
- assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1);
-
// make sure memory object is already locked
assert(pMemNode->flags & DWM_LOCKED);
@@ -515,17 +546,11 @@ void MemoryUnlock(MEM_NODE *pMemNode) {
* @param pMemNode Node of the memory object
*/
void MemoryTouch(MEM_NODE *pMemNode) {
- // validate mnode pointer
- assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1);
-
// update the LRU time
pMemNode->lruTime = DwGetCurrentTime();
}
uint8 *MemoryDeref(MEM_NODE *pMemNode) {
- // validate mnode pointer
- assert(pMemNode >= mnodeList && pMemNode <= mnodeList + NUM_MNODES - 1);
-
return pMemNode->pBaseAddr;
}
diff --git a/engines/tinsel/heapmem.h b/engines/tinsel/heapmem.h
index 86c7c456c0..5fa84dca4f 100644
--- a/engines/tinsel/heapmem.h
+++ b/engines/tinsel/heapmem.h
@@ -38,13 +38,14 @@ struct MEM_NODE;
|* Memory Function Prototypes *|
\*----------------------------------------------------------------------*/
-void MemoryInit(void); // initialises the memory manager
+void MemoryInit(); // initialises the memory manager
+void MemoryDeinit(); // deinitialises the memory manager
// reserves a memory node for a movable & discardable block
MEM_NODE *MemoryNoAlloc();
// allocates a fixed block with the specified number of bytes
-void *MemoryAllocFixed(long size);
+MEM_NODE *MemoryAllocFixed(long size);
void MemoryDiscard( // discards the specified memory object
MEM_NODE *pMemNode); // node of the memory object
diff --git a/engines/tinsel/tinsel.cpp b/engines/tinsel/tinsel.cpp
index 320eb495d5..6b71b0c245 100644
--- a/engines/tinsel/tinsel.cpp
+++ b/engines/tinsel/tinsel.cpp
@@ -893,6 +893,8 @@ TinselEngine::~TinselEngine() {
FreeGlobalProcesses();
FreeGlobals();
delete _scheduler;
+
+ MemoryDeinit();
}
void TinselEngine::syncSoundSettings() {