//************************************************************************** //** //** ## ## ## ## ## #### #### ### ### //** ## ## ## ## ## ## ## ## ## ## #### #### //** ## ## ## ## ## ## ## ## ## ## ## ## ## ## //** ## ## ######## ## ## ## ## ## ## ## ### ## //** ### ## ## ### ## ## ## ## ## ## //** # ## ## # #### #### ## ## //** //** $Id: d_scache.cpp 1802 2006-10-21 14:38:57Z dj_jl $ //** //** Copyright (C) 1999-2006 Jānis Legzdiņš //** //** This program is free software; you can redistribute it and/or //** modify it under the terms of the GNU General Public License //** as published by the Free Software Foundation; either version 2 //** of the License, or (at your option) any later version. //** //** This program is distributed in the hope that it will be useful, //** but WITHOUT ANY WARRANTY; without even the implied warranty of //** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //** GNU General Public License for more details. //** //************************************************************************** //** //** rasterization driver surface heap manager //** //************************************************************************** // HEADER FILES ------------------------------------------------------------ #include "d_local.h" // MACROS ------------------------------------------------------------------ #define SURFCACHE_SIZE_AT_320X200 600*1024 #define GUARDSIZE 4 // TYPES ------------------------------------------------------------------- // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- // PUBLIC FUNCTION PROTOTYPES ---------------------------------------------- // PRIVATE FUNCTION PROTOTYPES --------------------------------------------- // EXTERNAL DATA DECLARATIONS ---------------------------------------------- // PUBLIC DATA DEFINITIONS ------------------------------------------------- bool d_roverwrapped; surfcache_t *d_initial_rover; bool r_cache_thrash; // set if surface cache is thrashing // PRIVATE DATA DEFINITIONS ------------------------------------------------ int sc_size; surfcache_t *sc_rover, *sc_base; // CODE -------------------------------------------------------------------- //========================================================================== // // VSoftwareDrawer::SurfaceCacheForRes // //========================================================================== int VSoftwareDrawer::SurfaceCacheForRes(int width, int height, int bpp) { guard(VSoftwareDrawer::SurfaceCacheForRes); int size, pix, pixbytes; const char* p = GArgs.CheckValue("-surfcachesize"); if (p) { size = atoi(p) * 1024; return size; } size = SURFCACHE_SIZE_AT_320X200; pixbytes = (bpp + 7) / 8; pix = width * height * pixbytes; if (pix > 64000) size += (pix - 64000) * 3; return size; unguard; } //========================================================================== // // VSoftwareDrawer::CheckCacheGuard // //========================================================================== void VSoftwareDrawer::CheckCacheGuard(void) { guard(VSoftwareDrawer::CheckCacheGuard); byte *s; int i; s = (byte *)sc_base + sc_size; for (i = 0; i < GUARDSIZE; i++) if (s[i] != (byte)i) Sys_Error("D_CheckCacheGuard: failed"); unguard; } //========================================================================== // // VSoftwareDrawer::ClearCacheGuard // //========================================================================== void VSoftwareDrawer::ClearCacheGuard(void) { guard(VSoftwareDrawer::ClearCacheGuard); byte *s; int i; s = (byte *)sc_base + sc_size; for (i = 0; i < GUARDSIZE; i++) s[i] = (byte)i; unguard; } //========================================================================== // // VSoftwareDrawer::InitCaches // //========================================================================== void VSoftwareDrawer::InitCaches(void *buffer, int size) { guard(VSoftwareDrawer::InitCaches); // if (!msg_suppress_1) GCon->Logf(NAME_Init, "%dk surface cache", size / 1024); sc_size = size - GUARDSIZE; sc_base = (surfcache_t *)buffer; sc_rover = sc_base; sc_base->next = NULL; sc_base->owner = NULL; sc_base->size = sc_size; ClearCacheGuard(); unguard; } //========================================================================== // // VSoftwareDrawer::FlushCaches // //========================================================================== void VSoftwareDrawer::FlushCaches(bool free_blocks) { guard(VSoftwareDrawer::FlushCaches); surfcache_t *c; if (!sc_base) return; if (free_blocks) { for (c = sc_base; c; c = c->next) { if (c->owner) *c->owner = NULL; } } sc_rover = sc_base; sc_base->next = NULL; sc_base->owner = NULL; sc_base->size = sc_size; unguard; } //========================================================================== // // VSoftwareDrawer::SCAlloc // //========================================================================== surfcache_t *VSoftwareDrawer::SCAlloc(int width, int height) { guard(VSoftwareDrawer::SCAlloc); surfcache_t *newb; bool wrapped_this_time; int size = width * height * PixelBytes; if ((width < 0) || (width > 256)) Sys_Error("D_SCAlloc: bad cache width %d\n", width); if ((height < 0) || (height > 256)) Sys_Error("D_SCAlloc: bad cache height %d\n", height); size = &((surfcache_t *)0)->data[size] - (vuint8*)0; size = (size + 3) & ~3; if (size > sc_size) Sys_Error("D_SCAlloc: %i > cache size", size); // if there is not size bytes after the rover, reset to the start wrapped_this_time = false; if (!sc_rover || (byte *)sc_rover - (byte *)sc_base > sc_size - size) { if (sc_rover) { wrapped_this_time = true; } sc_rover = sc_base; } // colect and free surfcache_t blocks until the rover block is large enough newb = sc_rover; if (sc_rover->owner) *sc_rover->owner = NULL; while (newb->size < size) { // free another sc_rover = sc_rover->next; if (!sc_rover) Sys_Error("D_SCAlloc: hit the end of memory"); if (sc_rover->owner) *sc_rover->owner = NULL; newb->size += sc_rover->size; newb->next = sc_rover->next; } // create a fragment out of any leftovers if (newb->size - size > 256) { sc_rover = (surfcache_t *)( (byte *)newb + size); sc_rover->size = newb->size - size; sc_rover->next = newb->next; sc_rover->width = 0; sc_rover->owner = NULL; newb->next = sc_rover; newb->size = size; } else sc_rover = newb->next; newb->width = width; // DEBUG newb->height = height; newb->owner = NULL; // should be set properly after return if (d_roverwrapped) { if (wrapped_this_time || (sc_rover >= d_initial_rover)) r_cache_thrash = true; } else if (wrapped_this_time) { d_roverwrapped = true; } CheckCacheGuard(); // DEBUG return newb; unguard; } //========================================================================== // // VSoftwareDrawer::FreeSurfCache // //========================================================================== void VSoftwareDrawer::FreeSurfCache(surfcache_t* cache) { guard(VSoftwareDrawer::FreeSurfCache); *cache->owner = NULL; cache->owner = NULL; unguard; } //========================================================================== // // VSoftwareDrawer::SCDump // //========================================================================== void VSoftwareDrawer::SCDump(FOutputDevice& Ar) { guard(VSoftwareDrawer::SCDump); for (surfcache_t* test = sc_base ; test ; test = test->next) { if (test == sc_rover) Ar.Log("ROVER:"); Ar.Logf("%p : %i bytes %i width",test, test->size, test->width); } unguard; } //========================================================================== // // VSoftwareDrawer::SCInvalidateTexture // //========================================================================== void VSoftwareDrawer::SCInvalidateTexture(int TexNum) { guard(VSoftwareDrawer::SCInvalidateTexture); for (surfcache_t* c = sc_base; c; c = c->next) { if (c->texture == TexNum) c->texture = -1; } unguard; }