comparison mupdf-source/thirdparty/lcms2/plugins/threaded/src/threaded_split.c @ 2:b50eed0cc0ef upstream

ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4. The directory name has changed: no version number in the expanded directory now.
author Franz Glasner <fzglas.hg@dom66.de>
date Mon, 15 Sep 2025 11:43:07 +0200
parents
children
comparison
equal deleted inserted replaced
1:1d09e1dec1d9 2:b50eed0cc0ef
1 //---------------------------------------------------------------------------------
2 //
3 // Little Color Management System, fast floating point extensions
4 // Copyright (c) 1998-2023 Marti Maria Saguer, all rights reserved
5 //
6 //
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU General Public License as published by
9 // the Free Software Foundation, either version 3 of the License, or
10 // (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 //
20 //---------------------------------------------------------------------------------
21
22
23 #include "threaded_internal.h"
24
25
26 // Returns true component size
27 cmsINLINE cmsUInt32Number ComponentSize(cmsUInt32Number format)
28 {
29 cmsUInt32Number BytesPerComponent = T_BYTES(format);
30
31 // For double, the T_BYTES field is zero
32 if (BytesPerComponent == 0)
33 BytesPerComponent = sizeof(cmsUInt64Number);
34
35 return BytesPerComponent;
36 }
37
38 // Returns bytes from one pixel to the next
39 cmsINLINE cmsUInt32Number PixelSpacing(cmsUInt32Number format)
40 {
41 if (T_PLANAR(format))
42 return ComponentSize(format);
43 else
44 return ComponentSize(format) * (T_CHANNELS(format) + T_EXTRA(format));
45 }
46
47 // macro is not portable
48 cmsINLINE cmsUInt32Number minimum(cmsUInt32Number a, cmsUInt32Number b)
49 {
50 return a < b ? a : b;
51 }
52
53
54 // Memory of block depends of planar or chunky. If lines is 1, then the stride does not contain
55 // information and we have to calculate the size. If lines > 1, then we can take line size from stride.
56 // if planar, total memory is number of planes per plane stride. If chunky memory is number of lines per
57 // line size. If line size is zero, then it should be computed.
58 static
59 cmsUInt32Number MemSize(cmsUInt32Number format,
60 cmsUInt32Number PixelsPerLine,
61 cmsUInt32Number LineCount,
62 cmsUInt32Number* BytesPerLine,
63 cmsUInt32Number BytesPerPlane)
64 {
65 if (T_PLANAR(format)) {
66
67 if (*BytesPerLine == 0) {
68
69 *BytesPerLine = ComponentSize(format) * PixelsPerLine;
70 }
71
72 return (T_CHANNELS(format) + T_EXTRA(format)) * BytesPerPlane;
73 }
74 else
75 {
76 if (*BytesPerLine == 0) {
77
78 *BytesPerLine = ComponentSize(format) * (T_CHANNELS(format) + T_EXTRA(format)) * PixelsPerLine;
79 }
80
81 return LineCount * *BytesPerLine;
82 }
83 }
84
85 // Compute how many workers to use. Repairs Stride if any missing member
86 cmsUInt32Number _cmsThrCountSlices(struct _cmstransform_struct* CMMcargo, cmsInt32Number MaxWorkers,
87 cmsUInt32Number PixelsPerLine, cmsUInt32Number LineCount,
88 cmsStride* Stride)
89 {
90 cmsInt32Number MaxInputMem, MaxOutputMem;
91 cmsInt32Number WorkerCount;
92
93 cmsInt32Number MaxCPUs = _cmsThrIdealThreadCount();
94
95 if (MaxWorkers == CMS_THREADED_GUESS_MAX_THREADS) {
96 MaxWorkers = MaxCPUs;
97 }
98 else
99 {
100 // We allow large number of threads, but this is not going to work well. Warn it.
101 if (MaxWorkers > MaxCPUs) {
102 cmsSignalError(NULL, cmsERROR_RANGE,
103 "Warning: too many threads for actual processor (CPUs=%d, asked=%d)", MaxCPUs, MaxWorkers);
104 }
105 }
106
107 MaxInputMem = MemSize(cmsGetTransformInputFormat((cmsHTRANSFORM)CMMcargo),
108 PixelsPerLine, LineCount, &Stride->BytesPerLineIn, Stride->BytesPerPlaneIn);
109
110 MaxOutputMem = MemSize(cmsGetTransformOutputFormat((cmsHTRANSFORM)CMMcargo),
111 PixelsPerLine, LineCount, &Stride->BytesPerLineOut, Stride->BytesPerPlaneOut);
112
113 // Each thread takes 128K at least
114 WorkerCount = (MaxInputMem + MaxOutputMem) / (128 * 1024);
115
116 if (WorkerCount < 1)
117 WorkerCount = 1;
118 else
119 if (WorkerCount > MaxWorkers)
120 WorkerCount = MaxWorkers;
121
122 return WorkerCount;
123 }
124
125 // Slice input, output for lines
126 static
127 void SlicePerLines(const _cmsWorkSlice* master, cmsInt32Number nslices,
128 cmsInt32Number LinesPerSlice, _cmsWorkSlice slices[])
129 {
130 cmsInt32Number i;
131 cmsInt32Number TotalLines = master ->LineCount;
132
133 for (i = 0; i < nslices; i++) {
134
135 const cmsUInt8Number* PtrInput = master->InputBuffer;
136 cmsUInt8Number* PtrOutput = master->OutputBuffer;
137
138 cmsInt32Number lines = minimum(LinesPerSlice, TotalLines);
139
140 memcpy(&slices[i], master, sizeof(_cmsWorkSlice));
141
142 slices[i].InputBuffer = PtrInput + i * LinesPerSlice * master->Stride->BytesPerLineIn;
143 slices[i].OutputBuffer = PtrOutput + i * LinesPerSlice * master->Stride->BytesPerLineOut;
144
145 slices[i].LineCount = lines;
146 TotalLines -= lines;
147 }
148
149 // Add left lines because rounding
150 if (slices > 0) slices[nslices - 1].LineCount += TotalLines;
151 }
152
153 // Per pixels on big blocks of one line
154 static
155 void SlicePerPixels(const _cmsWorkSlice* master, cmsInt32Number nslices,
156 cmsInt32Number PixelsPerSlice, _cmsWorkSlice slices[])
157 {
158 cmsInt32Number i;
159 cmsInt32Number TotalPixels = master->PixelsPerLine; // As this works on one line only
160
161 cmsUInt32Number PixelSpacingIn = PixelSpacing(cmsGetTransformInputFormat((cmsHTRANSFORM)master->CMMcargo));
162 cmsUInt32Number PixelSpacingOut = PixelSpacing(cmsGetTransformOutputFormat((cmsHTRANSFORM)master->CMMcargo));
163
164 for (i = 0; i < nslices; i++) {
165
166 const cmsUInt8Number* PtrInput = master->InputBuffer;
167 cmsUInt8Number* PtrOutput = master->OutputBuffer;
168
169 cmsInt32Number pixels = minimum(PixelsPerSlice, TotalPixels);
170
171 memcpy(&slices[i], master, sizeof(_cmsWorkSlice));
172
173 slices[i].InputBuffer = PtrInput + i * PixelsPerSlice * PixelSpacingIn;
174 slices[i].OutputBuffer = PtrOutput + i * PixelsPerSlice * PixelSpacingOut;
175 slices[i].PixelsPerLine = pixels;
176
177 TotalPixels -= pixels;
178 }
179
180 // Add left pixels because rounding
181 if (slices > 0) slices[nslices - 1].PixelsPerLine += TotalPixels;
182 }
183
184
185 // If multiline, assign a number of lines to each thread. This works on chunky and planar. Stride parameters
186 // are not changed. In the case of one line, stride chunky is not used and stride planar keeps same.
187 cmsBool _cmsThrSplitWork(const _cmsWorkSlice* master, cmsInt32Number nslices, _cmsWorkSlice slices[])
188 {
189
190 // Check parameters
191 if (master->PixelsPerLine == 0 ||
192 master->Stride->BytesPerLineIn == 0 ||
193 master->Stride->BytesPerLineOut == 0) return FALSE;
194
195 // Do the splitting depending on lines
196 if (master->LineCount <= 1) {
197
198 cmsInt32Number PixelsPerWorker = master->PixelsPerLine / nslices;
199
200 if (PixelsPerWorker <= 0)
201 return FALSE;
202 else
203 SlicePerPixels(master, nslices, PixelsPerWorker, slices);
204 }
205 else {
206
207 cmsInt32Number LinesPerWorker = master->LineCount / nslices;
208
209 if (LinesPerWorker <= 0)
210 return FALSE;
211 else
212 SlicePerLines(master, nslices, LinesPerWorker, slices);
213 }
214
215 return TRUE;
216 }