1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282 |
- Unit JMemMgr;
- { This file contains the JPEG system-independent memory management
- routines. This code is usable across a wide variety of machines; most
- of the system dependencies have been isolated in a separate file.
- The major functions provided here are:
- * pool-based allocation and freeing of memory;
- * policy decisions about how to divide available memory among the
- virtual arrays;
- * control logic for swapping virtual arrays between main memory and
- backing storage.
- The separate system-dependent file provides the actual backing-storage
- access code, and it contains the policy decision about how much total
- main memory to use.
- This file is system-dependent in the sense that some of its functions
- are unnecessary in some systems. For example, if there is enough virtual
- memory so that backing storage will never be used, much of the virtual
- array control logic could be removed. (Of course, if you have that much
- memory then you shouldn't care about a little bit of unused code...) }
- { Original : jmemmgr.c ; Copyright (C) 1991-1997, Thomas G. Lane. }
- interface
- {$I jconfig.inc}
- uses
- jmorecfg,
- jinclude,
- jdeferr,
- jerror,
- jpeglib,
- jutils,
- {$IFDEF VER70}
- {$ifndef NO_GETENV}
- Dos, { DOS unit should declare getenv() }
- { function GetEnv(name : string) : string; }
- {$endif}
- jmemdos; { import the system-dependent declarations }
- {$ELSE}
- jmemnobs;
- {$DEFINE NO_GETENV}
- {$ENDIF}
- { Memory manager initialization.
- When this is called, only the error manager pointer is valid in cinfo! }
- {GLOBAL}
- procedure jinit_memory_mgr (cinfo : j_common_ptr);
- implementation
- { Some important notes:
- The allocation routines provided here must never return NIL.
- They should exit to error_exit if unsuccessful.
- It's not a good idea to try to merge the sarray and barray routines,
- even though they are textually almost the same, because samples are
- usually stored as bytes while coefficients are shorts or ints. Thus,
- in machines where byte pointers have a different representation from
- word pointers, the resulting machine code could not be the same. }
- { Many machines require storage alignment: longs must start on 4-byte
- boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc()
- always returns pointers that are multiples of the worst-case alignment
- requirement, and we had better do so too.
- There isn't any really portable way to determine the worst-case alignment
- requirement. This module assumes that the alignment requirement is
- multiples of sizeof(ALIGN_TYPE).
- By default, we define ALIGN_TYPE as double. This is necessary on some
- workstations (where doubles really do need 8-byte alignment) and will work
- fine on nearly everything. If your machine has lesser alignment needs,
- you can save a few bytes by making ALIGN_TYPE smaller.
- The only place I know of where this will NOT work is certain Macintosh
- 680x0 compilers that define double as a 10-byte IEEE extended float.
- Doing 10-byte alignment is counterproductive because longwords won't be
- aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have
- such a compiler. }
- {$ifndef ALIGN_TYPE} { so can override from jconfig.h }
- type
- ALIGN_TYPE = double;
- {$endif}
- { We allocate objects from "pools", where each pool is gotten with a single
- request to jpeg_get_small() or jpeg_get_large(). There is no per-object
- overhead within a pool, except for alignment padding. Each pool has a
- header with a link to the next pool of the same class.
- Small and large pool headers are identical except that the latter's
- link pointer must be FAR on 80x86 machines.
- Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE
- field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple
- of the alignment requirement of ALIGN_TYPE. }
- type
- small_pool_ptr = ^small_pool_hdr;
- small_pool_hdr = record
- case byte of
- 0:(hdr : record
- next : small_pool_ptr; { next in list of pools }
- bytes_used : size_t; { how many bytes already used within pool }
- bytes_left : size_t; { bytes still available in this pool }
- end);
- 1:(dummy : ALIGN_TYPE); { included in union to ensure alignment }
- end; {small_pool_hdr;}
- type
- large_pool_ptr = ^large_pool_hdr; {FAR}
- large_pool_hdr = record
- case byte of
- 0:(hdr : record
- next : large_pool_ptr; { next in list of pools }
- bytes_used : size_t; { how many bytes already used within pool }
- bytes_left : size_t; { bytes still available in this pool }
- end);
- 1:(dummy : ALIGN_TYPE); { included in union to ensure alignment }
- end; {large_pool_hdr;}
- { Here is the full definition of a memory manager object. }
- type
- my_mem_ptr = ^my_memory_mgr;
- my_memory_mgr = record
- pub : jpeg_memory_mgr; { public fields }
- { Each pool identifier (lifetime class) names a linked list of pools. }
- small_list : array[0..JPOOL_NUMPOOLS-1] of small_pool_ptr ;
- large_list : array[0..JPOOL_NUMPOOLS-1] of large_pool_ptr ;
- { Since we only have one lifetime class of virtual arrays, only one
- linked list is necessary (for each datatype). Note that the virtual
- array control blocks being linked together are actually stored somewhere
- in the small-pool list. }
- virt_sarray_list : jvirt_sarray_ptr;
- virt_barray_list : jvirt_barray_ptr;
- { This counts total space obtained from jpeg_get_small/large }
- total_space_allocated : long;
- { alloc_sarray and alloc_barray set this value for use by virtual
- array routines. }
- last_rowsperchunk : JDIMENSION; { from most recent alloc_sarray/barray }
- end; {my_memory_mgr;}
- {$ifndef AM_MEMORY_MANAGER} { only jmemmgr.c defines these }
- { The control blocks for virtual arrays.
- Note that these blocks are allocated in the "small" pool area.
- System-dependent info for the associated backing store (if any) is hidden
- inside the backing_store_info struct. }
- type
- jvirt_sarray_control = record
- mem_buffer : JSAMPARRAY; { => the in-memory buffer }
- rows_in_array : JDIMENSION; { total virtual array height }
- samplesperrow : JDIMENSION; { width of array (and of memory buffer) }
- maxaccess : JDIMENSION; { max rows accessed by access_virt_sarray }
- rows_in_mem : JDIMENSION; { height of memory buffer }
- rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer }
- cur_start_row : JDIMENSION; { first logical row # in the buffer }
- first_undef_row : JDIMENSION; { row # of first uninitialized row }
- pre_zero : boolean; { pre-zero mode requested? }
- dirty : boolean; { do current buffer contents need written? }
- b_s_open : boolean; { is backing-store data valid? }
- next : jvirt_sarray_ptr; { link to next virtual sarray control block }
- b_s_info : backing_store_info; { System-dependent control info }
- end;
- jvirt_barray_control = record
- mem_buffer : JBLOCKARRAY; { => the in-memory buffer }
- rows_in_array : JDIMENSION; { total virtual array height }
- blocksperrow : JDIMENSION; { width of array (and of memory buffer) }
- maxaccess : JDIMENSION; { max rows accessed by access_virt_barray }
- rows_in_mem : JDIMENSION; { height of memory buffer }
- rowsperchunk : JDIMENSION; { allocation chunk size in mem_buffer }
- cur_start_row : JDIMENSION; { first logical row # in the buffer }
- first_undef_row : JDIMENSION; { row # of first uninitialized row }
- pre_zero : boolean; { pre-zero mode requested? }
- dirty : boolean; { do current buffer contents need written? }
- b_s_open : boolean; { is backing-store data valid? }
- next : jvirt_barray_ptr; { link to next virtual barray control block }
- b_s_info : backing_store_info; { System-dependent control info }
- end;
- {$endif} { AM_MEMORY_MANAGER}
- {$ifdef MEM_STATS} { optional extra stuff for statistics }
- {LOCAL}
- procedure print_mem_stats (cinfo : j_common_ptr; pool_id : int);
- var
- mem : my_mem_ptr;
- shdr_ptr : small_pool_ptr;
- lhdr_ptr : large_pool_ptr;
- begin
- mem := my_mem_ptr (cinfo^.mem);
- { Since this is only a debugging stub, we can cheat a little by using
- fprintf directly rather than going through the trace message code.
- This is helpful because message parm array can't handle longs. }
- WriteLn(output, 'Freeing pool ', pool_id,', total space := ',
- mem^.total_space_allocated);
- lhdr_ptr := mem^.large_list[pool_id];
- while (lhdr_ptr <> NIL) do
- begin
- WriteLn(output, ' Large chunk used ',
- long (lhdr_ptr^.hdr.bytes_used));
- lhdr_ptr := lhdr_ptr^.hdr.next;
- end;
- shdr_ptr := mem^.small_list[pool_id];
- while (shdr_ptr <> NIL) do
- begin
- WriteLn(output, ' Small chunk used ',
- long (shdr_ptr^.hdr.bytes_used), ' free ',
- long (shdr_ptr^.hdr.bytes_left) );
- shdr_ptr := shdr_ptr^.hdr.next;
- end;
- end;
- {$endif} { MEM_STATS }
- {LOCAL}
- procedure out_of_memory (cinfo : j_common_ptr; which : int);
- { Report an out-of-memory error and stop execution }
- { If we compiled MEM_STATS support, report alloc requests before dying }
- begin
- {$ifdef MEM_STATS}
- cinfo^.err^.trace_level := 2; { force self_destruct to report stats }
- {$endif}
- ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which);
- end;
- { Allocation of "small" objects.
- For these, we use pooled storage. When a new pool must be created,
- we try to get enough space for the current request plus a "slop" factor,
- where the slop will be the amount of leftover space in the new pool.
- The speed vs. space tradeoff is largely determined by the slop values.
- A different slop value is provided for each pool class (lifetime),
- and we also distinguish the first pool of a class from later ones.
- NOTE: the values given work fairly well on both 16- and 32-bit-int
- machines, but may be too small if longs are 64 bits or more. }
- const
- first_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t =
- (1600, { first PERMANENT pool }
- 16000); { first IMAGE pool }
- const
- extra_pool_slop : array[0..JPOOL_NUMPOOLS-1] of size_t =
- (0, { additional PERMANENT pools }
- 5000); { additional IMAGE pools }
- const
- MIN_SLOP = 50; { greater than 0 to avoid futile looping }
- {METHODDEF}
- function alloc_small (cinfo : j_common_ptr;
- pool_id : int;
- sizeofobject : size_t) : pointer; far;
- type
- byteptr = ^byte;
- { Allocate a "small" object }
- var
- mem : my_mem_ptr;
- hdr_ptr, prev_hdr_ptr : small_pool_ptr;
- data_ptr : byteptr;
- odd_bytes, min_request, slop : size_t;
- begin
- mem := my_mem_ptr (cinfo^.mem);
- { Check for unsatisfiable request (do now to ensure no overflow below) }
- if (sizeofobject > size_t(MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) then
- out_of_memory(cinfo, 1); { request exceeds malloc's ability }
- { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) }
- odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE);
- if (odd_bytes > 0) then
- Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes);
- { See if space is available in any existing pool }
- if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
- ERREXIT1(j_common_ptr(cinfo), JERR_BAD_POOL_ID, pool_id); { safety check }
- prev_hdr_ptr := NIL;
- hdr_ptr := mem^.small_list[pool_id];
- while (hdr_ptr <> NIL) do
- begin
- if (hdr_ptr^.hdr.bytes_left >= sizeofobject) then
- break; { found pool with enough space }
- prev_hdr_ptr := hdr_ptr;
- hdr_ptr := hdr_ptr^.hdr.next;
- end;
- { Time to make a new pool? }
- if (hdr_ptr = NIL) then
- begin
- { min_request is what we need now, slop is what will be leftover }
- min_request := sizeofobject + SIZEOF(small_pool_hdr);
- if (prev_hdr_ptr = NIL) then { first pool in class? }
- slop := first_pool_slop[pool_id]
- else
- slop := extra_pool_slop[pool_id];
- { Don't ask for more than MAX_ALLOC_CHUNK }
- if (slop > size_t (MAX_ALLOC_CHUNK-min_request)) then
- slop := size_t (MAX_ALLOC_CHUNK-min_request);
- { Try to get space, if fail reduce slop and try again }
- while TRUE do
- begin
- hdr_ptr := small_pool_ptr(jpeg_get_small(cinfo, min_request + slop));
- if (hdr_ptr <> NIL) then
- break;
- slop := slop div 2;
- if (slop < MIN_SLOP) then { give up when it gets real small }
- out_of_memory(cinfo, 2); { jpeg_get_small failed }
- end;
- Inc(mem^.total_space_allocated, min_request + slop);
- { Success, initialize the new pool header and add to end of list }
- hdr_ptr^.hdr.next := NIL;
- hdr_ptr^.hdr.bytes_used := 0;
- hdr_ptr^.hdr.bytes_left := sizeofobject + slop;
- if (prev_hdr_ptr = NIL) then { first pool in class? }
- mem^.small_list[pool_id] := hdr_ptr
- else
- prev_hdr_ptr^.hdr.next := hdr_ptr;
- end;
- { OK, allocate the object from the current pool }
- data_ptr := byteptr (hdr_ptr);
- Inc(small_pool_ptr(data_ptr)); { point to first data byte in pool }
- Inc(data_ptr, hdr_ptr^.hdr.bytes_used); { point to place for object }
- Inc(hdr_ptr^.hdr.bytes_used, sizeofobject);
- Dec(hdr_ptr^.hdr.bytes_left, sizeofobject);
- alloc_small := pointer(data_ptr);
- end;
- { Allocation of "large" objects.
- The external semantics of these are the same as "small" objects,
- except that FAR pointers are used on 80x86. However the pool
- management heuristics are quite different. We assume that each
- request is large enough that it may as well be passed directly to
- jpeg_get_large; the pool management just links everything together
- so that we can free it all on demand.
- Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY
- structures. The routines that create these structures (see below)
- deliberately bunch rows together to ensure a large request size. }
- {METHODDEF}
- function alloc_large (cinfo : j_common_ptr;
- pool_id : int;
- sizeofobject : size_t) : pointer; FAR;
- { Allocate a "large" object }
- var
- mem : my_mem_ptr;
- hdr_ptr : large_pool_ptr;
- odd_bytes : size_t;
- var
- dest_ptr : large_pool_ptr;
- begin
- mem := my_mem_ptr (cinfo^.mem);
- { Check for unsatisfiable request (do now to ensure no overflow below) }
- if (sizeofobject > size_t (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) then
- out_of_memory(cinfo, 3); { request exceeds malloc's ability }
- { Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) }
- odd_bytes := sizeofobject mod SIZEOF(ALIGN_TYPE);
- if (odd_bytes > 0) then
- Inc(sizeofobject, SIZEOF(ALIGN_TYPE) - odd_bytes);
- { Always make a new pool }
- if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
- hdr_ptr := large_pool_ptr (jpeg_get_large(cinfo, sizeofobject +
- SIZEOF(large_pool_hdr)));
- if (hdr_ptr = NIL) then
- out_of_memory(cinfo, 4); { jpeg_get_large failed }
- Inc(mem^.total_space_allocated, sizeofobject + SIZEOF(large_pool_hdr));
- { Success, initialize the new pool header and add to list }
- hdr_ptr^.hdr.next := mem^.large_list[pool_id];
- { We maintain space counts in each pool header for statistical purposes,
- even though they are not needed for allocation. }
- hdr_ptr^.hdr.bytes_used := sizeofobject;
- hdr_ptr^.hdr.bytes_left := 0;
- mem^.large_list[pool_id] := hdr_ptr;
- {alloc_large := pointerFAR (hdr_ptr + 1); - point to first data byte in pool }
- dest_ptr := hdr_ptr;
- Inc(large_pool_ptr(dest_ptr));
- alloc_large := dest_ptr;
- end;
- { Creation of 2-D sample arrays.
- The pointers are in near heap, the samples themselves in FAR heap.
- To minimize allocation overhead and to allow I/O of large contiguous
- blocks, we allocate the sample rows in groups of as many rows as possible
- without exceeding MAX_ALLOC_CHUNK total bytes per allocation request.
- NB: the virtual array control routines, later in this file, know about
- this chunking of rows. The rowsperchunk value is left in the mem manager
- object so that it can be saved away if this sarray is the workspace for
- a virtual array. }
- {METHODDEF}
- function alloc_sarray (cinfo : j_common_ptr;
- pool_id : int;
- samplesperrow : JDIMENSION;
- numrows : JDIMENSION) : JSAMPARRAY; far;
- { Allocate a 2-D sample array }
- var
- mem : my_mem_ptr;
- the_result : JSAMPARRAY;
- workspace : JSAMPROW;
- rowsperchunk, currow, i : JDIMENSION;
- ltemp : long;
- begin
- mem := my_mem_ptr(cinfo^.mem);
- { Calculate max # of rows allowed in one allocation chunk }
- ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div
- (long(samplesperrow) * SIZEOF(JSAMPLE));
- if (ltemp <= 0) then
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- if (ltemp < long(numrows)) then
- rowsperchunk := JDIMENSION (ltemp)
- else
- rowsperchunk := numrows;
- mem^.last_rowsperchunk := rowsperchunk;
- { Get space for row pointers (small object) }
- the_result := JSAMPARRAY (alloc_small(cinfo, pool_id,
- size_t (numrows * SIZEOF(JSAMPROW))));
- { Get the rows themselves (large objects) }
- currow := 0;
- while (currow < numrows) do
- begin
- {rowsperchunk := MIN(rowsperchunk, numrows - currow);}
- if rowsperchunk > numrows - currow then
- rowsperchunk := numrows - currow;
- workspace := JSAMPROW (alloc_large(cinfo, pool_id,
- size_t (size_t(rowsperchunk) * size_t(samplesperrow)
- * SIZEOF(JSAMPLE))) );
- for i := pred(rowsperchunk) downto 0 do
- begin
- the_result^[currow] := workspace;
- Inc(currow);
- Inc(JSAMPLE_PTR(workspace), samplesperrow);
- end;
- end;
- alloc_sarray := the_result;
- end;
- { Creation of 2-D coefficient-block arrays.
- This is essentially the same as the code for sample arrays, above. }
- {METHODDEF}
- function alloc_barray (cinfo : j_common_ptr;
- pool_id : int;
- blocksperrow : JDIMENSION;
- numrows : JDIMENSION) : JBLOCKARRAY; far;
- { Allocate a 2-D coefficient-block array }
- var
- mem : my_mem_ptr;
- the_result : JBLOCKARRAY;
- workspace : JBLOCKROW;
- rowsperchunk, currow, i : JDIMENSION;
- ltemp : long;
- begin
- mem := my_mem_ptr(cinfo^.mem);
- { Calculate max # of rows allowed in one allocation chunk }
- ltemp := (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) div
- (long(blocksperrow) * SIZEOF(JBLOCK));
- if (ltemp <= 0) then
- ERREXIT(cinfo, JERR_WIDTH_OVERFLOW);
- if (ltemp < long(numrows)) then
- rowsperchunk := JDIMENSION (ltemp)
- else
- rowsperchunk := numrows;
- mem^.last_rowsperchunk := rowsperchunk;
- { Get space for row pointers (small object) }
- the_result := JBLOCKARRAY (alloc_small(cinfo, pool_id,
- size_t (numrows * SIZEOF(JBLOCKROW))) );
- { Get the rows themselves (large objects) }
- currow := 0;
- while (currow < numrows) do
- begin
- {rowsperchunk := MIN(rowsperchunk, numrows - currow);}
- if rowsperchunk > numrows - currow then
- rowsperchunk := numrows - currow;
- workspace := JBLOCKROW (alloc_large(cinfo, pool_id,
- size_t (size_t(rowsperchunk) * size_t(blocksperrow)
- * SIZEOF(JBLOCK))) );
- for i := rowsperchunk downto 1 do
- begin
- the_result^[currow] := workspace;
- Inc(currow);
- Inc(JBLOCK_PTR(workspace), blocksperrow);
- end;
- end;
- alloc_barray := the_result;
- end;
- { About virtual array management:
- The above "normal" array routines are only used to allocate strip buffers
- (as wide as the image, but just a few rows high). Full-image-sized buffers
- are handled as "virtual" arrays. The array is still accessed a strip at a
- time, but the memory manager must save the whole array for repeated
- accesses. The intended implementation is that there is a strip buffer in
- memory (as high as is possible given the desired memory limit), plus a
- backing file that holds the rest of the array.
- The request_virt_array routines are told the total size of the image and
- the maximum number of rows that will be accessed at once. The in-memory
- buffer must be at least as large as the maxaccess value.
- The request routines create control blocks but not the in-memory buffers.
- That is postponed until realize_virt_arrays is called. At that time the
- total amount of space needed is known (approximately, anyway), so free
- memory can be divided up fairly.
- The access_virt_array routines are responsible for making a specific strip
- area accessible (after reading or writing the backing file, if necessary).
- Note that the access routines are told whether the caller intends to modify
- the accessed strip; during a read-only pass this saves having to rewrite
- data to disk. The access routines are also responsible for pre-zeroing
- any newly accessed rows, if pre-zeroing was requested.
- In current usage, the access requests are usually for nonoverlapping
- strips; that is, successive access start_row numbers differ by exactly
- num_rows := maxaccess. This means we can get good performance with simple
- buffer dump/reload logic, by making the in-memory buffer be a multiple
- of the access height; then there will never be accesses across bufferload
- boundaries. The code will still work with overlapping access requests,
- but it doesn't handle bufferload overlaps very efficiently. }
- {METHODDEF}
- function request_virt_sarray (cinfo : j_common_ptr;
- pool_id : int;
- pre_zero : boolean;
- samplesperrow : JDIMENSION;
- numrows : JDIMENSION;
- maxaccess : JDIMENSION) : jvirt_sarray_ptr; far;
- { Request a virtual 2-D sample array }
- var
- mem : my_mem_ptr;
- the_result : jvirt_sarray_ptr;
- begin
- mem := my_mem_ptr (cinfo^.mem);
- { Only IMAGE-lifetime virtual arrays are currently supported }
- if (pool_id <> JPOOL_IMAGE) then
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
- { get control block }
- the_result := jvirt_sarray_ptr (alloc_small(cinfo, pool_id,
- SIZEOF(jvirt_sarray_control)) );
- the_result^.mem_buffer := NIL; { marks array not yet realized }
- the_result^.rows_in_array := numrows;
- the_result^.samplesperrow := samplesperrow;
- the_result^.maxaccess := maxaccess;
- the_result^.pre_zero := pre_zero;
- the_result^.b_s_open := FALSE; { no associated backing-store object }
- the_result^.next := mem^.virt_sarray_list; { add to list of virtual arrays }
- mem^.virt_sarray_list := the_result;
- request_virt_sarray := the_result;
- end;
- {METHODDEF}
- function request_virt_barray (cinfo : j_common_ptr;
- pool_id : int;
- pre_zero : boolean;
- blocksperrow : JDIMENSION;
- numrows : JDIMENSION;
- maxaccess : JDIMENSION) : jvirt_barray_ptr; far;
- { Request a virtual 2-D coefficient-block array }
- var
- mem : my_mem_ptr;
- the_result : jvirt_barray_ptr;
- begin
- mem := my_mem_ptr(cinfo^.mem);
- { Only IMAGE-lifetime virtual arrays are currently supported }
- if (pool_id <> JPOOL_IMAGE) then
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
- { get control block }
- the_result := jvirt_barray_ptr(alloc_small(cinfo, pool_id,
- SIZEOF(jvirt_barray_control)) );
- the_result^.mem_buffer := NIL; { marks array not yet realized }
- the_result^.rows_in_array := numrows;
- the_result^.blocksperrow := blocksperrow;
- the_result^.maxaccess := maxaccess;
- the_result^.pre_zero := pre_zero;
- the_result^.b_s_open := FALSE; { no associated backing-store object }
- the_result^.next := mem^.virt_barray_list; { add to list of virtual arrays }
- mem^.virt_barray_list := the_result;
- request_virt_barray := the_result;
- end;
- {METHODDEF}
- procedure realize_virt_arrays (cinfo : j_common_ptr); far;
- { Allocate the in-memory buffers for any unrealized virtual arrays }
- var
- mem : my_mem_ptr;
- space_per_minheight, maximum_space, avail_mem : long;
- minheights, max_minheights : long;
- sptr : jvirt_sarray_ptr;
- bptr : jvirt_barray_ptr;
- begin
- mem := my_mem_ptr (cinfo^.mem);
- { Compute the minimum space needed (maxaccess rows in each buffer)
- and the maximum space needed (full image height in each buffer).
- These may be of use to the system-dependent jpeg_mem_available routine. }
- space_per_minheight := 0;
- maximum_space := 0;
- sptr := mem^.virt_sarray_list;
- while (sptr <> NIL) do
- begin
- if (sptr^.mem_buffer = NIL) then
- begin { if not realized yet }
- Inc(space_per_minheight, long(sptr^.maxaccess) *
- long(sptr^.samplesperrow) * SIZEOF(JSAMPLE));
- Inc(maximum_space, long(sptr^.rows_in_array) *
- long(sptr^.samplesperrow) * SIZEOF(JSAMPLE));
- end;
- sptr := sptr^.next;
- end;
- bptr := mem^.virt_barray_list;
- while (bptr <> NIL) do
- begin
- if (bptr^.mem_buffer = NIL) then
- begin { if not realized yet }
- Inc(space_per_minheight, long(bptr^.maxaccess) *
- long(bptr^.blocksperrow) * SIZEOF(JBLOCK));
- Inc(maximum_space, long(bptr^.rows_in_array) *
- long(bptr^.blocksperrow) * SIZEOF(JBLOCK));
- end;
- bptr := bptr^.next;
- end;
- if (space_per_minheight <= 0) then
- exit; { no unrealized arrays, no work }
- { Determine amount of memory to actually use; this is system-dependent. }
- avail_mem := jpeg_mem_available(cinfo, space_per_minheight, maximum_space,
- mem^.total_space_allocated);
- { If the maximum space needed is available, make all the buffers full
- height; otherwise parcel it out with the same number of minheights
- in each buffer. }
- if (avail_mem >= maximum_space) then
- max_minheights := long(1000000000)
- else
- begin
- max_minheights := avail_mem div space_per_minheight;
- { If there doesn't seem to be enough space, try to get the minimum
- anyway. This allows a "stub" implementation of jpeg_mem_available(). }
- if (max_minheights <= 0) then
- max_minheights := 1;
- end;
- { Allocate the in-memory buffers and initialize backing store as needed. }
- sptr := mem^.virt_sarray_list;
- while (sptr <> NIL) do
- begin
- if (sptr^.mem_buffer = NIL) then
- begin { if not realized yet }
- minheights := (long(sptr^.rows_in_array) - long(1)) div sptr^.maxaccess + long(1);
- if (minheights <= max_minheights) then
- begin
- { This buffer fits in memory }
- sptr^.rows_in_mem := sptr^.rows_in_array;
- end
- else
- begin
- { It doesn't fit in memory, create backing store. }
- sptr^.rows_in_mem := JDIMENSION (max_minheights * sptr^.maxaccess);
- jpeg_open_backing_store(cinfo,
- @sptr^.b_s_info,
- long(sptr^.rows_in_array) *
- long(sptr^.samplesperrow) *
- long(SIZEOF(JSAMPLE)));
- sptr^.b_s_open := TRUE;
- end;
- sptr^.mem_buffer := alloc_sarray(cinfo, JPOOL_IMAGE,
- sptr^.samplesperrow, sptr^.rows_in_mem);
- sptr^.rowsperchunk := mem^.last_rowsperchunk;
- sptr^.cur_start_row := 0;
- sptr^.first_undef_row := 0;
- sptr^.dirty := FALSE;
- end;
- sptr := sptr^.next;
- end;
- bptr := mem^.virt_barray_list;
- while (bptr <> NIL) do
- begin
- if (bptr^.mem_buffer = NIL) then
- begin { if not realized yet }
- minheights := (long(bptr^.rows_in_array) - long(1)) div bptr^.maxaccess + long(1);
- if (minheights <= max_minheights) then
- begin
- { This buffer fits in memory }
- bptr^.rows_in_mem := bptr^.rows_in_array;
- end
- else
- begin
- { It doesn't fit in memory, create backing store. }
- bptr^.rows_in_mem := JDIMENSION (max_minheights * bptr^.maxaccess);
- jpeg_open_backing_store(cinfo,
- @bptr^.b_s_info,
- long(bptr^.rows_in_array) *
- long(bptr^.blocksperrow) *
- long(SIZEOF(JBLOCK)));
- bptr^.b_s_open := TRUE;
- end;
- bptr^.mem_buffer := alloc_barray(cinfo, JPOOL_IMAGE,
- bptr^.blocksperrow, bptr^.rows_in_mem);
- bptr^.rowsperchunk := mem^.last_rowsperchunk;
- bptr^.cur_start_row := 0;
- bptr^.first_undef_row := 0;
- bptr^.dirty := FALSE;
- end;
- bptr := bptr^.next;
- end;
- end;
- {LOCAL}
- procedure do_sarray_io (cinfo : j_common_ptr;
- ptr : jvirt_sarray_ptr;
- writing : boolean);
- { Do backing store read or write of a virtual sample array }
- var
- bytesperrow, file_offset, byte_count, rows, thisrow, i : long;
- begin
- bytesperrow := long(ptr^.samplesperrow * SIZEOF(JSAMPLE));
- file_offset := ptr^.cur_start_row * bytesperrow;
- { Loop to read or write each allocation chunk in mem_buffer }
- i := 0;
- while i < long(ptr^.rows_in_mem) do
- begin
- { One chunk, but check for short chunk at end of buffer }
- {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));}
- rows := long(ptr^.rowsperchunk);
- if rows > long(ptr^.rows_in_mem - i) then
- rows := long(ptr^.rows_in_mem - i);
- { Transfer no more than is currently defined }
- thisrow := long (ptr^.cur_start_row) + i;
- {rows := MIN(rows, long(ptr^.first_undef_row) - thisrow);}
- if (rows > long(ptr^.first_undef_row) - thisrow) then
- rows := long(ptr^.first_undef_row) - thisrow;
- { Transfer no more than fits in file }
- {rows := MIN(rows, long(ptr^.rows_in_array) - thisrow);}
- if (rows > long(ptr^.rows_in_array) - thisrow) then
- rows := long(ptr^.rows_in_array) - thisrow;
- if (rows <= 0) then { this chunk might be past end of file! }
- break;
- byte_count := rows * bytesperrow;
- if (writing) then
- ptr^.b_s_info.write_backing_store (cinfo,
- @ptr^.b_s_info,
- pointer {FAR} (ptr^.mem_buffer^[i]),
- file_offset, byte_count)
- else
- ptr^.b_s_info.read_backing_store (cinfo,
- @ptr^.b_s_info,
- pointer {FAR} (ptr^.mem_buffer^[i]),
- file_offset, byte_count);
- Inc(file_offset, byte_count);
- Inc(i, ptr^.rowsperchunk);
- end;
- end;
- {LOCAL}
- procedure do_barray_io (cinfo : j_common_ptr;
- ptr : jvirt_barray_ptr;
- writing : boolean);
- { Do backing store read or write of a virtual coefficient-block array }
- var
- bytesperrow, file_offset, byte_count, rows, thisrow, i : long;
- begin
- bytesperrow := long (ptr^.blocksperrow) * SIZEOF(JBLOCK);
- file_offset := ptr^.cur_start_row * bytesperrow;
- { Loop to read or write each allocation chunk in mem_buffer }
- i := 0;
- while (i < long(ptr^.rows_in_mem)) do
- begin
- { One chunk, but check for short chunk at end of buffer }
- {rows := MIN(long(ptr^.rowsperchunk), long(ptr^.rows_in_mem - i));}
- rows := long(ptr^.rowsperchunk);
- if rows >long(ptr^.rows_in_mem - i) then
- rows := long(ptr^.rows_in_mem - i);
- { Transfer no more than is currently defined }
- thisrow := long (ptr^.cur_start_row) + i;
- {rows := MIN(rows, long(ptr^.first_undef_row - thisrow));}
- if rows > long(ptr^.first_undef_row - thisrow) then
- rows := long(ptr^.first_undef_row - thisrow);
- { Transfer no more than fits in file }
- {rows := MIN(rows, long (ptr^.rows_in_array - thisrow));}
- if (rows > long (ptr^.rows_in_array - thisrow)) then
- rows := long (ptr^.rows_in_array - thisrow);
- if (rows <= 0) then { this chunk might be past end of file! }
- break;
- byte_count := rows * bytesperrow;
- if (writing) then
- ptr^.b_s_info.write_backing_store (cinfo,
- @ptr^.b_s_info,
- {FAR} pointer(ptr^.mem_buffer^[i]),
- file_offset, byte_count)
- else
- ptr^.b_s_info.read_backing_store (cinfo,
- @ptr^.b_s_info,
- {FAR} pointer(ptr^.mem_buffer^[i]),
- file_offset, byte_count);
- Inc(file_offset, byte_count);
- Inc(i, ptr^.rowsperchunk);
- end;
- end;
- {METHODDEF}
- function access_virt_sarray (cinfo : j_common_ptr;
- ptr : jvirt_sarray_ptr;
- start_row : JDIMENSION;
- num_rows : JDIMENSION;
- writable : boolean ) : JSAMPARRAY; far;
- { Access the part of a virtual sample array starting at start_row }
- { and extending for num_rows rows. writable is true if }
- { caller intends to modify the accessed area. }
- var
- end_row : JDIMENSION;
- undef_row : JDIMENSION;
- var
- bytesperrow : size_t;
- var
- ltemp : long;
- begin
- end_row := start_row + num_rows;
- { debugging check }
- if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or
- (ptr^.mem_buffer = NIL) then
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- { Make the desired part of the virtual array accessible }
- if (start_row < ptr^.cur_start_row) or
- (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then
- begin
- if (not ptr^.b_s_open) then
- ERREXIT(cinfo, JERR_VIRTUAL_BUG);
- { Flush old buffer contents if necessary }
- if (ptr^.dirty) then
- begin
- do_sarray_io(cinfo, ptr, TRUE);
- ptr^.dirty := FALSE;
- end;
- { Decide what part of virtual array to access.
- Algorithm: if target address > current window, assume forward scan,
- load starting at target address. If target address < current window,
- assume backward scan, load so that target area is top of window.
- Note that when switching from forward write to forward read, will have
- start_row := 0, so the limiting case applies and we load from 0 anyway. }
- if (start_row > ptr^.cur_start_row) then
- begin
- ptr^.cur_start_row := start_row;
- end
- else
- begin
- { use long arithmetic here to avoid overflow & unsigned problems }
- ltemp := long(end_row) - long(ptr^.rows_in_mem);
- if (ltemp < 0) then
- ltemp := 0; { don't fall off front end of file }
- ptr^.cur_start_row := JDIMENSION(ltemp);
- end;
- { Read in the selected part of the array.
- During the initial write pass, we will do no actual read
- because the selected part is all undefined. }
- do_sarray_io(cinfo, ptr, FALSE);
- end;
- { Ensure the accessed part of the array is defined; prezero if needed.
- To improve locality of access, we only prezero the part of the array
- that the caller is about to access, not the entire in-memory array. }
- if (ptr^.first_undef_row < end_row) then
- begin
- if (ptr^.first_undef_row < start_row) then
- begin
- if (writable) then { writer skipped over a section of array }
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- undef_row := start_row; { but reader is allowed to read ahead }
- end
- else
- begin
- undef_row := ptr^.first_undef_row;
- end;
- if (writable) then
- ptr^.first_undef_row := end_row;
- if (ptr^.pre_zero) then
- begin
- bytesperrow := size_t(ptr^.samplesperrow) * SIZEOF(JSAMPLE);
- Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer }
- Dec(end_row, ptr^.cur_start_row);
- while (undef_row < end_row) do
- begin
- jzero_far({FAR} pointer(ptr^.mem_buffer^[undef_row]), bytesperrow);
- Inc(undef_row);
- end;
- end
- else
- begin
- if (not writable) then { reader looking at undefined data }
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- end;
- end;
- { Flag the buffer dirty if caller will write in it }
- if (writable) then
- ptr^.dirty := TRUE;
- { Return address of proper part of the buffer }
- access_virt_sarray := JSAMPARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]);
- end;
- {METHODDEF}
- function access_virt_barray (cinfo : j_common_ptr;
- ptr : jvirt_barray_ptr;
- start_row : JDIMENSION;
- num_rows : JDIMENSION;
- writable : boolean) : JBLOCKARRAY; far;
- { Access the part of a virtual block array starting at start_row }
- { and extending for num_rows rows. writable is true if }
- { caller intends to modify the accessed area. }
- var
- end_row : JDIMENSION;
- undef_row : JDIMENSION;
- ltemp : long;
- var
- bytesperrow : size_t;
- begin
- end_row := start_row + num_rows;
- { debugging check }
- if (end_row > ptr^.rows_in_array) or (num_rows > ptr^.maxaccess) or
- (ptr^.mem_buffer = NIL) then
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- { Make the desired part of the virtual array accessible }
- if (start_row < ptr^.cur_start_row) or
- (end_row > ptr^.cur_start_row+ptr^.rows_in_mem) then
- begin
- if (not ptr^.b_s_open) then
- ERREXIT(cinfo, JERR_VIRTUAL_BUG);
- { Flush old buffer contents if necessary }
- if (ptr^.dirty) then
- begin
- do_barray_io(cinfo, ptr, TRUE);
- ptr^.dirty := FALSE;
- end;
- { Decide what part of virtual array to access.
- Algorithm: if target address > current window, assume forward scan,
- load starting at target address. If target address < current window,
- assume backward scan, load so that target area is top of window.
- Note that when switching from forward write to forward read, will have
- start_row := 0, so the limiting case applies and we load from 0 anyway. }
- if (start_row > ptr^.cur_start_row) then
- begin
- ptr^.cur_start_row := start_row;
- end
- else
- begin
- { use long arithmetic here to avoid overflow & unsigned problems }
- ltemp := long(end_row) - long(ptr^.rows_in_mem);
- if (ltemp < 0) then
- ltemp := 0; { don't fall off front end of file }
- ptr^.cur_start_row := JDIMENSION (ltemp);
- end;
- { Read in the selected part of the array.
- During the initial write pass, we will do no actual read
- because the selected part is all undefined. }
- do_barray_io(cinfo, ptr, FALSE);
- end;
- { Ensure the accessed part of the array is defined; prezero if needed.
- To improve locality of access, we only prezero the part of the array
- that the caller is about to access, not the entire in-memory array. }
- if (ptr^.first_undef_row < end_row) then
- begin
- if (ptr^.first_undef_row < start_row) then
- begin
- if (writable) then { writer skipped over a section of array }
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- undef_row := start_row; { but reader is allowed to read ahead }
- end
- else
- begin
- undef_row := ptr^.first_undef_row;
- end;
- if (writable) then
- ptr^.first_undef_row := end_row;
- if (ptr^.pre_zero) then
- begin
- bytesperrow := size_t (ptr^.blocksperrow) * SIZEOF(JBLOCK);
- Dec(undef_row, ptr^.cur_start_row); { make indexes relative to buffer }
- Dec(end_row, ptr^.cur_start_row);
- while (undef_row < end_row) do
- begin
- jzero_far({FAR}pointer(ptr^.mem_buffer^[undef_row]), bytesperrow);
- Inc(undef_row);
- end;
- end
- else
- begin
- if (not writable) then { reader looking at undefined data }
- ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS);
- end;
- end;
- { Flag the buffer dirty if caller will write in it }
- if (writable) then
- ptr^.dirty := TRUE;
- { Return address of proper part of the buffer }
- access_virt_barray := JBLOCKARRAY(@ ptr^.mem_buffer^[start_row - ptr^.cur_start_row]);
- end;
- { Release all objects belonging to a specified pool. }
- {METHODDEF}
- procedure free_pool (cinfo : j_common_ptr; pool_id : int); far;
- var
- mem : my_mem_ptr;
- shdr_ptr : small_pool_ptr;
- lhdr_ptr : large_pool_ptr;
- space_freed : size_t;
- var
- sptr : jvirt_sarray_ptr;
- bptr : jvirt_barray_ptr;
- var
- next_lhdr_ptr : large_pool_ptr;
- next_shdr_ptr : small_pool_ptr;
- begin
- mem := my_mem_ptr(cinfo^.mem);
- if (pool_id < 0) or (pool_id >= JPOOL_NUMPOOLS) then
- ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); { safety check }
- {$ifdef MEM_STATS}
- if (cinfo^.err^.trace_level > 1) then
- print_mem_stats(cinfo, pool_id); { print pool's memory usage statistics }
- {$endif}
- { If freeing IMAGE pool, close any virtual arrays first }
- if (pool_id = JPOOL_IMAGE) then
- begin
- sptr := mem^.virt_sarray_list;
- while (sptr <> NIL) do
- begin
- if (sptr^.b_s_open) then
- begin { there may be no backing store }
- sptr^.b_s_open := FALSE; { prevent recursive close if error }
- sptr^.b_s_info.close_backing_store (cinfo, @sptr^.b_s_info);
- end;
- sptr := sptr^.next;
- end;
- mem^.virt_sarray_list := NIL;
- bptr := mem^.virt_barray_list;
- while (bptr <> NIL) do
- begin
- if (bptr^.b_s_open) then
- begin { there may be no backing store }
- bptr^.b_s_open := FALSE; { prevent recursive close if error }
- bptr^.b_s_info.close_backing_store (cinfo, @bptr^.b_s_info);
- end;
- bptr := bptr^.next;
- end;
- mem^.virt_barray_list := NIL;
- end;
- { Release large objects }
- lhdr_ptr := mem^.large_list[pool_id];
- mem^.large_list[pool_id] := NIL;
- while (lhdr_ptr <> NIL) do
- begin
- next_lhdr_ptr := lhdr_ptr^.hdr.next;
- space_freed := lhdr_ptr^.hdr.bytes_used +
- lhdr_ptr^.hdr.bytes_left +
- SIZEOF(large_pool_hdr);
- jpeg_free_large(cinfo, {FAR} pointer(lhdr_ptr), space_freed);
- Dec(mem^.total_space_allocated, space_freed);
- lhdr_ptr := next_lhdr_ptr;
- end;
- { Release small objects }
- shdr_ptr := mem^.small_list[pool_id];
- mem^.small_list[pool_id] := NIL;
- while (shdr_ptr <> NIL) do
- begin
- next_shdr_ptr := shdr_ptr^.hdr.next;
- space_freed := shdr_ptr^.hdr.bytes_used +
- shdr_ptr^.hdr.bytes_left +
- SIZEOF(small_pool_hdr);
- jpeg_free_small(cinfo, pointer(shdr_ptr), space_freed);
- Dec(mem^.total_space_allocated, space_freed);
- shdr_ptr := next_shdr_ptr;
- end;
- end;
- { Close up shop entirely.
- Note that this cannot be called unless cinfo^.mem is non-NIL. }
- {METHODDEF}
- procedure self_destruct (cinfo : j_common_ptr); far;
- var
- pool : int;
- begin
- { Close all backing store, release all memory.
- Releasing pools in reverse order might help avoid fragmentation
- with some (brain-damaged) malloc libraries. }
- for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do
- begin
- free_pool(cinfo, pool);
- end;
- { Release the memory manager control block too. }
- jpeg_free_small(cinfo, pointer(cinfo^.mem), SIZEOF(my_memory_mgr));
- cinfo^.mem := NIL; { ensures I will be called only once }
- jpeg_mem_term(cinfo); { system-dependent cleanup }
- end;
- { Memory manager initialization.
- When this is called, only the error manager pointer is valid in cinfo! }
- {GLOBAL}
- procedure jinit_memory_mgr (cinfo : j_common_ptr);
- var
- mem : my_mem_ptr;
- max_to_use : long;
- pool : int;
- test_mac : size_t;
- {$ifndef NO_GETENV}
- var
- memenv : string;
- code : integer;
- {$endif}
- begin
- cinfo^.mem := NIL; { for safety if init fails }
- { Check for configuration errors.
- SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably
- doesn't reflect any real hardware alignment requirement.
- The test is a little tricky: for X>0, X and X-1 have no one-bits
- in common if and only if X is a power of 2, ie has only one one-bit.
- Some compilers may give an "unreachable code" warning here; ignore it. }
- if ((SIZEOF(ALIGN_TYPE) and (SIZEOF(ALIGN_TYPE)-1)) <> 0) then
- ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE);
- { MAX_ALLOC_CHUNK must be representable as type size_t, and must be
- a multiple of SIZEOF(ALIGN_TYPE).
- Again, an "unreachable code" warning may be ignored here.
- But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. }
- test_mac := size_t (MAX_ALLOC_CHUNK);
- if (long (test_mac) <> MAX_ALLOC_CHUNK) or
- ((MAX_ALLOC_CHUNK mod SIZEOF(ALIGN_TYPE)) <> 0) then
- ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK);
- max_to_use := jpeg_mem_init(cinfo); { system-dependent initialization }
- { Attempt to allocate memory manager's control block }
- mem := my_mem_ptr (jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)));
- if (mem = NIL) then
- begin
- jpeg_mem_term(cinfo); { system-dependent cleanup }
- ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0);
- end;
- { OK, fill in the method pointers }
- mem^.pub.alloc_small := alloc_small;
- mem^.pub.alloc_large := alloc_large;
- mem^.pub.alloc_sarray := alloc_sarray;
- mem^.pub.alloc_barray := alloc_barray;
- mem^.pub.request_virt_sarray := request_virt_sarray;
- mem^.pub.request_virt_barray := request_virt_barray;
- mem^.pub.realize_virt_arrays := realize_virt_arrays;
- mem^.pub.access_virt_sarray := access_virt_sarray;
- mem^.pub.access_virt_barray := access_virt_barray;
- mem^.pub.free_pool := free_pool;
- mem^.pub.self_destruct := self_destruct;
- { Make MAX_ALLOC_CHUNK accessible to other modules }
- mem^.pub.max_alloc_chunk := MAX_ALLOC_CHUNK;
- { Initialize working state }
- mem^.pub.max_memory_to_use := max_to_use;
- for pool := JPOOL_NUMPOOLS-1 downto JPOOL_PERMANENT do
- begin
- mem^.small_list[pool] := NIL;
- mem^.large_list[pool] := NIL;
- end;
- mem^.virt_sarray_list := NIL;
- mem^.virt_barray_list := NIL;
- mem^.total_space_allocated := SIZEOF(my_memory_mgr);
- { Declare ourselves open for business }
- cinfo^.mem := @mem^.pub;
- { Check for an environment variable JPEGMEM; if found, override the
- default max_memory setting from jpeg_mem_init. Note that the
- surrounding application may again override this value.
- If your system doesn't support getenv(), define NO_GETENV to disable
- this feature. }
- {$ifndef NO_GETENV}
- memenv := getenv('JPEGMEM');
- if (memenv <> '') then
- begin
- Val(memenv, max_to_use, code);
- if (Code = 0) then
- begin
- max_to_use := max_to_use * long(1000);
- mem^.pub.max_memory_to_use := max_to_use * long(1000);
- end;
- end;
- {$endif}
- end;
- end.
|