43 #include "magick/studio.h"
44 #include "magick/blob.h"
45 #include "magick/blob-private.h"
46 #include "magick/cache.h"
47 #include "magick/cache-private.h"
48 #include "magick/color-private.h"
49 #include "magick/colorspace.h"
50 #include "magick/colorspace-private.h"
51 #include "magick/composite-private.h"
52 #include "magick/distribute-cache-private.h"
53 #include "magick/exception.h"
54 #include "magick/exception-private.h"
55 #include "magick/geometry.h"
56 #include "magick/list.h"
57 #include "magick/log.h"
58 #include "magick/magick.h"
59 #include "magick/memory_.h"
60 #include "magick/memory-private.h"
61 #include "magick/nt-base-private.h"
62 #include "magick/option.h"
63 #include "magick/pixel.h"
64 #include "magick/pixel-accessor.h"
65 #include "magick/pixel-private.h"
66 #include "magick/policy.h"
67 #include "magick/quantum.h"
68 #include "magick/random_.h"
69 #include "magick/registry.h"
70 #include "magick/resource_.h"
71 #include "magick/semaphore.h"
72 #include "magick/splay-tree.h"
73 #include "magick/string_.h"
74 #include "magick/string-private.h"
75 #include "magick/thread-private.h"
76 #include "magick/timer-private.h"
77 #include "magick/utility.h"
78 #include "magick/utility-private.h"
79 #if defined(MAGICKCORE_ZLIB_DELEGATE)
86 #define CacheTick(offset,extent) QuantumTick((MagickOffsetType) offset,extent)
87 #define IsFileDescriptorLimitExceeded() (GetMagickResource(FileResource) > \
88 GetMagickResourceLimit(FileResource) ? MagickTrue : MagickFalse)
103 #if defined(__cplusplus) || defined(c_plusplus)
111 static const IndexPacket
112 *GetVirtualIndexesFromCache(const
Image *);
115 *GetVirtualPixelCache(const Image *,const VirtualPixelMethod,const ssize_t,
117 *GetVirtualPixelsCache(const Image *);
119 static MagickBooleanType
120 GetOneAuthenticPixelFromCache(Image *,const ssize_t,const ssize_t,
122 GetOneVirtualPixelFromCache(const Image *,const VirtualPixelMethod,
123 const ssize_t,const ssize_t,PixelPacket *,ExceptionInfo *),
124 OpenPixelCache(Image *,const MapMode,ExceptionInfo *),
125 OpenPixelCacheOnDisk(
CacheInfo *,const MapMode),
126 ReadPixelCacheIndexes(CacheInfo *magick_restrict,
NexusInfo *magick_restrict,
128 ReadPixelCachePixels(CacheInfo *magick_restrict,
NexusInfo *magick_restrict,
130 SyncAuthenticPixelsCache(Image *,ExceptionInfo *),
131 WritePixelCacheIndexes(CacheInfo *,
NexusInfo *magick_restrict,
133 WritePixelCachePixels(CacheInfo *,
NexusInfo *magick_restrict,
137 *GetAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const
size_t,
138 const
size_t,ExceptionInfo *),
139 *QueueAuthenticPixelsCache(Image *,const ssize_t,const ssize_t,const
size_t,
140 const
size_t,ExceptionInfo *),
141 *SetPixelCacheNexusPixels(const CacheInfo *magick_restrict,const MapMode,
142 const ssize_t,const ssize_t,const
size_t,const
size_t,
143 const MagickBooleanType,
NexusInfo *magick_restrict,ExceptionInfo *)
146 #if defined(MAGICKCORE_OPENCL_SUPPORT)
148 CopyOpenCLBuffer(CacheInfo *magick_restrict);
151 #if defined(__cplusplus) || defined(c_plusplus)
162 cache_anonymous_memory = (-1);
167 #if defined(MAGICKCORE_OPENCL_SUPPORT)
174 for (i=0; i < (ssize_t) info->event_count; i++)
175 clEnv->library->clReleaseEvent(info->events[i]);
176 info->events=(cl_event *) RelinquishMagickMemory(info->events);
177 DestroySemaphoreInfo(&info->events_semaphore);
178 if (info->buffer != (cl_mem) NULL)
180 clEnv->library->clReleaseMemObject(info->buffer);
181 info->buffer=(cl_mem) NULL;
186 static void CL_API_CALL RelinquishPixelCachePixelsDelayed(
187 cl_event magick_unused(event),cl_int magick_unused(event_command_exec_status),
202 magick_unreferenced(event);
203 magick_unreferenced(event_command_exec_status);
205 clEnv=GetDefaultOpenCLEnv();
206 for (i=(ssize_t)info->event_count-1; i >= 0; i--)
214 status=clEnv->library->clGetEventInfo(info->events[i],
215 CL_EVENT_COMMAND_EXECUTION_STATUS,
sizeof(cl_int),&event_status,NULL);
216 if ((status == CL_SUCCESS) && (event_status > CL_COMPLETE))
218 clEnv->library->clSetEventCallback(info->events[i],CL_COMPLETE,
219 &RelinquishPixelCachePixelsDelayed,info);
224 RelinquishMagickResource(MemoryResource,info->length);
225 (void) RelinquishOpenCLCacheInfo(clEnv,info);
226 (void) RelinquishAlignedMemory(pixels);
229 static MagickBooleanType RelinquishOpenCLBuffer(
235 assert(cache_info != (
CacheInfo *) NULL);
238 RelinquishPixelCachePixelsDelayed((cl_event) NULL,0,cache_info->opencl);
243 cl_uint *event_count)
252 events=(cl_event *) NULL;
253 LockSemaphoreInfo(opencl_info->events_semaphore);
254 *event_count=opencl_info->event_count;
255 if (*event_count > 0)
257 events=AcquireQuantumMemory(*event_count,
sizeof(*events));
258 if (events == (cl_event *) NULL)
262 for (i=0; i < opencl_info->event_count; i++)
263 events[i]=opencl_info->events[i];
266 UnlockSemaphoreInfo(opencl_info->events_semaphore);
271 #if defined(MAGICKCORE_OPENCL_SUPPORT)
297 extern MagickPrivate
void AddOpenCLEvent(
const Image *image,cl_event event)
300 *magick_restrict cache_info;
305 assert(image != (
const Image *) NULL);
306 assert(event != (cl_event) NULL);
309 clEnv=GetDefaultOpenCLEnv();
310 if (clEnv->library->clRetainEvent(event) != CL_SUCCESS)
312 clEnv->library->clWaitForEvents(1,&event);
315 LockSemaphoreInfo(cache_info->opencl->events_semaphore);
316 if (cache_info->opencl->events == (cl_event *) NULL)
318 cache_info->opencl->events=AcquireMagickMemory(
sizeof(
319 *cache_info->opencl->events));
320 cache_info->opencl->event_count=1;
323 cache_info->opencl->events=ResizeQuantumMemory(cache_info->opencl->events,
324 ++cache_info->opencl->event_count,
sizeof(*cache_info->opencl->events));
325 if (cache_info->opencl->events == (cl_event *) NULL)
326 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
327 cache_info->opencl->events[cache_info->opencl->event_count-1]=event;
328 UnlockSemaphoreInfo(cache_info->opencl->events_semaphore);
354 MagickExport Cache AcquirePixelCache(
const size_t number_threads)
357 *magick_restrict cache_info;
362 cache_info=(
CacheInfo *) AcquireAlignedMemory(1,
sizeof(*cache_info));
364 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
365 (void) memset(cache_info,0,
sizeof(*cache_info));
366 cache_info->type=UndefinedCache;
367 cache_info->mode=IOMode;
368 cache_info->disk_mode=IOMode;
369 cache_info->colorspace=sRGBColorspace;
370 cache_info->channels=4;
371 cache_info->file=(-1);
372 cache_info->id=GetMagickThreadId();
373 cache_info->number_threads=number_threads;
374 if (GetOpenMPMaximumThreads() > cache_info->number_threads)
375 cache_info->number_threads=GetOpenMPMaximumThreads();
376 if (GetMagickResourceLimit(ThreadResource) > cache_info->number_threads)
377 cache_info->number_threads=(size_t) GetMagickResourceLimit(ThreadResource);
378 if (cache_info->number_threads == 0)
379 cache_info->number_threads=1;
380 cache_info->nexus_info=AcquirePixelCacheNexus(cache_info->number_threads);
381 value=GetEnvironmentValue(
"MAGICK_SYNCHRONIZE");
382 if (value != (
const char *) NULL)
384 cache_info->synchronize=IsStringTrue(value);
385 value=DestroyString(value);
387 value=GetPolicyValue(
"cache:synchronize");
388 if (value != (
const char *) NULL)
390 cache_info->synchronize=IsStringTrue(value);
391 value=DestroyString(value);
393 cache_info->width_limit=MagickMin(GetMagickResourceLimit(WidthResource),
394 (MagickSizeType) MAGICK_SSIZE_MAX);
395 cache_info->height_limit=MagickMin(GetMagickResourceLimit(HeightResource),
396 (MagickSizeType) MAGICK_SSIZE_MAX);
397 cache_info->semaphore=AllocateSemaphoreInfo();
398 cache_info->reference_count=1;
399 cache_info->file_semaphore=AllocateSemaphoreInfo();
400 cache_info->debug=GetLogEventMask() & CacheEvent ? MagickTrue : MagickFalse;
401 cache_info->signature=MagickCoreSignature;
402 return((Cache ) cache_info);
427 MagickExport
NexusInfo **AcquirePixelCacheNexus(
const size_t number_threads)
430 **magick_restrict nexus_info;
435 nexus_info=(
NexusInfo **) MagickAssumeAligned(AcquireAlignedMemory(2*
436 number_threads,
sizeof(*nexus_info)));
438 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
439 *nexus_info=(
NexusInfo *) AcquireQuantumMemory(number_threads,
440 2*
sizeof(**nexus_info));
442 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
443 (void) memset(*nexus_info,0,2*number_threads*
sizeof(**nexus_info));
444 for (i=0; i < (ssize_t) (2*number_threads); i++)
446 nexus_info[i]=(*nexus_info+i);
447 if (i < (ssize_t) number_threads)
448 nexus_info[i]->virtual_nexus=(*nexus_info+number_threads+i);
449 nexus_info[i]->signature=MagickCoreSignature;
482 MagickExport
const void *AcquirePixelCachePixels(
const Image *image,
486 *magick_restrict cache_info;
488 assert(image != (
const Image *) NULL);
489 assert(image->signature == MagickCoreSignature);
491 assert(exception->signature == MagickCoreSignature);
492 assert(image->cache != (Cache) NULL);
494 assert(cache_info->signature == MagickCoreSignature);
497 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
498 return((
const void *) NULL);
499 *length=cache_info->length;
500 return((
const void *) cache_info->pixels);
521 MagickExport MagickBooleanType CacheComponentGenesis(
void)
524 cache_semaphore=AllocateSemaphoreInfo();
546 MagickExport
void CacheComponentTerminus(
void)
549 ActivateSemaphoreInfo(&cache_semaphore);
551 DestroySemaphoreInfo(&cache_semaphore);
583 static MagickBooleanType ClipPixelCacheNexus(
Image *image,
587 *magick_restrict cache_info;
593 *magick_restrict nexus_indexes,
594 *magick_restrict indexes;
600 **magick_restrict clip_nexus;
612 if (IsEventLogging() != MagickFalse)
613 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
614 if ((image->clip_mask == (
Image *) NULL) ||
615 (image->storage_class == PseudoClass))
617 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
620 if (cache_info == (Cache) NULL)
622 clip_nexus=AcquirePixelCacheNexus(1);
623 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y,
624 nexus_info->region.width,nexus_info->region.height,
625 nexus_info->virtual_nexus,exception);
626 indexes=nexus_info->virtual_nexus->indexes;
627 q=nexus_info->pixels;
628 nexus_indexes=nexus_info->indexes;
629 r=GetVirtualPixelCacheNexus(image->clip_mask,MaskVirtualPixelMethod,
630 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
631 nexus_info->region.height,clip_nexus[0],exception);
636 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
641 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
646 mask_alpha=QuantumScale*GetPixelIntensity(image,r);
647 if (fabs(mask_alpha) >= MagickEpsilon)
649 SetPixelRed(q,MagickOver_((MagickRealType) p->red,(MagickRealType)
650 GetPixelOpacity(p),(MagickRealType) q->red,(MagickRealType)
651 GetPixelOpacity(q)));
652 SetPixelGreen(q,MagickOver_((MagickRealType) p->green,(MagickRealType)
653 GetPixelOpacity(p),(MagickRealType) q->green,(MagickRealType)
654 GetPixelOpacity(q)));
655 SetPixelBlue(q,MagickOver_((MagickRealType) p->blue,(MagickRealType)
656 GetPixelOpacity(p),(MagickRealType) q->blue,(MagickRealType)
657 GetPixelOpacity(q)));
658 SetPixelOpacity(q,GetPixelOpacity(p));
659 if (cache_info->active_index_channel != MagickFalse)
660 SetPixelIndex(nexus_indexes+n,GetPixelIndex(indexes+n));
668 clip_nexus=DestroyPixelCacheNexus(clip_nexus,1);
694 MagickExport Cache ClonePixelCache(
const Cache cache)
697 *magick_restrict clone_info;
700 *magick_restrict cache_info;
702 assert(cache != NULL);
704 assert(cache_info->signature == MagickCoreSignature);
705 if (IsEventLogging() != MagickFalse)
706 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
707 cache_info->filename);
708 clone_info=(
CacheInfo *) AcquirePixelCache(cache_info->number_threads);
709 clone_info->virtual_pixel_method=cache_info->virtual_pixel_method;
710 return((Cache ) clone_info);
738 MagickExport
void ClonePixelCacheMethods(Cache clone,
const Cache cache)
741 *magick_restrict cache_info,
742 *magick_restrict source_info;
744 assert(clone != (Cache) NULL);
746 assert(source_info->signature == MagickCoreSignature);
747 if (IsEventLogging() != MagickFalse)
748 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
749 source_info->filename);
750 assert(cache != (Cache) NULL);
752 assert(cache_info->signature == MagickCoreSignature);
753 source_info->methods=cache_info->methods;
785 static MagickBooleanType ClonePixelCacheOnDisk(
806 if ((OpenPixelCacheOnDisk(cache_info,ReadMode) == MagickFalse) ||
807 (OpenPixelCacheOnDisk(clone_info,IOMode) == MagickFalse))
809 if ((lseek(cache_info->file,0,SEEK_SET) < 0) ||
810 (lseek(clone_info->file,0,SEEK_SET) < 0))
812 quantum=(size_t) MagickMaxBufferExtent;
813 if ((fstat(cache_info->file,&file_stats) == 0) && (file_stats.st_size > 0))
815 #if defined(MAGICKCORE_HAVE_LINUX_SENDFILE)
816 if (cache_info->length < 0x7ffff000)
818 count=sendfile(clone_info->file,cache_info->file,(off_t *) NULL,
819 (
size_t) cache_info->length);
820 if (count == (ssize_t) cache_info->length)
822 if ((lseek(cache_info->file,0,SEEK_SET) < 0) ||
823 (lseek(clone_info->file,0,SEEK_SET) < 0))
827 quantum=(size_t) MagickMin(file_stats.st_size,MagickMaxBufferExtent);
829 buffer=(
unsigned char *) AcquireQuantumMemory(quantum,
sizeof(*buffer));
830 if (buffer == (
unsigned char *) NULL)
831 ThrowFatalException(ResourceLimitFatalError,
"MemoryAllocationFailed");
833 while ((count=read(cache_info->file,buffer,quantum)) > 0)
838 number_bytes=write(clone_info->file,buffer,(
size_t) count);
839 if (number_bytes != count)
841 extent+=number_bytes;
843 buffer=(
unsigned char *) RelinquishMagickMemory(buffer);
844 if (extent != cache_info->length)
849 static MagickBooleanType ClonePixelCacheRepository(
853 #define MaxCacheThreads ((size_t) GetMagickResourceLimit(ThreadResource))
854 #define cache_number_threads(source,destination,chunk,multithreaded) \
855 num_threads((multithreaded) == 0 ? 1 : \
856 (((source)->type != MemoryCache) && ((source)->type != MapCache)) || \
857 (((destination)->type != MemoryCache) && ((destination)->type != MapCache)) ? \
858 MagickMax(MagickMin((ssize_t) GetMagickResourceLimit(ThreadResource),2),1) : \
859 MagickMax(MagickMin((ssize_t) GetMagickResourceLimit(ThreadResource),(ssize_t) (chunk)/256),1))
865 **magick_restrict cache_nexus,
866 **magick_restrict clone_nexus;
874 assert(cache_info != (
CacheInfo *) NULL);
875 assert(clone_info != (
CacheInfo *) NULL);
877 if (cache_info->type == PingCache)
879 if ((cache_info->storage_class == clone_info->storage_class) &&
880 (cache_info->colorspace == clone_info->colorspace) &&
881 (cache_info->channels == clone_info->channels) &&
882 (cache_info->columns == clone_info->columns) &&
883 (cache_info->rows == clone_info->rows) &&
884 (cache_info->active_index_channel == clone_info->active_index_channel))
889 if (((cache_info->type == MemoryCache) ||
890 (cache_info->type == MapCache)) &&
891 ((clone_info->type == MemoryCache) ||
892 (clone_info->type == MapCache)))
894 (void) memcpy(clone_info->pixels,cache_info->pixels,
895 cache_info->columns*cache_info->rows*
sizeof(*cache_info->pixels));
896 if ((cache_info->active_index_channel != MagickFalse) &&
897 (clone_info->active_index_channel != MagickFalse))
898 (void) memcpy(clone_info->indexes,cache_info->indexes,
899 cache_info->columns*cache_info->rows*
900 sizeof(*cache_info->indexes));
903 if ((cache_info->type == DiskCache) && (clone_info->type == DiskCache))
904 return(ClonePixelCacheOnDisk(cache_info,clone_info));
909 cache_nexus=AcquirePixelCacheNexus(cache_info->number_threads);
910 clone_nexus=AcquirePixelCacheNexus(clone_info->number_threads);
911 length=(size_t) MagickMin(cache_info->columns,clone_info->columns)*
912 sizeof(*cache_info->pixels);
914 #if defined(MAGICKCORE_OPENMP_SUPPORT)
915 #pragma omp parallel for schedule(static) shared(status) \
916 cache_number_threads(cache_info,clone_info,cache_info->rows,1)
918 for (y=0; y < (ssize_t) cache_info->rows; y++)
921 id = GetOpenMPThreadId();
926 if (status == MagickFalse)
928 if (y >= (ssize_t) clone_info->rows)
930 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,0,y,
931 cache_info->columns,1,MagickFalse,cache_nexus[
id],exception);
934 status=ReadPixelCachePixels(cache_info,cache_nexus[
id],exception);
935 if (status == MagickFalse)
937 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,0,y,
938 clone_info->columns,1,MagickFalse,clone_nexus[
id],exception);
941 (void) memset(clone_nexus[
id]->pixels,0,(
size_t) clone_nexus[id]->length);
942 (void) memcpy(clone_nexus[
id]->pixels,cache_nexus[
id]->pixels,length);
943 status=WritePixelCachePixels(clone_info,clone_nexus[
id],exception);
945 if ((cache_info->active_index_channel != MagickFalse) &&
946 (clone_info->active_index_channel != MagickFalse))
951 length=(size_t) MagickMin(cache_info->columns,clone_info->columns)*
952 sizeof(*cache_info->indexes);
953 #if defined(MAGICKCORE_OPENMP_SUPPORT)
954 #pragma omp parallel for schedule(static) shared(status) \
955 cache_number_threads(cache_info,clone_info,cache_info->rows,1)
957 for (y=0; y < (ssize_t) cache_info->rows; y++)
960 id = GetOpenMPThreadId();
965 if (status == MagickFalse)
967 if (y >= (ssize_t) clone_info->rows)
969 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,0,y,
970 cache_info->columns,1,MagickFalse,cache_nexus[
id],exception);
973 status=ReadPixelCacheIndexes(cache_info,cache_nexus[
id],exception);
974 if (status == MagickFalse)
976 pixels=SetPixelCacheNexusPixels(clone_info,WriteMode,0,y,
977 clone_info->columns,1,MagickFalse,clone_nexus[
id],exception);
980 (void) memcpy(clone_nexus[
id]->indexes,cache_nexus[
id]->indexes,length);
981 status=WritePixelCacheIndexes(clone_info,clone_nexus[
id],exception);
984 clone_nexus=DestroyPixelCacheNexus(clone_nexus,clone_info->number_threads);
985 cache_nexus=DestroyPixelCacheNexus(cache_nexus,cache_info->number_threads);
986 if (cache_info->debug != MagickFalse)
989 message[MaxTextExtent];
991 (void) FormatLocaleString(message,MaxTextExtent,
"%s => %s",
992 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) cache_info->type),
993 CommandOptionToMnemonic(MagickCacheOptions,(ssize_t) clone_info->type));
994 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",message);
1021 static void DestroyImagePixelCache(
Image *image)
1023 assert(image != (
Image *) NULL);
1024 assert(image->signature == MagickCoreSignature);
1025 if (IsEventLogging() != MagickFalse)
1026 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1027 if (image->cache != (
void *) NULL)
1028 image->cache=DestroyPixelCache(image->cache);
1053 MagickExport
void DestroyImagePixels(
Image *image)
1056 *magick_restrict cache_info;
1058 assert(image != (
const Image *) NULL);
1059 assert(image->signature == MagickCoreSignature);
1060 if (IsEventLogging() != MagickFalse)
1061 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1062 assert(image->cache != (Cache) NULL);
1064 assert(cache_info->signature == MagickCoreSignature);
1065 if (cache_info->methods.destroy_pixel_handler != (DestroyPixelHandler) NULL)
1067 cache_info->methods.destroy_pixel_handler(image);
1070 image->cache=DestroyPixelCache(image->cache);
1096 static MagickBooleanType ClosePixelCacheOnDisk(
CacheInfo *cache_info)
1102 if (cache_info->file != -1)
1104 status=close(cache_info->file);
1105 cache_info->file=(-1);
1106 RelinquishMagickResource(FileResource,1);
1108 return(status == -1 ? MagickFalse : MagickTrue);
1111 static inline void RelinquishPixelCachePixels(
CacheInfo *cache_info)
1113 switch (cache_info->type)
1117 (void) ShredMagickMemory(cache_info->pixels,(
size_t) cache_info->length);
1118 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1119 if (RelinquishOpenCLBuffer(cache_info) != MagickFalse)
1125 if (cache_info->mapped == MagickFalse)
1126 cache_info->pixels=(
PixelPacket *) RelinquishAlignedMemory(
1127 cache_info->pixels);
1130 (void) UnmapBlob(cache_info->pixels,(
size_t) cache_info->length);
1133 RelinquishMagickResource(MemoryResource,cache_info->length);
1138 (void) UnmapBlob(cache_info->pixels,(
size_t) cache_info->length);
1140 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
1141 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1142 *cache_info->cache_filename=
'\0';
1143 RelinquishMagickResource(MapResource,cache_info->length);
1148 if (cache_info->file != -1)
1149 (void) ClosePixelCacheOnDisk(cache_info);
1150 if ((cache_info->mode != ReadMode) && (cache_info->mode != PersistMode))
1151 (void) RelinquishUniqueFileResource(cache_info->cache_filename);
1152 *cache_info->cache_filename=
'\0';
1153 RelinquishMagickResource(DiskResource,cache_info->length);
1156 case DistributedCache:
1158 *cache_info->cache_filename=
'\0';
1160 cache_info->server_info);
1166 cache_info->type=UndefinedCache;
1167 cache_info->mapped=MagickFalse;
1168 cache_info->indexes=(IndexPacket *) NULL;
1171 MagickExport Cache DestroyPixelCache(Cache cache)
1174 *magick_restrict cache_info;
1176 assert(cache != (Cache) NULL);
1178 assert(cache_info->signature == MagickCoreSignature);
1179 if (IsEventLogging() != MagickFalse)
1180 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
1181 cache_info->filename);
1182 LockSemaphoreInfo(cache_info->semaphore);
1183 cache_info->reference_count--;
1184 if (cache_info->reference_count != 0)
1186 UnlockSemaphoreInfo(cache_info->semaphore);
1187 return((Cache) NULL);
1189 UnlockSemaphoreInfo(cache_info->semaphore);
1190 if (cache_info->debug != MagickFalse)
1193 message[MaxTextExtent];
1195 (void) FormatLocaleString(message,MaxTextExtent,
"destroy %s",
1196 cache_info->filename);
1197 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",message);
1199 RelinquishPixelCachePixels(cache_info);
1202 cache_info->server_info);
1203 if (cache_info->nexus_info != (
NexusInfo **) NULL)
1204 cache_info->nexus_info=DestroyPixelCacheNexus(cache_info->nexus_info,
1205 cache_info->number_threads);
1206 if (cache_info->random_info != (
RandomInfo *) NULL)
1207 cache_info->random_info=DestroyRandomInfo(cache_info->random_info);
1209 DestroySemaphoreInfo(&cache_info->file_semaphore);
1211 DestroySemaphoreInfo(&cache_info->semaphore);
1212 cache_info->signature=(~MagickCoreSignature);
1213 cache_info=(
CacheInfo *) RelinquishAlignedMemory(cache_info);
1244 static inline void RelinquishCacheNexusPixels(
NexusInfo *nexus_info)
1246 if (nexus_info->mapped == MagickFalse)
1247 (void) RelinquishAlignedMemory(nexus_info->cache);
1249 (
void) UnmapBlob(nexus_info->cache,(
size_t) nexus_info->length);
1252 nexus_info->indexes=(IndexPacket *) NULL;
1253 nexus_info->length=0;
1254 nexus_info->mapped=MagickFalse;
1258 const size_t number_threads)
1263 assert(nexus_info != (
NexusInfo **) NULL);
1264 for (i=0; i < (ssize_t) (2*number_threads); i++)
1267 RelinquishCacheNexusPixels(nexus_info[i]);
1268 nexus_info[i]->signature=(~MagickCoreSignature);
1270 *nexus_info=(
NexusInfo *) RelinquishMagickMemory(*nexus_info);
1271 nexus_info=(
NexusInfo **) RelinquishAlignedMemory(nexus_info);
1298 static IndexPacket *GetAuthenticIndexesFromCache(
const Image *image)
1301 *magick_restrict cache_info;
1304 id = GetOpenMPThreadId();
1306 assert(image != (
const Image *) NULL);
1307 assert(image->signature == MagickCoreSignature);
1308 assert(image->cache != (Cache) NULL);
1310 assert(cache_info->signature == MagickCoreSignature);
1311 assert(
id < (
int) cache_info->number_threads);
1312 return(cache_info->nexus_info[
id]->indexes);
1340 MagickExport IndexPacket *GetAuthenticIndexQueue(
const Image *image)
1343 *magick_restrict cache_info;
1346 id = GetOpenMPThreadId();
1348 assert(image != (
const Image *) NULL);
1349 assert(image->signature == MagickCoreSignature);
1350 assert(image->cache != (Cache) NULL);
1352 assert(cache_info->signature == MagickCoreSignature);
1353 if (cache_info->methods.get_authentic_indexes_from_handler !=
1354 (GetAuthenticIndexesFromHandler) NULL)
1355 return(cache_info->methods.get_authentic_indexes_from_handler(image));
1356 assert(
id < (
int) cache_info->number_threads);
1357 return(cache_info->nexus_info[
id]->indexes);
1360 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1384 MagickPrivate cl_mem GetAuthenticOpenCLBuffer(
const Image *image,
1388 *magick_restrict cache_info;
1399 assert(image != (
const Image *) NULL);
1401 if ((cache_info->type == UndefinedCache) || (cache_info->reference_count > 1))
1403 SyncImagePixelCache((
Image *) image,exception);
1406 if ((cache_info->type != MemoryCache) || (cache_info->mapped != MagickFalse))
1407 return((cl_mem) NULL);
1408 LockSemaphoreInfo(cache_info->semaphore);
1409 clEnv=GetDefaultOpenCLEnv();
1412 assert(cache_info->pixels != NULL);
1413 context=GetOpenCLContext(clEnv);
1415 sizeof(*cache_info->opencl));
1416 (void) memset(cache_info->opencl,0,
sizeof(*cache_info->opencl));
1417 cache_info->opencl->events_semaphore=AllocateSemaphoreInfo();
1418 cache_info->opencl->length=cache_info->length;
1419 cache_info->opencl->pixels=cache_info->pixels;
1420 cache_info->opencl->buffer=clEnv->library->clCreateBuffer(context,
1421 CL_MEM_USE_HOST_PTR,cache_info->length,cache_info->pixels,&status);
1422 if (status != CL_SUCCESS)
1423 cache_info->opencl=RelinquishOpenCLCacheInfo(clEnv,cache_info->opencl);
1426 clEnv->library->clRetainMemObject(cache_info->opencl->buffer);
1427 UnlockSemaphoreInfo(cache_info->semaphore);
1429 return((cl_mem) NULL);
1430 return(cache_info->opencl->buffer);
1470 const ssize_t x,
const ssize_t y,
const size_t columns,
const size_t rows,
1474 *magick_restrict cache_info;
1477 *magick_restrict pixels;
1482 assert(image != (
Image *) NULL);
1483 assert(image->signature == MagickCoreSignature);
1484 pixels=QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickTrue,
1485 nexus_info,exception);
1489 assert(cache_info->signature == MagickCoreSignature);
1490 if (nexus_info->authentic_pixel_cache != MagickFalse)
1492 if (ReadPixelCachePixels(cache_info,nexus_info,exception) == MagickFalse)
1494 if (cache_info->active_index_channel != MagickFalse)
1495 if (ReadPixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse)
1526 *magick_restrict cache_info;
1529 id = GetOpenMPThreadId();
1531 assert(image != (
const Image *) NULL);
1532 assert(image->signature == MagickCoreSignature);
1533 assert(image->cache != (Cache) NULL);
1535 assert(cache_info->signature == MagickCoreSignature);
1536 assert(
id < (
int) cache_info->number_threads);
1537 return(cache_info->nexus_info[
id]->pixels);
1566 *magick_restrict cache_info;
1569 id = GetOpenMPThreadId();
1571 assert(image != (
const Image *) NULL);
1572 assert(image->signature == MagickCoreSignature);
1573 assert(image->cache != (Cache) NULL);
1575 assert(cache_info->signature == MagickCoreSignature);
1576 if (cache_info->methods.get_authentic_pixels_from_handler !=
1577 (GetAuthenticPixelsFromHandler) NULL)
1578 return(cache_info->methods.get_authentic_pixels_from_handler(image));
1579 assert(
id < (
int) cache_info->number_threads);
1580 return(cache_info->nexus_info[
id]->pixels);
1630 const ssize_t y,
const size_t columns,
const size_t rows,
1634 *magick_restrict cache_info;
1637 id = GetOpenMPThreadId();
1639 assert(image != (
Image *) NULL);
1640 assert(image->signature == MagickCoreSignature);
1641 assert(image->cache != (Cache) NULL);
1643 assert(cache_info->signature == MagickCoreSignature);
1644 if (cache_info->methods.get_authentic_pixels_handler !=
1645 (GetAuthenticPixelsHandler) NULL)
1646 return(cache_info->methods.get_authentic_pixels_handler(image,x,y,columns,
1648 assert(
id < (
int) cache_info->number_threads);
1649 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1650 cache_info->nexus_info[
id],exception));
1685 const ssize_t y,
const size_t columns,
const size_t rows,
1689 *magick_restrict cache_info;
1692 id = GetOpenMPThreadId();
1694 assert(image != (
const Image *) NULL);
1695 assert(image->signature == MagickCoreSignature);
1696 assert(image->cache != (Cache) NULL);
1698 if (cache_info == (Cache) NULL)
1700 assert(cache_info->signature == MagickCoreSignature);
1701 assert(
id < (
int) cache_info->number_threads);
1702 return(GetAuthenticPixelCacheNexus(image,x,y,columns,rows,
1703 cache_info->nexus_info[
id],exception));
1729 MagickExport MagickSizeType GetImageExtent(
const Image *image)
1732 *magick_restrict cache_info;
1735 id = GetOpenMPThreadId();
1737 assert(image != (
Image *) NULL);
1738 assert(image->signature == MagickCoreSignature);
1739 if (IsEventLogging() != MagickFalse)
1740 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
1741 assert(image->cache != (Cache) NULL);
1743 assert(cache_info->signature == MagickCoreSignature);
1744 assert(
id < (
int) cache_info->number_threads);
1745 return(GetPixelCacheNexusExtent(cache_info,cache_info->nexus_info[
id]));
1748 #if defined(MAGICKCORE_OPENCL_SUPPORT)
1776 extern MagickPrivate cl_event *GetOpenCLEvents(
const Image *image,
1777 cl_uint *event_count)
1780 *magick_restrict cache_info;
1785 assert(image != (
const Image *) NULL);
1786 assert(event_count != (cl_uint *) NULL);
1789 events=(cl_event *) NULL;
1791 events=CopyOpenCLEvents(cache_info->opencl,event_count);
1826 static inline MagickBooleanType ValidatePixelCacheMorphology(
1827 const Image *magick_restrict image)
1830 *magick_restrict cache_info;
1836 if ((image->storage_class != cache_info->storage_class) ||
1837 (image->colorspace != cache_info->colorspace) ||
1838 (image->channels != cache_info->channels) ||
1839 (image->columns != cache_info->columns) ||
1840 (image->rows != cache_info->rows) ||
1841 (cache_info->nexus_info == (
NexusInfo **) NULL))
1842 return(MagickFalse);
1846 static Cache GetImagePixelCache(
Image *image,
const MagickBooleanType clone,
1850 *magick_restrict cache_info;
1856 static MagickSizeType
1857 cache_timelimit = MagickResourceInfinity,
1858 cpu_throttle = MagickResourceInfinity,
1862 if (cpu_throttle == MagickResourceInfinity)
1863 cpu_throttle=GetMagickResourceLimit(ThrottleResource);
1864 if ((cpu_throttle != 0) && ((cycles++ % 32) == 0))
1865 MagickDelay(cpu_throttle);
1866 if (cache_epoch == 0)
1871 cache_epoch=GetMagickTime();
1872 cache_timelimit=GetMagickResourceLimit(TimeResource);
1874 if ((cache_timelimit != MagickResourceInfinity) &&
1875 ((MagickSizeType) (GetMagickTime()-cache_epoch) >= cache_timelimit))
1877 #if defined(ECANCELED)
1881 if (cache_info->file != -1)
1882 (void) ClosePixelCacheOnDisk(cache_info);
1883 (void) ThrowMagickException(exception,GetMagickModule(),
1884 ResourceLimitFatalError,
"TimeLimitExceeded",
"`%s'",image->filename);
1885 return((Cache) NULL);
1887 LockSemaphoreInfo(image->semaphore);
1888 assert(image->cache != (Cache) NULL);
1890 #
if defined(MAGICKCORE_OPENCL_SUPPORT)
1891 CopyOpenCLBuffer(cache_info);
1893 destroy=MagickFalse;
1894 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1896 LockSemaphoreInfo(cache_info->semaphore);
1897 if ((cache_info->reference_count > 1) || (cache_info->mode == ReadMode))
1908 clone_image=(*image);
1909 clone_image.semaphore=AllocateSemaphoreInfo();
1910 clone_image.reference_count=1;
1911 clone_image.cache=ClonePixelCache(cache_info);
1912 clone_info=(
CacheInfo *) clone_image.cache;
1913 status=OpenPixelCache(&clone_image,IOMode,exception);
1914 if (status == MagickFalse)
1915 clone_info=(
CacheInfo *) DestroyPixelCache(clone_info);
1918 if (clone != MagickFalse)
1919 status=ClonePixelCacheRepository(clone_info,cache_info,
1921 if (status == MagickFalse)
1922 clone_info=(
CacheInfo *) DestroyPixelCache(clone_info);
1926 image->cache=clone_info;
1929 DestroySemaphoreInfo(&clone_image.semaphore);
1931 UnlockSemaphoreInfo(cache_info->semaphore);
1933 if (destroy != MagickFalse)
1934 cache_info=(
CacheInfo *) DestroyPixelCache(cache_info);
1935 if (status != MagickFalse)
1940 if (image->type != UndefinedType)
1941 image->type=UndefinedType;
1942 if (ValidatePixelCacheMorphology(image) == MagickFalse)
1944 status=OpenPixelCache(image,IOMode,exception);
1946 if (cache_info->file != -1)
1947 (void) ClosePixelCacheOnDisk(cache_info);
1950 UnlockSemaphoreInfo(image->semaphore);
1951 if (status == MagickFalse)
1952 return((Cache) NULL);
1953 return(image->cache);
1980 MagickExport CacheType GetPixelCacheType(
const Image *image)
1982 return(GetImagePixelCacheType(image));
1985 MagickExport CacheType GetImagePixelCacheType(
const Image *image)
1988 *magick_restrict cache_info;
1990 assert(image != (
Image *) NULL);
1991 assert(image->signature == MagickCoreSignature);
1992 assert(image->cache != (Cache) NULL);
1994 assert(cache_info->signature == MagickCoreSignature);
1995 return(cache_info->type);
2028 MagickExport MagickBooleanType GetOneAuthenticPixel(
Image *image,
2032 *magick_restrict cache_info;
2035 *magick_restrict pixels;
2037 assert(image != (
Image *) NULL);
2038 assert(image->signature == MagickCoreSignature);
2039 assert(image->cache != (Cache) NULL);
2041 assert(cache_info->signature == MagickCoreSignature);
2042 *pixel=image->background_color;
2043 if (cache_info->methods.get_one_authentic_pixel_from_handler != (GetOneAuthenticPixelFromHandler) NULL)
2044 return(cache_info->methods.get_one_authentic_pixel_from_handler(image,x,y,pixel,exception));
2045 pixels=GetAuthenticPixelsCache(image,x,y,1UL,1UL,exception);
2047 return(MagickFalse);
2083 static MagickBooleanType GetOneAuthenticPixelFromCache(
Image *image,
2087 *magick_restrict cache_info;
2090 id = GetOpenMPThreadId();
2093 *magick_restrict pixels;
2095 assert(image != (
const Image *) NULL);
2096 assert(image->signature == MagickCoreSignature);
2097 assert(image->cache != (Cache) NULL);
2099 assert(cache_info->signature == MagickCoreSignature);
2100 *pixel=image->background_color;
2101 assert(
id < (
int) cache_info->number_threads);
2102 pixels=GetAuthenticPixelCacheNexus(image,x,y,1UL,1UL,
2103 cache_info->nexus_info[
id],exception);
2105 return(MagickFalse);
2142 MagickExport MagickBooleanType GetOneVirtualMagickPixel(
const Image *image,
2147 *magick_restrict cache_info;
2150 id = GetOpenMPThreadId();
2153 *magick_restrict indexes;
2156 *magick_restrict pixels;
2158 assert(image != (
const Image *) NULL);
2159 assert(image->signature == MagickCoreSignature);
2160 assert(image->cache != (Cache) NULL);
2162 assert(cache_info->signature == MagickCoreSignature);
2163 assert(
id < (
int) cache_info->number_threads);
2164 pixels=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2165 1UL,1UL,cache_info->nexus_info[
id],exception);
2166 GetMagickPixelPacket(image,pixel);
2168 return(MagickFalse);
2169 indexes=GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[
id]);
2170 SetMagickPixelPacket(image,pixels,indexes,pixel);
2209 MagickExport MagickBooleanType GetOneVirtualMethodPixel(
const Image *image,
2210 const VirtualPixelMethod virtual_pixel_method,
const ssize_t x,
const ssize_t y,
2214 *magick_restrict cache_info;
2217 id = GetOpenMPThreadId();
2220 *magick_restrict pixels;
2222 assert(image != (
const Image *) NULL);
2223 assert(image->signature == MagickCoreSignature);
2224 assert(image->cache != (Cache) NULL);
2226 assert(cache_info->signature == MagickCoreSignature);
2227 *pixel=image->background_color;
2228 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2229 (GetOneVirtualPixelFromHandler) NULL)
2230 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2231 virtual_pixel_method,x,y,pixel,exception));
2232 assert(
id < (
int) cache_info->number_threads);
2233 pixels=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2234 cache_info->nexus_info[
id],exception);
2236 return(MagickFalse);
2272 MagickExport MagickBooleanType GetOneVirtualPixel(
const Image *image,
2276 *magick_restrict cache_info;
2279 id = GetOpenMPThreadId();
2282 *magick_restrict pixels;
2284 assert(image != (
const Image *) NULL);
2285 assert(image->signature == MagickCoreSignature);
2286 assert(image->cache != (Cache) NULL);
2288 assert(cache_info->signature == MagickCoreSignature);
2289 *pixel=image->background_color;
2290 if (cache_info->methods.get_one_virtual_pixel_from_handler !=
2291 (GetOneVirtualPixelFromHandler) NULL)
2292 return(cache_info->methods.get_one_virtual_pixel_from_handler(image,
2293 GetPixelCacheVirtualMethod(image),x,y,pixel,exception));
2294 assert(
id < (
int) cache_info->number_threads);
2295 pixels=GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
2296 1UL,1UL,cache_info->nexus_info[
id],exception);
2298 return(MagickFalse);
2337 static MagickBooleanType GetOneVirtualPixelFromCache(
const Image *image,
2338 const VirtualPixelMethod virtual_pixel_method,
const ssize_t x,
const ssize_t y,
2342 *magick_restrict cache_info;
2345 id = GetOpenMPThreadId();
2348 *magick_restrict pixels;
2350 assert(image != (
const Image *) NULL);
2351 assert(image->signature == MagickCoreSignature);
2352 assert(image->cache != (Cache) NULL);
2354 assert(cache_info->signature == MagickCoreSignature);
2355 assert(
id < (
int) cache_info->number_threads);
2356 *pixel=image->background_color;
2357 pixels=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,1UL,1UL,
2358 cache_info->nexus_info[
id],exception);
2360 return(MagickFalse);
2390 MagickExport
size_t GetPixelCacheChannels(
const Cache cache)
2393 *magick_restrict cache_info;
2395 assert(cache != (Cache) NULL);
2397 assert(cache_info->signature == MagickCoreSignature);
2398 if (IsEventLogging() != MagickFalse)
2399 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
2400 cache_info->filename);
2401 return(cache_info->channels);
2426 MagickExport ColorspaceType GetPixelCacheColorspace(
const Cache cache)
2429 *magick_restrict cache_info;
2431 assert(cache != (Cache) NULL);
2433 assert(cache_info->signature == MagickCoreSignature);
2434 if (IsEventLogging() != MagickFalse)
2435 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
2436 cache_info->filename);
2437 return(cache_info->colorspace);
2463 MagickExport
const char *GetPixelCacheFilename(
const Image *image)
2466 *magick_restrict cache_info;
2468 assert(image != (
const Image *) NULL);
2469 assert(image->signature == MagickCoreSignature);
2470 assert(image->cache != (Cache) NULL);
2472 assert(cache_info->signature == MagickCoreSignature);
2473 return(cache_info->cache_filename);
2498 MagickExport
void GetPixelCacheMethods(
CacheMethods *cache_methods)
2501 (void) memset(cache_methods,0,
sizeof(*cache_methods));
2502 cache_methods->get_virtual_pixel_handler=GetVirtualPixelCache;
2503 cache_methods->get_virtual_pixels_handler=GetVirtualPixelsCache;
2504 cache_methods->get_virtual_indexes_from_handler=GetVirtualIndexesFromCache;
2505 cache_methods->get_one_virtual_pixel_from_handler=GetOneVirtualPixelFromCache;
2506 cache_methods->get_authentic_pixels_handler=GetAuthenticPixelsCache;
2507 cache_methods->get_authentic_indexes_from_handler=
2508 GetAuthenticIndexesFromCache;
2509 cache_methods->get_authentic_pixels_from_handler=GetAuthenticPixelsFromCache;
2510 cache_methods->get_one_authentic_pixel_from_handler=
2511 GetOneAuthenticPixelFromCache;
2512 cache_methods->queue_authentic_pixels_handler=QueueAuthenticPixelsCache;
2513 cache_methods->sync_authentic_pixels_handler=SyncAuthenticPixelsCache;
2514 cache_methods->destroy_pixel_handler=DestroyImagePixelCache;
2541 MagickExport MagickSizeType GetPixelCacheNexusExtent(
const Cache cache,
2545 *magick_restrict cache_info;
2550 assert(cache != NULL);
2552 assert(cache_info->signature == MagickCoreSignature);
2553 extent=(MagickSizeType) nexus_info->region.width*nexus_info->region.height;
2555 return((MagickSizeType) cache_info->columns*cache_info->rows);
2586 MagickExport
void *GetPixelCachePixels(
Image *image,MagickSizeType *length,
2590 *magick_restrict cache_info;
2592 assert(image != (
const Image *) NULL);
2593 assert(image->signature == MagickCoreSignature);
2594 assert(image->cache != (Cache) NULL);
2595 assert(length != (MagickSizeType *) NULL);
2597 assert(exception->signature == MagickCoreSignature);
2599 assert(cache_info->signature == MagickCoreSignature);
2601 *length=cache_info->length;
2602 if ((cache_info->type != MemoryCache) && (cache_info->type != MapCache))
2603 return((
void *) NULL);
2604 return((
void *) cache_info->pixels);
2631 MagickExport ClassType GetPixelCacheStorageClass(
const Cache cache)
2634 *magick_restrict cache_info;
2636 assert(cache != (Cache) NULL);
2638 assert(cache_info->signature == MagickCoreSignature);
2639 if (IsEventLogging() != MagickFalse)
2640 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
2641 cache_info->filename);
2642 return(cache_info->storage_class);
2672 MagickExport
void GetPixelCacheTileSize(
const Image *image,
size_t *width,
2675 assert(image != (
Image *) NULL);
2676 assert(image->signature == MagickCoreSignature);
2677 if (IsEventLogging() != MagickFalse)
2678 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
2680 if (GetImagePixelCacheType(image) == DiskCache)
2709 MagickExport VirtualPixelMethod GetPixelCacheVirtualMethod(
const Image *image)
2712 *magick_restrict cache_info;
2714 assert(image != (
Image *) NULL);
2715 assert(image->signature == MagickCoreSignature);
2716 assert(image->cache != (Cache) NULL);
2718 assert(cache_info->signature == MagickCoreSignature);
2719 return(cache_info->virtual_pixel_method);
2745 static const IndexPacket *GetVirtualIndexesFromCache(
const Image *image)
2748 *magick_restrict cache_info;
2751 id = GetOpenMPThreadId();
2753 assert(image != (
const Image *) NULL);
2754 assert(image->signature == MagickCoreSignature);
2755 assert(image->cache != (Cache) NULL);
2757 assert(cache_info->signature == MagickCoreSignature);
2758 assert(
id < (
int) cache_info->number_threads);
2759 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[
id]));
2788 MagickExport
const IndexPacket *GetVirtualIndexesFromNexus(
const Cache cache,
2792 *magick_restrict cache_info;
2794 assert(cache != (Cache) NULL);
2796 assert(cache_info->signature == MagickCoreSignature);
2797 if (cache_info->storage_class == UndefinedClass)
2798 return((IndexPacket *) NULL);
2799 return(nexus_info->indexes);
2827 MagickExport
const IndexPacket *GetVirtualIndexQueue(
const Image *image)
2830 *magick_restrict cache_info;
2833 id = GetOpenMPThreadId();
2835 assert(image != (
const Image *) NULL);
2836 assert(image->signature == MagickCoreSignature);
2837 assert(image->cache != (Cache) NULL);
2839 assert(cache_info->signature == MagickCoreSignature);
2840 if (cache_info->methods.get_virtual_indexes_from_handler !=
2841 (GetVirtualIndexesFromHandler) NULL)
2842 return(cache_info->methods.get_virtual_indexes_from_handler(image));
2843 assert(
id < (
int) cache_info->number_threads);
2844 return(GetVirtualIndexesFromNexus(cache_info,cache_info->nexus_info[
id]));
2887 0, 48, 12, 60, 3, 51, 15, 63,
2888 32, 16, 44, 28, 35, 19, 47, 31,
2889 8, 56, 4, 52, 11, 59, 7, 55,
2890 40, 24, 36, 20, 43, 27, 39, 23,
2891 2, 50, 14, 62, 1, 49, 13, 61,
2892 34, 18, 46, 30, 33, 17, 45, 29,
2893 10, 58, 6, 54, 9, 57, 5, 53,
2894 42, 26, 38, 22, 41, 25, 37, 21
2897 static inline ssize_t DitherX(
const ssize_t x,
const size_t columns)
2902 index=x+DitherMatrix[x & 0x07]-32L;
2905 if (index >= (ssize_t) columns)
2906 return((ssize_t) columns-1L);
2910 static inline ssize_t DitherY(
const ssize_t y,
const size_t rows)
2915 index=y+DitherMatrix[y & 0x07]-32L;
2918 if (index >= (ssize_t) rows)
2919 return((ssize_t) rows-1L);
2923 static inline ssize_t EdgeX(
const ssize_t x,
const size_t columns)
2927 if (x >= (ssize_t) columns)
2928 return((ssize_t) (columns-1));
2932 static inline ssize_t EdgeY(
const ssize_t y,
const size_t rows)
2936 if (y >= (ssize_t) rows)
2937 return((ssize_t) (rows-1));
2941 static inline ssize_t RandomX(
RandomInfo *random_info,
const size_t columns)
2943 return((ssize_t) (columns*GetPseudoRandomValue(random_info)));
2946 static inline ssize_t RandomY(
RandomInfo *random_info,
const size_t rows)
2948 return((ssize_t) (rows*GetPseudoRandomValue(random_info)));
2951 static inline MagickModulo VirtualPixelModulo(
const ssize_t offset,
2952 const size_t extent)
2957 modulo.quotient=offset;
2961 modulo.quotient=offset/((ssize_t) extent);
2962 modulo.remainder=offset % ((ssize_t) extent);
2964 if ((modulo.remainder != 0) && ((offset ^ ((ssize_t) extent)) < 0))
2967 modulo.remainder+=((ssize_t) extent);
2972 MagickExport
const PixelPacket *GetVirtualPixelCacheNexus(
const Image *image,
2973 const VirtualPixelMethod virtual_pixel_method,
const ssize_t x,
const ssize_t y,
2974 const size_t columns,
const size_t rows,
NexusInfo *nexus_info,
2978 *magick_restrict cache_info;
2981 *magick_restrict virtual_indexes;
2988 *magick_restrict indexes;
2998 *magick_restrict virtual_nexus;
3001 *magick_restrict pixels,
3012 assert(image != (
const Image *) NULL);
3013 assert(image->signature == MagickCoreSignature);
3014 assert(image->cache != (Cache) NULL);
3016 assert(cache_info->signature == MagickCoreSignature);
3017 if (cache_info->type == UndefinedCache)
3019 #if defined(MAGICKCORE_OPENCL_SUPPORT)
3020 CopyOpenCLBuffer(cache_info);
3022 pixels=SetPixelCacheNexusPixels(cache_info,ReadMode,x,y,columns,rows,
3023 (image->clip_mask != (
Image *) NULL) || (image->mask != (
Image *) NULL) ?
3024 MagickTrue : MagickFalse,nexus_info,exception);
3027 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
3028 nexus_info->region.x;
3029 length=(MagickSizeType) (nexus_info->region.height-1L)*cache_info->columns+
3030 nexus_info->region.width-1L;
3031 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3032 if ((offset >= 0) && (((MagickSizeType) offset+length) < number_pixels))
3033 if ((x >= 0) && ((ssize_t) (x+columns) <= (ssize_t) cache_info->columns) &&
3034 (y >= 0) && ((ssize_t) (y+rows) <= (ssize_t) cache_info->rows))
3042 if (nexus_info->authentic_pixel_cache != MagickFalse)
3044 status=ReadPixelCachePixels(cache_info,nexus_info,exception);
3045 if (status == MagickFalse)
3047 if ((cache_info->storage_class == PseudoClass) ||
3048 (cache_info->colorspace == CMYKColorspace))
3050 status=ReadPixelCacheIndexes(cache_info,nexus_info,exception);
3051 if (status == MagickFalse)
3059 virtual_nexus=nexus_info->virtual_nexus;
3061 indexes=nexus_info->indexes;
3062 switch (virtual_pixel_method)
3064 case BlackVirtualPixelMethod:
3066 SetPixelRed(&virtual_pixel,0);
3067 SetPixelGreen(&virtual_pixel,0);
3068 SetPixelBlue(&virtual_pixel,0);
3069 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3072 case GrayVirtualPixelMethod:
3074 SetPixelRed(&virtual_pixel,QuantumRange/2);
3075 SetPixelGreen(&virtual_pixel,QuantumRange/2);
3076 SetPixelBlue(&virtual_pixel,QuantumRange/2);
3077 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3080 case TransparentVirtualPixelMethod:
3082 SetPixelRed(&virtual_pixel,0);
3083 SetPixelGreen(&virtual_pixel,0);
3084 SetPixelBlue(&virtual_pixel,0);
3085 SetPixelOpacity(&virtual_pixel,TransparentOpacity);
3088 case MaskVirtualPixelMethod:
3089 case WhiteVirtualPixelMethod:
3091 SetPixelRed(&virtual_pixel,QuantumRange);
3092 SetPixelGreen(&virtual_pixel,QuantumRange);
3093 SetPixelBlue(&virtual_pixel,QuantumRange);
3094 SetPixelOpacity(&virtual_pixel,OpaqueOpacity);
3099 virtual_pixel=image->background_color;
3103 virtual_index=(IndexPacket) 0;
3104 for (v=0; v < (ssize_t) rows; v++)
3110 if ((virtual_pixel_method == EdgeVirtualPixelMethod) ||
3111 (virtual_pixel_method == UndefinedVirtualPixelMethod))
3112 y_offset=EdgeY(y_offset,cache_info->rows);
3113 for (u=0; u < (ssize_t) columns; u+=length)
3119 length=(MagickSizeType) MagickMin(cache_info->columns-x_offset,columns-u);
3120 if (((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns)) ||
3121 ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows)) ||
3131 length=(MagickSizeType) 1;
3132 switch (virtual_pixel_method)
3134 case BackgroundVirtualPixelMethod:
3135 case ConstantVirtualPixelMethod:
3136 case BlackVirtualPixelMethod:
3137 case GrayVirtualPixelMethod:
3138 case TransparentVirtualPixelMethod:
3139 case MaskVirtualPixelMethod:
3140 case WhiteVirtualPixelMethod:
3143 virtual_indexes=(&virtual_index);
3146 case EdgeVirtualPixelMethod:
3149 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3150 EdgeX(x_offset,cache_info->columns),
3151 EdgeY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3153 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3157 case RandomVirtualPixelMethod:
3159 if (cache_info->random_info == (
RandomInfo *) NULL)
3160 cache_info->random_info=AcquireRandomInfo();
3161 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3162 RandomX(cache_info->random_info,cache_info->columns),
3163 RandomY(cache_info->random_info,cache_info->rows),1UL,1UL,
3164 virtual_nexus,exception);
3165 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3169 case DitherVirtualPixelMethod:
3171 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3172 DitherX(x_offset,cache_info->columns),
3173 DitherY(y_offset,cache_info->rows),1UL,1UL,virtual_nexus,
3175 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3179 case TileVirtualPixelMethod:
3181 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3182 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3183 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3184 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3186 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3190 case MirrorVirtualPixelMethod:
3192 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3193 if ((x_modulo.quotient & 0x01) == 1L)
3194 x_modulo.remainder=(ssize_t) cache_info->columns-
3195 x_modulo.remainder-1L;
3196 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3197 if ((y_modulo.quotient & 0x01) == 1L)
3198 y_modulo.remainder=(ssize_t) cache_info->rows-
3199 y_modulo.remainder-1L;
3200 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3201 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3203 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3207 case CheckerTileVirtualPixelMethod:
3209 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3210 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3211 if (((x_modulo.quotient ^ y_modulo.quotient) & 0x01) != 0L)
3214 virtual_indexes=(&virtual_index);
3217 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3218 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3220 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3224 case HorizontalTileVirtualPixelMethod:
3226 if ((y_offset < 0) || (y_offset >= (ssize_t) cache_info->rows))
3229 virtual_indexes=(&virtual_index);
3232 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3233 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3234 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3235 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3237 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3241 case VerticalTileVirtualPixelMethod:
3243 if ((x_offset < 0) || (x_offset >= (ssize_t) cache_info->columns))
3246 virtual_indexes=(&virtual_index);
3249 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3250 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3251 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3252 x_modulo.remainder,y_modulo.remainder,1UL,1UL,virtual_nexus,
3254 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3258 case HorizontalTileEdgeVirtualPixelMethod:
3260 x_modulo=VirtualPixelModulo(x_offset,cache_info->columns);
3261 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3262 x_modulo.remainder,EdgeY(y_offset,cache_info->rows),1UL,1UL,
3263 virtual_nexus,exception);
3264 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3268 case VerticalTileEdgeVirtualPixelMethod:
3270 y_modulo=VirtualPixelModulo(y_offset,cache_info->rows);
3271 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,
3272 EdgeX(x_offset,cache_info->columns),y_modulo.remainder,1UL,1UL,
3273 virtual_nexus,exception);
3274 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,
3282 if ((indexes != (IndexPacket *) NULL) &&
3283 (virtual_indexes != (
const IndexPacket *) NULL))
3284 *indexes++=(*virtual_indexes);
3290 p=GetVirtualPixelCacheNexus(image,virtual_pixel_method,x_offset,y_offset,
3291 (
size_t) length,1UL,virtual_nexus,exception);
3294 virtual_indexes=GetVirtualIndexesFromNexus(cache_info,virtual_nexus);
3295 (void) memcpy(q,p,(
size_t) length*
sizeof(*p));
3297 if ((indexes != (IndexPacket *) NULL) &&
3298 (virtual_indexes != (
const IndexPacket *) NULL))
3300 (void) memcpy(indexes,virtual_indexes,(
size_t) length*
3301 sizeof(*virtual_indexes));
3305 if (u < (ssize_t) columns)
3311 if (v < (ssize_t) rows)
3351 const VirtualPixelMethod virtual_pixel_method,
const ssize_t x,
const ssize_t y,
3352 const size_t columns,
const size_t rows,
ExceptionInfo *exception)
3355 *magick_restrict cache_info;
3358 id = GetOpenMPThreadId();
3360 assert(image != (
const Image *) NULL);
3361 assert(image->signature == MagickCoreSignature);
3362 assert(image->cache != (Cache) NULL);
3364 assert(cache_info->signature == MagickCoreSignature);
3365 assert(
id < (
int) cache_info->number_threads);
3366 return(GetVirtualPixelCacheNexus(image,virtual_pixel_method,x,y,columns,rows,
3367 cache_info->nexus_info[
id],exception));
3396 *magick_restrict cache_info;
3399 id = GetOpenMPThreadId();
3401 assert(image != (
const Image *) NULL);
3402 assert(image->signature == MagickCoreSignature);
3403 assert(image->cache != (Cache) NULL);
3405 assert(cache_info->signature == MagickCoreSignature);
3406 if (cache_info->methods.get_virtual_pixels_handler !=
3407 (GetVirtualPixelsHandler) NULL)
3408 return(cache_info->methods.get_virtual_pixels_handler(image));
3409 assert(
id < (
int) cache_info->number_threads);
3410 return(GetVirtualPixelsNexus(cache_info,cache_info->nexus_info[
id]));
3462 const ssize_t x,
const ssize_t y,
const size_t columns,
const size_t rows,
3466 *magick_restrict cache_info;
3469 id = GetOpenMPThreadId();
3471 assert(image != (
const Image *) NULL);
3472 assert(image->signature == MagickCoreSignature);
3473 assert(image->cache != (Cache) NULL);
3475 assert(cache_info->signature == MagickCoreSignature);
3476 if (cache_info->methods.get_virtual_pixel_handler !=
3477 (GetVirtualPixelHandler) NULL)
3478 return(cache_info->methods.get_virtual_pixel_handler(image,
3479 GetPixelCacheVirtualMethod(image),x,y,columns,rows,exception));
3480 assert(
id < (
int) cache_info->number_threads);
3481 return(GetVirtualPixelCacheNexus(image,GetPixelCacheVirtualMethod(image),x,y,
3482 columns,rows,cache_info->nexus_info[
id],exception));
3511 *magick_restrict cache_info;
3514 id = GetOpenMPThreadId();
3516 assert(image != (
const Image *) NULL);
3517 assert(image->signature == MagickCoreSignature);
3518 assert(image->cache != (Cache) NULL);
3520 assert(cache_info->signature == MagickCoreSignature);
3521 assert(
id < (
int) cache_info->number_threads);
3522 return(GetVirtualPixelsNexus(image->cache,cache_info->nexus_info[
id]));
3551 MagickExport
const PixelPacket *GetVirtualPixelsNexus(
const Cache cache,
3555 *magick_restrict cache_info;
3557 assert(cache != (Cache) NULL);
3559 assert(cache_info->signature == MagickCoreSignature);
3560 if (cache_info->storage_class == UndefinedClass)
3602 if (fabs((
double) (alpha-TransparentOpacity)) < MagickEpsilon)
3607 gamma=1.0-QuantumScale*QuantumScale*alpha*beta;
3608 gamma=PerceptibleReciprocal(gamma);
3609 composite->red=gamma*MagickOver_(p->red,alpha,q->red,beta);
3610 composite->green=gamma*MagickOver_(p->green,alpha,q->green,beta);
3611 composite->blue=gamma*MagickOver_(p->blue,alpha,q->blue,beta);
3612 if ((p->colorspace == CMYKColorspace) && (q->colorspace == CMYKColorspace))
3613 composite->index=gamma*MagickOver_(p->index,alpha,q->index,beta);
3616 static MagickBooleanType MaskPixelCacheNexus(
Image *image,
NexusInfo *nexus_info,
3620 *magick_restrict cache_info;
3626 *magick_restrict nexus_indexes,
3627 *magick_restrict indexes;
3637 **magick_restrict mask_nexus;
3649 if (IsEventLogging() != MagickFalse)
3650 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3651 if ((image->mask == (
Image *) NULL) || (image->storage_class == PseudoClass))
3653 if ((nexus_info->region.width == 0) || (nexus_info->region.height == 0))
3656 if (cache_info == (Cache) NULL)
3657 return(MagickFalse);
3658 mask_nexus=AcquirePixelCacheNexus(1);
3659 p=GetAuthenticPixelCacheNexus(image,nexus_info->region.x,nexus_info->region.y, nexus_info->region.width,nexus_info->region.height,
3660 nexus_info->virtual_nexus,exception);
3661 indexes=nexus_info->virtual_nexus->indexes;
3662 q=nexus_info->pixels;
3663 nexus_indexes=nexus_info->indexes;
3664 r=GetVirtualPixelCacheNexus(image->mask,MaskVirtualPixelMethod,
3665 nexus_info->region.x,nexus_info->region.y,nexus_info->region.width,
3666 nexus_info->region.height,mask_nexus[0],&image->exception);
3669 return(MagickFalse);
3671 GetMagickPixelPacket(image,&alpha);
3672 GetMagickPixelPacket(image,&beta);
3673 for (y=0; y < (ssize_t) nexus_info->region.height; y++)
3678 for (x=0; x < (ssize_t) nexus_info->region.width; x++)
3680 SetMagickPixelPacket(image,p,indexes+n,&alpha);
3681 SetMagickPixelPacket(image,q,nexus_indexes+n,&beta);
3682 ApplyPixelCompositeMask(&beta,GetPixelIntensity(image,r),&alpha,
3683 alpha.opacity,&beta);
3684 SetPixelRed(q,ClampToQuantum(beta.red));
3685 SetPixelGreen(q,ClampToQuantum(beta.green));
3686 SetPixelBlue(q,ClampToQuantum(beta.blue));
3687 SetPixelOpacity(q,ClampToQuantum(beta.opacity));
3688 if (cache_info->active_index_channel != MagickFalse)
3689 SetPixelIndex(nexus_indexes+n,GetPixelIndex(indexes+n));
3696 mask_nexus=DestroyPixelCacheNexus(mask_nexus,1);
3731 static MagickBooleanType OpenPixelCacheOnDisk(
CacheInfo *cache_info,
3740 if ((cache_info->file != -1) && (cache_info->disk_mode == mode))
3742 if (*cache_info->cache_filename ==
'\0')
3743 file=AcquireUniqueFileResource(cache_info->cache_filename);
3749 file=open_utf8(cache_info->cache_filename,O_RDONLY | O_BINARY,0);
3754 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_CREAT |
3755 O_BINARY | O_EXCL,S_MODE);
3757 file=open_utf8(cache_info->cache_filename,O_WRONLY | O_BINARY,S_MODE);
3763 file=open_utf8(cache_info->cache_filename,O_RDWR | O_CREAT | O_BINARY |
3766 file=open_utf8(cache_info->cache_filename,O_RDWR | O_BINARY,S_MODE);
3771 return(MagickFalse);
3772 (void) AcquireMagickResource(FileResource,1);
3773 if (cache_info->file != -1)
3774 (void) ClosePixelCacheOnDisk(cache_info);
3775 cache_info->file=file;
3776 cache_info->disk_mode=mode;
3780 static inline MagickOffsetType WritePixelCacheRegion(
3781 const CacheInfo *magick_restrict cache_info,
const MagickOffsetType offset,
3782 const MagickSizeType length,
const unsigned char *magick_restrict buffer)
3790 #if !defined(MAGICKCORE_HAVE_PWRITE)
3791 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
3792 return((MagickOffsetType) -1);
3794 for (i=0; i < (MagickOffsetType) length; i+=count)
3796 #if !defined(MAGICKCORE_HAVE_PWRITE)
3797 count=write(cache_info->file,buffer+i,(
size_t) MagickMin(length-i,(
size_t)
3800 count=pwrite(cache_info->file,buffer+i,(
size_t) MagickMin(length-i,(
size_t)
3801 MAGICK_SSIZE_MAX),offset+i);
3813 static MagickBooleanType SetPixelCacheExtent(
Image *image,MagickSizeType length)
3816 *magick_restrict cache_info;
3822 if (cache_info->debug != MagickFalse)
3825 format[MaxTextExtent],
3826 message[MaxTextExtent];
3828 (void) FormatMagickSize(length,MagickFalse,format);
3829 (void) FormatLocaleString(message,MaxTextExtent,
3830 "extend %s (%s[%d], disk, %s)",cache_info->filename,
3831 cache_info->cache_filename,cache_info->file,format);
3832 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",message);
3834 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_END);
3836 return(MagickFalse);
3837 if ((MagickSizeType) offset < length)
3843 extent=(MagickOffsetType) length-1;
3844 count=WritePixelCacheRegion(cache_info,extent,1,(
const unsigned char *)
3847 return(MagickFalse);
3848 #if defined(MAGICKCORE_HAVE_POSIX_FALLOCATE)
3849 if (cache_info->synchronize != MagickFalse)
3850 if (posix_fallocate(cache_info->file,offset+1,extent-offset) != 0)
3851 return(MagickFalse);
3854 offset=(MagickOffsetType) lseek(cache_info->file,0,SEEK_SET);
3856 return(MagickFalse);
3860 static MagickBooleanType OpenPixelCache(
Image *image,
const MapMode mode,
3864 *magick_restrict cache_info,
3868 format[MaxTextExtent],
3869 message[MaxTextExtent];
3886 assert(image != (
const Image *) NULL);
3887 assert(image->signature == MagickCoreSignature);
3888 assert(image->cache != (Cache) NULL);
3889 if (IsEventLogging() != MagickFalse)
3890 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
3891 if (cache_anonymous_memory < 0)
3899 cache_anonymous_memory=0;
3900 value=GetPolicyValue(
"pixel-cache-memory");
3901 if (value == (
char *) NULL)
3902 value=GetPolicyValue(
"cache:memory-map");
3903 if (LocaleCompare(value,
"anonymous") == 0)
3905 #if defined(MAGICKCORE_HAVE_MMAP) && defined(MAP_ANONYMOUS)
3906 cache_anonymous_memory=1;
3908 (void) ThrowMagickException(exception,GetMagickModule(),
3909 MissingDelegateError,
"DelegateLibrarySupportNotBuiltIn",
3910 "'%s' (policy requires anonymous memory mapping)",image->filename);
3913 value=DestroyString(value);
3915 if ((image->columns == 0) || (image->rows == 0))
3916 ThrowBinaryException(CacheError,
"NoPixelsDefinedInCache",image->filename);
3918 assert(cache_info->signature == MagickCoreSignature);
3919 if (((MagickSizeType) image->columns > cache_info->width_limit) ||
3920 ((MagickSizeType) image->rows > cache_info->height_limit))
3921 ThrowBinaryException(ImageError,
"WidthOrHeightExceedsLimit",
3923 if (GetMagickResourceLimit(ListLengthResource) != MagickResourceInfinity)
3925 length=GetImageListLength(image);
3926 if (AcquireMagickResource(ListLengthResource,length) == MagickFalse)
3927 ThrowBinaryException(ResourceLimitError,
"ListLengthExceedsLimit",
3930 source_info=(*cache_info);
3931 source_info.file=(-1);
3932 (void) FormatLocaleString(cache_info->filename,MaxTextExtent,
"%s[%.20g]",
3933 image->filename,(
double) image->scene);
3934 cache_info->storage_class=image->storage_class;
3935 cache_info->colorspace=image->colorspace;
3936 cache_info->rows=image->rows;
3937 cache_info->columns=image->columns;
3938 cache_info->channels=image->channels;
3939 cache_info->active_index_channel=((image->storage_class == PseudoClass) ||
3940 (image->colorspace == CMYKColorspace)) ? MagickTrue : MagickFalse;
3941 cache_info->mode=mode;
3942 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
3944 if (cache_info->active_index_channel != MagickFalse)
3945 packet_size+=
sizeof(IndexPacket);
3946 length=number_pixels*packet_size;
3947 columns=(size_t) (length/cache_info->rows/packet_size);
3948 if ((cache_info->columns != columns) || ((ssize_t) cache_info->columns < 0) ||
3949 ((ssize_t) cache_info->rows < 0))
3950 ThrowBinaryException(ResourceLimitError,
"PixelCacheAllocationFailed",
3952 cache_info->length=length;
3953 if (image->ping != MagickFalse)
3955 cache_info->type=PingCache;
3958 status=AcquireMagickResource(AreaResource,(MagickSizeType)
3959 cache_info->columns*cache_info->rows);
3960 if (cache_info->mode == PersistMode)
3962 length=number_pixels*(
sizeof(
PixelPacket)+
sizeof(IndexPacket));
3963 if ((status != MagickFalse) &&
3964 (length == (MagickSizeType) ((
size_t) length)) &&
3965 ((cache_info->type == UndefinedCache) ||
3966 (cache_info->type == MemoryCache)))
3968 status=AcquireMagickResource(MemoryResource,cache_info->length);
3969 if (status != MagickFalse)
3972 if (cache_anonymous_memory <= 0)
3974 cache_info->mapped=MagickFalse;
3975 cache_info->pixels=(
PixelPacket *) MagickAssumeAligned(
3976 AcquireAlignedMemory(1,(
size_t) cache_info->length));
3980 cache_info->mapped=MagickTrue;
3981 cache_info->pixels=(
PixelPacket *) MapBlob(-1,IOMode,0,(
size_t)
3982 cache_info->length);
3986 cache_info->mapped=source_info.mapped;
3987 cache_info->pixels=source_info.pixels;
3994 cache_info->colorspace=image->colorspace;
3995 cache_info->type=MemoryCache;
3996 cache_info->indexes=(IndexPacket *) NULL;
3997 if (cache_info->active_index_channel != MagickFalse)
3998 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4000 if ((source_info.storage_class != UndefinedClass) &&
4003 status&=ClonePixelCacheRepository(cache_info,&source_info,
4005 RelinquishPixelCachePixels(&source_info);
4007 if (cache_info->debug != MagickFalse)
4009 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4010 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4012 (void) FormatLocaleString(message,MaxTextExtent,
4013 "open %s (%s %s, %.20gx%.20g %s)",cache_info->filename,
4014 cache_info->mapped != MagickFalse ?
"Anonymous" :
"Heap",
4015 type,(
double) cache_info->columns,(double) cache_info->rows,
4017 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",
4020 cache_info->storage_class=image->storage_class;
4023 cache_info->type=UndefinedCache;
4024 return(MagickFalse);
4030 status=AcquireMagickResource(DiskResource,cache_info->length);
4031 hosts=(
const char *) GetImageRegistry(StringRegistryType,
"cache:hosts",
4033 if ((status == MagickFalse) && (hosts != (
const char *) NULL))
4041 server_info=AcquireDistributeCacheInfo(exception);
4044 status=OpenDistributePixelCache(server_info,image);
4045 if (status == MagickFalse)
4047 ThrowFileException(exception,CacheError,
"UnableToOpenPixelCache",
4048 GetDistributeCacheHostname(server_info));
4049 server_info=DestroyDistributeCacheInfo(server_info);
4057 cache_info->type=DistributedCache;
4058 cache_info->storage_class=image->storage_class;
4059 cache_info->colorspace=image->colorspace;
4060 cache_info->server_info=server_info;
4061 (void) FormatLocaleString(cache_info->cache_filename,
4062 MaxTextExtent,
"%s:%d",GetDistributeCacheHostname(
4065 cache_info->server_info));
4066 if ((source_info.storage_class != UndefinedClass) &&
4069 status=ClonePixelCacheRepository(cache_info,&source_info,
4071 RelinquishPixelCachePixels(&source_info);
4073 if (cache_info->debug != MagickFalse)
4075 (void) FormatMagickSize(cache_info->length,MagickFalse,
4077 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4079 (void) FormatLocaleString(message,MaxTextExtent,
4080 "open %s (%s[%d], %s, %.20gx%.20g %s)",cache_info->filename,
4081 cache_info->cache_filename,GetDistributeCacheFile(
4083 (double) cache_info->columns,(
double) cache_info->rows,
4085 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",
4090 cache_info->type=UndefinedCache;
4091 return(MagickFalse);
4096 cache_info->type=UndefinedCache;
4097 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4098 "CacheResourcesExhausted",
"`%s'",image->filename);
4099 return(MagickFalse);
4104 if (status == MagickFalse)
4106 cache_info->type=UndefinedCache;
4107 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4108 "CacheResourcesExhausted",
"`%s'",image->filename);
4109 return(MagickFalse);
4111 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode) &&
4112 (cache_info->mode != PersistMode))
4114 (void) ClosePixelCacheOnDisk(cache_info);
4115 *cache_info->cache_filename=
'\0';
4117 if (OpenPixelCacheOnDisk(cache_info,mode) == MagickFalse)
4119 cache_info->type=UndefinedCache;
4120 ThrowFileException(exception,CacheError,
"UnableToOpenPixelCache",
4122 return(MagickFalse);
4124 status=SetPixelCacheExtent(image,(MagickSizeType) cache_info->offset+
4125 cache_info->length);
4126 if (status == MagickFalse)
4128 cache_info->type=UndefinedCache;
4129 ThrowFileException(exception,CacheError,
"UnableToExtendCache",
4131 return(MagickFalse);
4133 cache_info->storage_class=image->storage_class;
4134 cache_info->colorspace=image->colorspace;
4135 cache_info->type=DiskCache;
4136 length=number_pixels*(
sizeof(
PixelPacket)+
sizeof(IndexPacket));
4137 if (length == (MagickSizeType) ((size_t) length))
4139 status=AcquireMagickResource(MapResource,cache_info->length);
4140 if (status != MagickFalse)
4142 cache_info->pixels=(
PixelPacket *) MapBlob(cache_info->file,mode,
4143 cache_info->offset,(
size_t) cache_info->length);
4146 cache_info->mapped=source_info.mapped;
4147 cache_info->pixels=source_info.pixels;
4148 RelinquishMagickResource(MapResource,cache_info->length);
4155 (void) ClosePixelCacheOnDisk(cache_info);
4156 cache_info->type=MapCache;
4157 cache_info->mapped=MagickTrue;
4158 cache_info->indexes=(IndexPacket *) NULL;
4159 if (cache_info->active_index_channel != MagickFalse)
4160 cache_info->indexes=(IndexPacket *) (cache_info->pixels+
4162 if ((source_info.storage_class != UndefinedClass) &&
4165 status=ClonePixelCacheRepository(cache_info,&source_info,
4167 RelinquishPixelCachePixels(&source_info);
4169 if (cache_info->debug != MagickFalse)
4171 (void) FormatMagickSize(cache_info->length,MagickTrue,format);
4172 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4174 (void) FormatLocaleString(message,MaxTextExtent,
4175 "open %s (%s[%d], %s, %.20gx%.20g %s)",
4176 cache_info->filename,cache_info->cache_filename,
4177 cache_info->file,type,(
double) cache_info->columns,
4178 (double) cache_info->rows,format);
4179 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",
4184 cache_info->type=UndefinedCache;
4185 return(MagickFalse);
4192 if ((source_info.storage_class != UndefinedClass) && (mode != ReadMode))
4194 status=ClonePixelCacheRepository(cache_info,&source_info,exception);
4195 RelinquishPixelCachePixels(&source_info);
4197 if (cache_info->debug != MagickFalse)
4199 (void) FormatMagickSize(cache_info->length,MagickFalse,format);
4200 type=CommandOptionToMnemonic(MagickCacheOptions,(ssize_t)
4202 (void) FormatLocaleString(message,MaxTextExtent,
4203 "open %s (%s[%d], %s, %.20gx%.20g %s)",cache_info->filename,
4204 cache_info->cache_filename,cache_info->file,type,(
double)
4205 cache_info->columns,(double) cache_info->rows,format);
4206 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
"%s",message);
4210 cache_info->type=UndefinedCache;
4211 return(MagickFalse);
4253 MagickExport MagickBooleanType PersistPixelCache(
Image *image,
4254 const char *filename,
const MagickBooleanType attach,MagickOffsetType *offset,
4258 *magick_restrict cache_info,
4259 *magick_restrict clone_info;
4267 assert(image != (
Image *) NULL);
4268 assert(image->signature == MagickCoreSignature);
4269 if (IsEventLogging() != MagickFalse)
4270 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
4271 assert(image->cache != (
void *) NULL);
4272 assert(filename != (
const char *) NULL);
4273 assert(offset != (MagickOffsetType *) NULL);
4274 page_size=GetMagickPageSize();
4276 assert(cache_info->signature == MagickCoreSignature);
4277 #if defined(MAGICKCORE_OPENCL_SUPPORT)
4278 CopyOpenCLBuffer(cache_info);
4280 if (attach != MagickFalse)
4285 if (cache_info->debug != MagickFalse)
4286 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4287 "attach persistent cache");
4288 (void) CopyMagickString(cache_info->cache_filename,filename,
4290 cache_info->type=MapCache;
4291 cache_info->offset=(*offset);
4292 if (OpenPixelCache(image,ReadMode,exception) == MagickFalse)
4293 return(MagickFalse);
4294 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4300 status=AcquireMagickResource(DiskResource,cache_info->length);
4301 if (status == MagickFalse)
4303 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4304 "CacheResourcesExhausted",
"`%s'",image->filename);
4305 return(MagickFalse);
4307 clone_info=(
CacheInfo *) ClonePixelCache(cache_info);
4308 clone_info->type=DiskCache;
4309 (void) CopyMagickString(clone_info->cache_filename,filename,MaxTextExtent);
4310 clone_info->file=(-1);
4311 clone_info->storage_class=cache_info->storage_class;
4312 clone_info->colorspace=cache_info->colorspace;
4313 clone_info->columns=cache_info->columns;
4314 clone_info->rows=cache_info->rows;
4315 clone_info->active_index_channel=cache_info->active_index_channel;
4316 clone_info->mode=PersistMode;
4317 clone_info->length=cache_info->length;
4318 clone_info->channels=cache_info->channels;
4319 clone_info->offset=(*offset);
4320 status=OpenPixelCacheOnDisk(clone_info,WriteMode);
4321 if (status != MagickFalse)
4322 status=ClonePixelCacheRepository(clone_info,cache_info,exception);
4323 *offset+=cache_info->length+page_size-(cache_info->length % page_size);
4324 clone_info=(
CacheInfo *) DestroyPixelCache(clone_info);
4366 MagickExport
PixelPacket *QueueAuthenticPixel(
Image *image,
const ssize_t x,
4367 const ssize_t y,
const size_t columns,
const size_t rows,
4368 const MagickBooleanType clone,
NexusInfo *nexus_info,
4371 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,clone,nexus_info,
4376 const ssize_t x,
const ssize_t y,
const size_t columns,
const size_t rows,
4380 *magick_restrict cache_info;
4389 *magick_restrict pixels;
4394 assert(image != (
const Image *) NULL);
4395 assert(image->signature == MagickCoreSignature);
4396 assert(image->cache != (Cache) NULL);
4397 cache_info=(
CacheInfo *) GetImagePixelCache(image,clone,exception);
4398 if (cache_info == (Cache) NULL)
4400 assert(cache_info->signature == MagickCoreSignature);
4401 if ((cache_info->columns == 0) || (cache_info->rows == 0) || (x < 0) ||
4402 (y < 0) || (x >= (ssize_t) cache_info->columns) ||
4403 (y >= (ssize_t) cache_info->rows))
4405 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
4406 "PixelsAreNotAuthentic",
"`%s'",image->filename);
4409 offset=(MagickOffsetType) y*cache_info->columns+x;
4412 number_pixels=(MagickSizeType) cache_info->columns*cache_info->rows;
4413 offset+=(MagickOffsetType) (rows-1)*cache_info->columns+columns-1;
4414 if ((MagickSizeType) offset >= number_pixels)
4419 pixels=SetPixelCacheNexusPixels(cache_info,WriteMode,x,y,columns,rows,
4420 (image->clip_mask != (
Image *) NULL) || (image->mask != (
Image *) NULL) ?
4421 MagickTrue : MagickFalse,nexus_info,exception);
4458 static PixelPacket *QueueAuthenticPixelsCache(
Image *image,
const ssize_t x,
4459 const ssize_t y,
const size_t columns,
const size_t rows,
4463 *magick_restrict cache_info;
4466 id = GetOpenMPThreadId();
4468 assert(image != (
const Image *) NULL);
4469 assert(image->signature == MagickCoreSignature);
4470 assert(image->cache != (Cache) NULL);
4472 assert(cache_info->signature == MagickCoreSignature);
4473 assert(
id < (
int) cache_info->number_threads);
4474 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4475 cache_info->nexus_info[
id],exception));
4534 MagickExport
PixelPacket *QueueAuthenticPixels(
Image *image,
const ssize_t x,
4535 const ssize_t y,
const size_t columns,
const size_t rows,
4539 *magick_restrict cache_info;
4542 id = GetOpenMPThreadId();
4544 assert(image != (
Image *) NULL);
4545 assert(image->signature == MagickCoreSignature);
4546 assert(image->cache != (Cache) NULL);
4548 assert(cache_info->signature == MagickCoreSignature);
4549 if (cache_info->methods.queue_authentic_pixels_handler !=
4550 (QueueAuthenticPixelsHandler) NULL)
4551 return(cache_info->methods.queue_authentic_pixels_handler(image,x,y,columns,
4553 assert(
id < (
int) cache_info->number_threads);
4554 return(QueueAuthenticPixelCacheNexus(image,x,y,columns,rows,MagickFalse,
4555 cache_info->nexus_info[
id],exception));
4587 static inline MagickOffsetType ReadPixelCacheRegion(
4588 const CacheInfo *magick_restrict cache_info,
const MagickOffsetType offset,
4589 const MagickSizeType length,
unsigned char *magick_restrict buffer)
4597 #if !defined(MAGICKCORE_HAVE_PREAD)
4598 if (lseek(cache_info->file,offset,SEEK_SET) < 0)
4599 return((MagickOffsetType) -1);
4601 for (i=0; i < (MagickOffsetType) length; i+=count)
4603 #if !defined(MAGICKCORE_HAVE_PREAD)
4604 count=read(cache_info->file,buffer+i,(
size_t) MagickMin(length-i,(
size_t)
4607 count=pread(cache_info->file,buffer+i,(
size_t) MagickMin(length-i,(
size_t)
4608 MAGICK_SSIZE_MAX),offset+i);
4620 static MagickBooleanType ReadPixelCacheIndexes(
4641 if (cache_info->active_index_channel == MagickFalse)
4642 return(MagickFalse);
4643 if (nexus_info->authentic_pixel_cache != MagickFalse)
4645 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
4646 nexus_info->region.x;
4647 length=(MagickSizeType) nexus_info->region.width*
sizeof(IndexPacket);
4648 rows=nexus_info->region.height;
4650 q=nexus_info->indexes;
4652 switch (cache_info->type)
4663 if ((cache_info->columns == nexus_info->region.width) &&
4664 (extent == (MagickSizeType) ((
size_t) extent)))
4669 p=cache_info->indexes+offset;
4670 for (y=0; y < (ssize_t) rows; y++)
4672 (void) memcpy(q,p,(
size_t) length);
4673 p+=cache_info->columns;
4674 q+=nexus_info->region.width;
4683 LockSemaphoreInfo(cache_info->file_semaphore);
4684 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4686 ThrowFileException(exception,FileOpenError,
"UnableToOpenFile",
4687 cache_info->cache_filename);
4688 UnlockSemaphoreInfo(cache_info->file_semaphore);
4689 return(MagickFalse);
4691 if ((cache_info->columns == nexus_info->region.width) &&
4692 (extent <= MagickMaxBufferExtent))
4697 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
4698 for (y=0; y < (ssize_t) rows; y++)
4700 count=ReadPixelCacheRegion(cache_info,cache_info->offset+extent*
4701 sizeof(
PixelPacket)+offset*
sizeof(*q),length,(
unsigned char *) q);
4702 if (count < (MagickOffsetType) length)
4704 offset+=cache_info->columns;
4705 q+=nexus_info->region.width;
4707 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4708 (void) ClosePixelCacheOnDisk(cache_info);
4709 UnlockSemaphoreInfo(cache_info->file_semaphore);
4712 case DistributedCache:
4720 LockSemaphoreInfo(cache_info->file_semaphore);
4721 region=nexus_info->region;
4722 if ((cache_info->columns != nexus_info->region.width) ||
4723 (extent > MagickMaxBufferExtent))
4730 for (y=0; y < (ssize_t) rows; y++)
4733 cache_info->server_info,®ion,length,(
unsigned char *) q);
4734 if (count != (MagickOffsetType) length)
4736 q+=nexus_info->region.width;
4739 UnlockSemaphoreInfo(cache_info->file_semaphore);
4745 if (y < (ssize_t) rows)
4747 ThrowFileException(exception,CacheError,
"UnableToReadPixelCache",
4748 cache_info->cache_filename);
4749 return(MagickFalse);
4751 if ((cache_info->debug != MagickFalse) &&
4752 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4753 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4754 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4755 nexus_info->region.width,(
double) nexus_info->region.height,(double)
4756 nexus_info->region.x,(
double) nexus_info->region.y);
4788 static MagickBooleanType ReadPixelCachePixels(
4809 if (nexus_info->authentic_pixel_cache != MagickFalse)
4811 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns;
4812 if ((ssize_t) (offset/cache_info->columns) != nexus_info->region.y)
4813 return(MagickFalse);
4814 offset+=nexus_info->region.x;
4815 length=(MagickSizeType) nexus_info->region.width*
sizeof(
PixelPacket);
4816 if ((length/
sizeof(
PixelPacket)) != nexus_info->region.width)
4817 return(MagickFalse);
4818 rows=nexus_info->region.height;
4820 if ((extent == 0) || ((extent/length) != rows))
4821 return(MagickFalse);
4822 q=nexus_info->pixels;
4824 switch (cache_info->type)
4835 if ((cache_info->columns == nexus_info->region.width) &&
4836 (extent == (MagickSizeType) ((
size_t) extent)))
4841 p=cache_info->pixels+offset;
4842 for (y=0; y < (ssize_t) rows; y++)
4844 (void) memcpy(q,p,(
size_t) length);
4845 p+=cache_info->columns;
4846 q+=nexus_info->region.width;
4855 LockSemaphoreInfo(cache_info->file_semaphore);
4856 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
4858 ThrowFileException(exception,FileOpenError,
"UnableToOpenFile",
4859 cache_info->cache_filename);
4860 UnlockSemaphoreInfo(cache_info->file_semaphore);
4861 return(MagickFalse);
4863 if ((cache_info->columns == nexus_info->region.width) &&
4864 (extent <= MagickMaxBufferExtent))
4869 for (y=0; y < (ssize_t) rows; y++)
4871 count=ReadPixelCacheRegion(cache_info,cache_info->offset+offset*
4872 sizeof(*q),length,(
unsigned char *) q);
4873 if (count < (MagickOffsetType) length)
4875 offset+=cache_info->columns;
4876 q+=nexus_info->region.width;
4878 if (IsFileDescriptorLimitExceeded() != MagickFalse)
4879 (void) ClosePixelCacheOnDisk(cache_info);
4880 UnlockSemaphoreInfo(cache_info->file_semaphore);
4883 case DistributedCache:
4891 LockSemaphoreInfo(cache_info->file_semaphore);
4892 region=nexus_info->region;
4893 if ((cache_info->columns != nexus_info->region.width) ||
4894 (extent > MagickMaxBufferExtent))
4901 for (y=0; y < (ssize_t) rows; y++)
4904 cache_info->server_info,®ion,length,(
unsigned char *) q);
4905 if (count != (MagickOffsetType) length)
4907 q+=nexus_info->region.width;
4910 UnlockSemaphoreInfo(cache_info->file_semaphore);
4916 if (y < (ssize_t) rows)
4918 ThrowFileException(exception,CacheError,
"UnableToReadPixelCache",
4919 cache_info->cache_filename);
4920 return(MagickFalse);
4922 if ((cache_info->debug != MagickFalse) &&
4923 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
4924 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
4925 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
4926 nexus_info->region.width,(
double) nexus_info->region.height,(double)
4927 nexus_info->region.x,(
double) nexus_info->region.y);
4954 MagickExport Cache ReferencePixelCache(Cache cache)
4957 *magick_restrict cache_info;
4959 assert(cache != (Cache *) NULL);
4961 assert(cache_info->signature == MagickCoreSignature);
4962 LockSemaphoreInfo(cache_info->semaphore);
4963 cache_info->reference_count++;
4964 UnlockSemaphoreInfo(cache_info->semaphore);
4986 MagickPrivate
void ResetPixelCacheEpoch(
void)
5015 MagickExport
void SetPixelCacheMethods(Cache cache,
CacheMethods *cache_methods)
5018 *magick_restrict cache_info;
5020 GetOneAuthenticPixelFromHandler
5021 get_one_authentic_pixel_from_handler;
5023 GetOneVirtualPixelFromHandler
5024 get_one_virtual_pixel_from_handler;
5029 assert(cache != (Cache) NULL);
5032 assert(cache_info->signature == MagickCoreSignature);
5033 if (IsEventLogging() != MagickFalse)
5034 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",
5035 cache_info->filename);
5036 if (cache_methods->get_virtual_pixel_handler != (GetVirtualPixelHandler) NULL)
5037 cache_info->methods.get_virtual_pixel_handler=
5038 cache_methods->get_virtual_pixel_handler;
5039 if (cache_methods->destroy_pixel_handler != (DestroyPixelHandler) NULL)
5040 cache_info->methods.destroy_pixel_handler=
5041 cache_methods->destroy_pixel_handler;
5042 if (cache_methods->get_virtual_indexes_from_handler !=
5043 (GetVirtualIndexesFromHandler) NULL)
5044 cache_info->methods.get_virtual_indexes_from_handler=
5045 cache_methods->get_virtual_indexes_from_handler;
5046 if (cache_methods->get_authentic_pixels_handler !=
5047 (GetAuthenticPixelsHandler) NULL)
5048 cache_info->methods.get_authentic_pixels_handler=
5049 cache_methods->get_authentic_pixels_handler;
5050 if (cache_methods->queue_authentic_pixels_handler !=
5051 (QueueAuthenticPixelsHandler) NULL)
5052 cache_info->methods.queue_authentic_pixels_handler=
5053 cache_methods->queue_authentic_pixels_handler;
5054 if (cache_methods->sync_authentic_pixels_handler !=
5055 (SyncAuthenticPixelsHandler) NULL)
5056 cache_info->methods.sync_authentic_pixels_handler=
5057 cache_methods->sync_authentic_pixels_handler;
5058 if (cache_methods->get_authentic_pixels_from_handler !=
5059 (GetAuthenticPixelsFromHandler) NULL)
5060 cache_info->methods.get_authentic_pixels_from_handler=
5061 cache_methods->get_authentic_pixels_from_handler;
5062 if (cache_methods->get_authentic_indexes_from_handler !=
5063 (GetAuthenticIndexesFromHandler) NULL)
5064 cache_info->methods.get_authentic_indexes_from_handler=
5065 cache_methods->get_authentic_indexes_from_handler;
5066 get_one_virtual_pixel_from_handler=
5067 cache_info->methods.get_one_virtual_pixel_from_handler;
5068 if (get_one_virtual_pixel_from_handler !=
5069 (GetOneVirtualPixelFromHandler) NULL)
5070 cache_info->methods.get_one_virtual_pixel_from_handler=
5071 cache_methods->get_one_virtual_pixel_from_handler;
5072 get_one_authentic_pixel_from_handler=
5073 cache_methods->get_one_authentic_pixel_from_handler;
5074 if (get_one_authentic_pixel_from_handler !=
5075 (GetOneAuthenticPixelFromHandler) NULL)
5076 cache_info->methods.get_one_authentic_pixel_from_handler=
5077 cache_methods->get_one_authentic_pixel_from_handler;
5118 static inline MagickBooleanType AcquireCacheNexusPixels(
5119 const CacheInfo *magick_restrict cache_info,
const MagickSizeType length,
5122 if (length != (MagickSizeType) ((
size_t) length))
5124 (void) ThrowMagickException(exception,GetMagickModule(),
5125 ResourceLimitError,
"PixelCacheAllocationFailed",
"`%s'",
5126 cache_info->filename);
5127 return(MagickFalse);
5129 nexus_info->length=0;
5130 nexus_info->mapped=MagickFalse;
5131 if (cache_anonymous_memory <= 0)
5133 nexus_info->cache=(
PixelPacket *) MagickAssumeAligned(
5134 AcquireAlignedMemory(1,(
size_t) length));
5136 (
void) memset(nexus_info->cache,0,(
size_t) length);
5140 nexus_info->cache=(
PixelPacket *) MapBlob(-1,IOMode,0,(
size_t) length);
5142 nexus_info->mapped=MagickTrue;
5146 (void) ThrowMagickException(exception,GetMagickModule(),
5147 ResourceLimitError,
"PixelCacheAllocationFailed",
"`%s'",
5148 cache_info->filename);
5149 return(MagickFalse);
5151 nexus_info->length=length;
5155 static inline void PrefetchPixelCacheNexusPixels(
const NexusInfo *nexus_info,
5158 if (nexus_info->length < CACHE_LINE_SIZE)
5160 if (mode == ReadMode)
5162 MagickCachePrefetch((
unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,
5166 MagickCachePrefetch((
unsigned char *) nexus_info->pixels+CACHE_LINE_SIZE,1,1);
5169 static inline MagickBooleanType ValidatePixelOffset(
const ssize_t x,
5172 if ((x >= 0) && (x >= ((ssize_t) (MAGICK_SSIZE_MAX-5*a))))
5173 return(MagickFalse);
5174 if (x <= ((ssize_t) (MAGICK_SSIZE_MIN+5*a)))
5175 return(MagickFalse);
5180 const CacheInfo *magick_restrict cache_info,
const MapMode mode,
5181 const ssize_t x,
const ssize_t y,
const size_t width,
const size_t height,
5182 const MagickBooleanType buffered,
NexusInfo *magick_restrict nexus_info,
5192 assert(cache_info != (
const CacheInfo *) NULL);
5193 assert(cache_info->signature == MagickCoreSignature);
5194 if (cache_info->type == UndefinedCache)
5196 assert(nexus_info->signature == MagickCoreSignature);
5197 (void) memset(&nexus_info->region,0,
sizeof(nexus_info->region));
5198 if ((width == 0) || (height == 0))
5200 (void) ThrowMagickException(exception,GetMagickModule(),CacheError,
5201 "NoPixelsDefinedInCache",
"`%s'",cache_info->filename);
5204 if (((MagickSizeType) width > cache_info->width_limit) ||
5205 ((MagickSizeType) height > cache_info->height_limit) ||
5206 (ValidatePixelOffset(x,width) == MagickFalse) ||
5207 (ValidatePixelOffset(y,height) == MagickFalse))
5209 (void) ThrowMagickException(exception,GetMagickModule(),ImageError,
5210 "WidthOrHeightExceedsLimit",
"`%s'",cache_info->filename);
5213 if (((cache_info->type == MemoryCache) || (cache_info->type == MapCache)) &&
5214 (buffered == MagickFalse))
5216 if (((x >= 0) && (y >= 0) &&
5217 (((ssize_t) height+y-1) < (ssize_t) cache_info->rows)) &&
5218 (((x == 0) && (width == cache_info->columns)) || ((height == 1) &&
5219 (((ssize_t) width+x-1) < (ssize_t) cache_info->columns))))
5227 offset=(MagickOffsetType) y*cache_info->columns+x;
5228 nexus_info->pixels=cache_info->pixels+offset;
5229 nexus_info->indexes=(IndexPacket *) NULL;
5230 if (cache_info->active_index_channel != MagickFalse)
5231 nexus_info->indexes=cache_info->indexes+offset;
5232 nexus_info->region.width=width;
5233 nexus_info->region.height=height;
5234 nexus_info->region.x=x;
5235 nexus_info->region.y=y;
5236 nexus_info->authentic_pixel_cache=MagickTrue;
5237 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5238 return(nexus_info->pixels);
5244 number_pixels=(MagickSizeType) width*height;
5245 length=MagickMax(number_pixels,MagickMax(cache_info->columns,
5247 if (cache_info->active_index_channel != MagickFalse)
5248 length+=number_pixels*
sizeof(IndexPacket);
5251 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5253 if (nexus_info->length < length)
5255 RelinquishCacheNexusPixels(nexus_info);
5256 status=AcquireCacheNexusPixels(cache_info,length,nexus_info,exception);
5258 if (status == MagickFalse)
5260 (void) memset(&nexus_info->region,0,
sizeof(nexus_info->region));
5263 nexus_info->pixels=nexus_info->cache;
5264 nexus_info->indexes=(IndexPacket *) NULL;
5265 if (cache_info->active_index_channel != MagickFalse)
5266 nexus_info->indexes=(IndexPacket *) (nexus_info->pixels+number_pixels);
5267 nexus_info->region.width=width;
5268 nexus_info->region.height=height;
5269 nexus_info->region.x=x;
5270 nexus_info->region.y=y;
5271 nexus_info->authentic_pixel_cache=cache_info->type == PingCache ?
5272 MagickTrue : MagickFalse;
5273 PrefetchPixelCacheNexusPixels(nexus_info,mode);
5274 return(nexus_info->pixels);
5305 static MagickBooleanType SetCacheAlphaChannel(
Image *image,
5306 const Quantum opacity)
5309 *magick_restrict image_view;
5317 assert(image != (
Image *) NULL);
5318 assert(image->signature == MagickCoreSignature);
5319 if (IsEventLogging() != MagickFalse)
5320 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
5321 assert(image->cache != (Cache) NULL);
5322 image->matte=MagickTrue;
5324 image_view=AcquireVirtualCacheView(image,&image->exception);
5325 #if defined(MAGICKCORE_OPENMP_SUPPORT)
5326 #pragma omp parallel for schedule(static) shared(status) \
5327 magick_number_threads(image,image,image->rows,1)
5329 for (y=0; y < (ssize_t) image->rows; y++)
5337 if (status == MagickFalse)
5339 q=GetCacheViewAuthenticPixels(image_view,0,y,image->columns,1,
5346 for (x=0; x < (ssize_t) image->columns; x++)
5351 status=SyncCacheViewAuthenticPixels(image_view,&image->exception);
5353 image_view=DestroyCacheView(image_view);
5357 MagickExport VirtualPixelMethod SetPixelCacheVirtualMethod(
const Image *image,
5358 const VirtualPixelMethod virtual_pixel_method)
5361 *magick_restrict cache_info;
5366 assert(image != (
Image *) NULL);
5367 assert(image->signature == MagickCoreSignature);
5368 if (IsEventLogging() != MagickFalse)
5369 (void) LogMagickEvent(TraceEvent,GetMagickModule(),
"%s",image->filename);
5370 assert(image->cache != (Cache) NULL);
5372 assert(cache_info->signature == MagickCoreSignature);
5373 method=cache_info->virtual_pixel_method;
5374 cache_info->virtual_pixel_method=virtual_pixel_method;
5375 if ((image->columns != 0) && (image->rows != 0))
5376 switch (virtual_pixel_method)
5378 case BackgroundVirtualPixelMethod:
5380 if ((image->background_color.opacity != OpaqueOpacity) &&
5381 (image->matte == MagickFalse))
5382 (void) SetCacheAlphaChannel((
Image *) image,OpaqueOpacity);
5383 if ((IsPixelGray(&image->background_color) == MagickFalse) &&
5384 (IsGrayColorspace(image->colorspace) != MagickFalse))
5385 (void) SetImageColorspace((
Image *) image,sRGBColorspace);
5388 case TransparentVirtualPixelMethod:
5390 if (image->matte == MagickFalse)
5391 (void) SetCacheAlphaChannel((
Image *) image,OpaqueOpacity);
5400 #if defined(MAGICKCORE_OPENCL_SUPPORT)
5424 static void CopyOpenCLBuffer(
CacheInfo *magick_restrict cache_info)
5429 assert(cache_info != (
CacheInfo *)NULL);
5430 if ((cache_info->type != MemoryCache) ||
5436 LockSemaphoreInfo(cache_info->semaphore);
5445 clEnv=GetDefaultOpenCLEnv();
5446 events=CopyOpenCLEvents(cache_info->opencl,&event_count);
5447 if (events != (cl_event *) NULL)
5461 context=GetOpenCLContext(clEnv);
5462 queue=AcquireOpenCLCommandQueue(clEnv);
5463 pixels=(
PixelPacket *) clEnv->library->clEnqueueMapBuffer(queue,
5464 cache_info->opencl->buffer,CL_TRUE, CL_MAP_READ | CL_MAP_WRITE,0,
5465 cache_info->length,event_count,events,NULL,&status);
5466 assert(pixels == cache_info->pixels);
5467 events=(cl_event *) RelinquishMagickMemory(events);
5468 RelinquishOpenCLCommandQueue(clEnv,queue);
5470 cache_info->opencl=RelinquishOpenCLCacheInfo(clEnv,cache_info->opencl);
5472 UnlockSemaphoreInfo(cache_info->semaphore);
5475 MagickPrivate
void SyncAuthenticOpenCLBuffer(
const Image *image)
5478 *magick_restrict cache_info;
5480 assert(image != (
Image *)NULL);
5482 CopyOpenCLBuffer(cache_info);
5515 MagickExport MagickBooleanType SyncAuthenticPixelCacheNexus(
Image *image,
5519 *magick_restrict cache_info;
5527 assert(image != (
Image *) NULL);
5528 assert(image->signature == MagickCoreSignature);
5529 if (image->cache == (Cache) NULL)
5530 ThrowBinaryException(CacheError,
"PixelCacheIsNotOpen",image->filename);
5532 assert(cache_info->signature == MagickCoreSignature);
5533 if (cache_info->type == UndefinedCache)
5534 return(MagickFalse);
5535 if ((image->storage_class == DirectClass) &&
5536 (image->clip_mask != (
Image *) NULL) &&
5537 (ClipPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5538 return(MagickFalse);
5539 if ((image->storage_class == DirectClass) &&
5540 (image->mask != (
Image *) NULL) &&
5541 (MaskPixelCacheNexus(image,nexus_info,exception) == MagickFalse))
5542 return(MagickFalse);
5543 if (nexus_info->authentic_pixel_cache != MagickFalse)
5545 if (image->taint == MagickFalse)
5546 image->taint=MagickTrue;
5549 assert(cache_info->signature == MagickCoreSignature);
5550 status=WritePixelCachePixels(cache_info,nexus_info,exception);
5551 if ((cache_info->active_index_channel != MagickFalse) &&
5552 (WritePixelCacheIndexes(cache_info,nexus_info,exception) == MagickFalse))
5553 return(MagickFalse);
5554 if ((status != MagickFalse) && (image->taint == MagickFalse))
5555 image->taint=MagickTrue;
5586 static MagickBooleanType SyncAuthenticPixelsCache(
Image *image,
5590 *magick_restrict cache_info;
5593 id = GetOpenMPThreadId();
5598 assert(image != (
Image *) NULL);
5599 assert(image->signature == MagickCoreSignature);
5600 assert(image->cache != (Cache) NULL);
5602 assert(cache_info->signature == MagickCoreSignature);
5603 assert(
id < (
int) cache_info->number_threads);
5604 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[
id],
5636 MagickExport MagickBooleanType SyncAuthenticPixels(
Image *image,
5640 *magick_restrict cache_info;
5643 id = GetOpenMPThreadId();
5648 assert(image != (
Image *) NULL);
5649 assert(image->signature == MagickCoreSignature);
5650 assert(image->cache != (Cache) NULL);
5652 assert(cache_info->signature == MagickCoreSignature);
5653 if (cache_info->methods.sync_authentic_pixels_handler !=
5654 (SyncAuthenticPixelsHandler) NULL)
5655 return(cache_info->methods.sync_authentic_pixels_handler(image,exception));
5656 assert(
id < (
int) cache_info->number_threads);
5657 status=SyncAuthenticPixelCacheNexus(image,cache_info->nexus_info[
id],
5689 MagickPrivate MagickBooleanType SyncImagePixelCache(
Image *image,
5693 *magick_restrict cache_info;
5695 assert(image != (
Image *) NULL);
5697 cache_info=(
CacheInfo *) GetImagePixelCache(image,MagickTrue,exception);
5698 return(cache_info == (
CacheInfo *) NULL ? MagickFalse : MagickTrue);
5729 static MagickBooleanType WritePixelCacheIndexes(
CacheInfo *cache_info,
5749 if (cache_info->active_index_channel == MagickFalse)
5750 return(MagickFalse);
5751 if (nexus_info->authentic_pixel_cache != MagickFalse)
5753 if (nexus_info->indexes == (IndexPacket *) NULL)
5754 return(MagickFalse);
5755 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5756 nexus_info->region.x;
5757 length=(MagickSizeType) nexus_info->region.width*
sizeof(IndexPacket);
5758 rows=nexus_info->region.height;
5759 extent=(MagickSizeType) length*rows;
5760 p=nexus_info->indexes;
5762 switch (cache_info->type)
5773 if ((cache_info->columns == nexus_info->region.width) &&
5774 (extent == (MagickSizeType) ((
size_t) extent)))
5779 q=cache_info->indexes+offset;
5780 for (y=0; y < (ssize_t) rows; y++)
5782 (void) memcpy(q,p,(
size_t) length);
5783 p+=nexus_info->region.width;
5784 q+=cache_info->columns;
5793 LockSemaphoreInfo(cache_info->file_semaphore);
5794 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5796 ThrowFileException(exception,FileOpenError,
"UnableToOpenFile",
5797 cache_info->cache_filename);
5798 UnlockSemaphoreInfo(cache_info->file_semaphore);
5799 return(MagickFalse);
5801 if ((cache_info->columns == nexus_info->region.width) &&
5802 (extent <= MagickMaxBufferExtent))
5807 extent=(MagickSizeType) cache_info->columns*cache_info->rows;
5808 for (y=0; y < (ssize_t) rows; y++)
5810 count=WritePixelCacheRegion(cache_info,cache_info->offset+extent*
5811 sizeof(
PixelPacket)+offset*
sizeof(*p),length,(
const unsigned char *)
5813 if (count < (MagickOffsetType) length)
5815 p+=nexus_info->region.width;
5816 offset+=cache_info->columns;
5818 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5819 (void) ClosePixelCacheOnDisk(cache_info);
5820 UnlockSemaphoreInfo(cache_info->file_semaphore);
5823 case DistributedCache:
5831 LockSemaphoreInfo(cache_info->file_semaphore);
5832 region=nexus_info->region;
5833 if ((cache_info->columns != nexus_info->region.width) ||
5834 (extent > MagickMaxBufferExtent))
5841 for (y=0; y < (ssize_t) rows; y++)
5844 cache_info->server_info,®ion,length,(
const unsigned char *) p);
5845 if (count != (MagickOffsetType) length)
5847 p+=nexus_info->region.width;
5850 UnlockSemaphoreInfo(cache_info->file_semaphore);
5856 if (y < (ssize_t) rows)
5858 ThrowFileException(exception,CacheError,
"UnableToWritePixelCache",
5859 cache_info->cache_filename);
5860 return(MagickFalse);
5862 if ((cache_info->debug != MagickFalse) &&
5863 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
5864 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
5865 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
5866 nexus_info->region.width,(
double) nexus_info->region.height,(double)
5867 nexus_info->region.x,(
double) nexus_info->region.y);
5899 static MagickBooleanType WritePixelCachePixels(
CacheInfo *cache_info,
5919 if (nexus_info->authentic_pixel_cache != MagickFalse)
5921 offset=(MagickOffsetType) nexus_info->region.y*cache_info->columns+
5922 nexus_info->region.x;
5923 length=(MagickSizeType) nexus_info->region.width*
sizeof(
PixelPacket);
5924 rows=nexus_info->region.height;
5926 p=nexus_info->pixels;
5928 switch (cache_info->type)
5939 if ((cache_info->columns == nexus_info->region.width) &&
5940 (extent == (MagickSizeType) ((
size_t) extent)))
5945 q=cache_info->pixels+offset;
5946 for (y=0; y < (ssize_t) rows; y++)
5948 (void) memcpy(q,p,(
size_t) length);
5949 p+=nexus_info->region.width;
5950 q+=cache_info->columns;
5959 LockSemaphoreInfo(cache_info->file_semaphore);
5960 if (OpenPixelCacheOnDisk(cache_info,IOMode) == MagickFalse)
5962 ThrowFileException(exception,FileOpenError,
"UnableToOpenFile",
5963 cache_info->cache_filename);
5964 UnlockSemaphoreInfo(cache_info->file_semaphore);
5965 return(MagickFalse);
5967 if ((cache_info->columns == nexus_info->region.width) &&
5968 (extent <= MagickMaxBufferExtent))
5973 for (y=0; y < (ssize_t) rows; y++)
5975 count=WritePixelCacheRegion(cache_info,cache_info->offset+offset*
5976 sizeof(*p),length,(
const unsigned char *) p);
5977 if (count < (MagickOffsetType) length)
5979 p+=nexus_info->region.width;
5980 offset+=cache_info->columns;
5982 if (IsFileDescriptorLimitExceeded() != MagickFalse)
5983 (void) ClosePixelCacheOnDisk(cache_info);
5984 UnlockSemaphoreInfo(cache_info->file_semaphore);
5987 case DistributedCache:
5995 LockSemaphoreInfo(cache_info->file_semaphore);
5996 region=nexus_info->region;
5997 if ((cache_info->columns != nexus_info->region.width) ||
5998 (extent > MagickMaxBufferExtent))
6005 for (y=0; y < (ssize_t) rows; y++)
6008 cache_info->server_info,®ion,length,(
const unsigned char *) p);
6009 if (count != (MagickOffsetType) length)
6011 p+=nexus_info->region.width;
6014 UnlockSemaphoreInfo(cache_info->file_semaphore);
6020 if (y < (ssize_t) rows)
6022 ThrowFileException(exception,CacheError,
"UnableToWritePixelCache",
6023 cache_info->cache_filename);
6024 return(MagickFalse);
6026 if ((cache_info->debug != MagickFalse) &&
6027 (CacheTick(nexus_info->region.y,cache_info->rows) != MagickFalse))
6028 (void) LogMagickEvent(CacheEvent,GetMagickModule(),
6029 "%s[%.20gx%.20g%+.20g%+.20g]",cache_info->filename,(double)
6030 nexus_info->region.width,(
double) nexus_info->region.height,(double)
6031 nexus_info->region.x,(
double) nexus_info->region.y);