@@ -17,9 +17,12 @@ namespace facebook::torchcodec {
1717// each. P016 uses 16-bit samples (uint16_t) with actual data in the most
1818// significant bits (right-shifted by 16 - bitDepth).
1919
20- // Color conversion matrix stored in constant memory for fast access.
21- // It is available to every single thread.
22- __constant__ float d_colorMatrix[3 ][4 ];
20+ // Wraps the 3x4 color-conversion matrix so it can be passed as a kernel param,
21+ // to ensure thread-safety (previous implem had it __global__, which wasn't
22+ // safe)
23+ struct ColorMatrix {
24+ float m[3 ][4 ];
25+ };
2326
2427// Takes a pair of consecutive Y values, a pair of UV values, and writes the
2528// corresponding two RGB values. Instead of writing each ra ga ba and rb gb bb
@@ -34,33 +37,34 @@ __device__ void writePairOfRGBPixels(
3437 float u,
3538 float v,
3639 T* rgbPlaneToWrite,
37- int bitShift) {
40+ int bitShift,
41+ const ColorMatrix& cm) {
3842 constexpr float clampMax = sizeof (T) == 1 ? 255 .0f : 65535 .0f ;
3943
4044 float ya = static_cast <float >(yayb.x >> bitShift);
4145 float yb = static_cast <float >(yayb.y >> bitShift);
4246
43- float ra = d_colorMatrix [0 ][0 ] * ya + d_colorMatrix [0 ][1 ] * u +
44- d_colorMatrix [0 ][2 ] * v + d_colorMatrix [0 ][3 ];
45- float ga = d_colorMatrix [1 ][0 ] * ya + d_colorMatrix [1 ][1 ] * u +
46- d_colorMatrix [1 ][2 ] * v + d_colorMatrix [1 ][3 ];
47+ float ra = cm. m [0 ][0 ] * ya + cm. m [0 ][1 ] * u +
48+ cm. m [0 ][2 ] * v + cm. m [0 ][3 ];
49+ float ga = cm. m [1 ][0 ] * ya + cm. m [1 ][1 ] * u +
50+ cm. m [1 ][2 ] * v + cm. m [1 ][3 ];
4751
4852 Vec2T raga = {static_cast <T>(fminf (fmaxf (ra, 0 .0f ), clampMax)),
4953 static_cast <T>(fminf (fmaxf (ga, 0 .0f ), clampMax))};
5054 *(reinterpret_cast <Vec2T*>(&rgbPlaneToWrite[0 ])) = raga;
5155
52- float ba = d_colorMatrix [2 ][0 ] * ya + d_colorMatrix [2 ][1 ] * u +
53- d_colorMatrix [2 ][2 ] * v + d_colorMatrix [2 ][3 ];
54- float rb = d_colorMatrix [0 ][0 ] * yb + d_colorMatrix [0 ][1 ] * u +
55- d_colorMatrix [0 ][2 ] * v + d_colorMatrix [0 ][3 ];
56+ float ba = cm. m [2 ][0 ] * ya + cm. m [2 ][1 ] * u +
57+ cm. m [2 ][2 ] * v + cm. m [2 ][3 ];
58+ float rb = cm. m [0 ][0 ] * yb + cm. m [0 ][1 ] * u +
59+ cm. m [0 ][2 ] * v + cm. m [0 ][3 ];
5660 Vec2T barb = {static_cast <T>(fminf (fmaxf (ba, 0 .0f ), clampMax)),
5761 static_cast <T>(fminf (fmaxf (rb, 0 .0f ), clampMax))};
5862 *(reinterpret_cast <Vec2T*>(&rgbPlaneToWrite[2 ])) = barb;
5963
60- float gb = d_colorMatrix [1 ][0 ] * yb + d_colorMatrix [1 ][1 ] * u +
61- d_colorMatrix [1 ][2 ] * v + d_colorMatrix [1 ][3 ];
62- float bb = d_colorMatrix [2 ][0 ] * yb + d_colorMatrix [2 ][1 ] * u +
63- d_colorMatrix [2 ][2 ] * v + d_colorMatrix [2 ][3 ];
64+ float gb = cm. m [1 ][0 ] * yb + cm. m [1 ][1 ] * u +
65+ cm. m [1 ][2 ] * v + cm. m [1 ][3 ];
66+ float bb = cm. m [2 ][0 ] * yb + cm. m [2 ][1 ] * u +
67+ cm. m [2 ][2 ] * v + cm. m [2 ][3 ];
6468 Vec2T gbbb = {static_cast <T>(fminf (fmaxf (gb, 0 .0f ), clampMax)),
6569 static_cast <T>(fminf (fmaxf (bb, 0 .0f ), clampMax))};
6670 *(reinterpret_cast <Vec2T*>(&rgbPlaneToWrite[4 ])) = gbbb;
@@ -95,7 +99,8 @@ __global__ void yuvToRgbKernel(
9599 int yPitchElements,
96100 int uvPitchElements,
97101 int rgbPitchElements,
98- int bitShift) {
102+ int bitShift,
103+ const ColorMatrix cm) {
99104 // The kernel operates on 2x2 blocks, so it's called H / 2 * W / 2 times.
100105 // We have to multiply back by 2 to retrieve the output pixel coordinates x
101106 // and y.
@@ -120,33 +125,12 @@ __global__ void yuvToRgbKernel(
120125
121126 T* rgbPlaneToWrite = rgbOutput + y * rgbPitchElements + x * 3 ;
122127 writePairOfRGBPixels<T, Vec2T>(
123- y1y2, u, v, rgbPlaneToWrite, bitShift);
128+ y1y2, u, v, rgbPlaneToWrite, bitShift, cm );
124129 rgbPlaneToWrite += rgbPitchElements; // go to next line
125130 writePairOfRGBPixels<T, Vec2T>(
126- y3y4, u, v, rgbPlaneToWrite, bitShift);
131+ y3y4, u, v, rgbPlaneToWrite, bitShift, cm );
127132}
128133
129- namespace {
130-
131- void maybeUploadColorMatrix (
132- const float colorMatrix[3 ][4 ],
133- bool colorMatrixChanged) {
134- // We only send the color-matrix from CPU to GPU if it changed.
135- // In practice it probably doesn't impact perf that much since decoding is
136- // bottlenecked by NVDEC's frame mapping, not color-conversion. But it's a
137- // simple optimization, so we do it anyway.
138- if (colorMatrixChanged) {
139- cudaMemcpyToSymbol (
140- d_colorMatrix,
141- colorMatrix,
142- sizeof (float ) * 12 ,
143- 0 ,
144- cudaMemcpyHostToDevice);
145- }
146- }
147-
148- } // namespace
149-
150134void launchNV12ToRGBKernel (
151135 const uint8_t * yPlane,
152136 const uint8_t * uvPlane,
@@ -157,9 +141,9 @@ void launchNV12ToRGBKernel(
157141 int uvPitch,
158142 int rgbPitch,
159143 const float colorMatrix[3 ][4 ],
160- bool colorMatrixChanged,
161144 cudaStream_t stream) {
162- maybeUploadColorMatrix (colorMatrix, colorMatrixChanged);
145+ const auto & cm =
146+ *reinterpret_cast <const ColorMatrix*>(colorMatrix);
163147
164148 dim3 block (32 , 2 );
165149 dim3 grid (
@@ -175,7 +159,8 @@ void launchNV12ToRGBKernel(
175159 yPitch,
176160 uvPitch,
177161 rgbPitch,
178- 0 ); // bitShift = 0 for NV12
162+ 0 , // bitShift = 0 for NV12
163+ cm);
179164}
180165
181166void launchP016ToRGB16Kernel (
@@ -189,9 +174,9 @@ void launchP016ToRGB16Kernel(
189174 int rgbPitch,
190175 int bitDepth,
191176 const float colorMatrix[3 ][4 ],
192- bool colorMatrixChanged,
193177 cudaStream_t stream) {
194- maybeUploadColorMatrix (colorMatrix, colorMatrixChanged);
178+ const auto & cm =
179+ *reinterpret_cast <const ColorMatrix*>(colorMatrix);
195180
196181 int yPitchElements =
197182 yPitch / static_cast <int >(sizeof (uint16_t ));
@@ -215,7 +200,8 @@ void launchP016ToRGB16Kernel(
215200 yPitchElements,
216201 uvPitchElements,
217202 rgbPitchElements,
218- bitShift);
203+ bitShift,
204+ cm);
219205}
220206
221207// RGB -> NV12 kernel for encoding.
@@ -229,7 +215,8 @@ __global__ void rgbToNV12Kernel(
229215 int height,
230216 int rgbPitchElements,
231217 int yPitchElements,
232- int uvPitchElements) {
218+ int uvPitchElements,
219+ const ColorMatrix cm) {
233220 int x = (blockIdx .x * blockDim .x + threadIdx .x ) * 2 ;
234221 int y = (blockIdx .y * blockDim .y + threadIdx .y ) * 2 ;
235222 if (x + 1 >= width || y + 1 >= height) {
@@ -247,18 +234,18 @@ __global__ void rgbToNV12Kernel(
247234 float r11 = row1[3 ], g11 = row1[4 ], b11 = row1[5 ];
248235
249236 // Compute Y for all 4 pixels
250- float y00 = d_colorMatrix [0 ][0 ] * r00 +
251- d_colorMatrix [0 ][1 ] * g00 + d_colorMatrix [0 ][2 ] * b00 +
252- d_colorMatrix [0 ][3 ];
253- float y01 = d_colorMatrix [0 ][0 ] * r01 +
254- d_colorMatrix [0 ][1 ] * g01 + d_colorMatrix [0 ][2 ] * b01 +
255- d_colorMatrix [0 ][3 ];
256- float y10 = d_colorMatrix [0 ][0 ] * r10 +
257- d_colorMatrix [0 ][1 ] * g10 + d_colorMatrix [0 ][2 ] * b10 +
258- d_colorMatrix [0 ][3 ];
259- float y11 = d_colorMatrix [0 ][0 ] * r11 +
260- d_colorMatrix [0 ][1 ] * g11 + d_colorMatrix [0 ][2 ] * b11 +
261- d_colorMatrix [0 ][3 ];
237+ float y00 = cm. m [0 ][0 ] * r00 +
238+ cm. m [0 ][1 ] * g00 + cm. m [0 ][2 ] * b00 +
239+ cm. m [0 ][3 ];
240+ float y01 = cm. m [0 ][0 ] * r01 +
241+ cm. m [0 ][1 ] * g01 + cm. m [0 ][2 ] * b01 +
242+ cm. m [0 ][3 ];
243+ float y10 = cm. m [0 ][0 ] * r10 +
244+ cm. m [0 ][1 ] * g10 + cm. m [0 ][2 ] * b10 +
245+ cm. m [0 ][3 ];
246+ float y11 = cm. m [0 ][0 ] * r11 +
247+ cm. m [0 ][1 ] * g11 + cm. m [0 ][2 ] * b11 +
248+ cm. m [0 ][3 ];
262249
263250 // Write Y plane
264251 uchar2 yRow0 = {
@@ -278,31 +265,31 @@ __global__ void rgbToNV12Kernel(
278265 &yPlane[(y + 1 ) * yPitchElements + x])) = yRow1;
279266
280267 // Compute U,V for all 4 pixels and average for 4:2:0 subsampling
281- float u00 = d_colorMatrix [1 ][0 ] * r00 +
282- d_colorMatrix [1 ][1 ] * g00 + d_colorMatrix [1 ][2 ] * b00 +
283- d_colorMatrix [1 ][3 ];
284- float u01 = d_colorMatrix [1 ][0 ] * r01 +
285- d_colorMatrix [1 ][1 ] * g01 + d_colorMatrix [1 ][2 ] * b01 +
286- d_colorMatrix [1 ][3 ];
287- float u10 = d_colorMatrix [1 ][0 ] * r10 +
288- d_colorMatrix [1 ][1 ] * g10 + d_colorMatrix [1 ][2 ] * b10 +
289- d_colorMatrix [1 ][3 ];
290- float u11 = d_colorMatrix [1 ][0 ] * r11 +
291- d_colorMatrix [1 ][1 ] * g11 + d_colorMatrix [1 ][2 ] * b11 +
292- d_colorMatrix [1 ][3 ];
293-
294- float v00 = d_colorMatrix [2 ][0 ] * r00 +
295- d_colorMatrix [2 ][1 ] * g00 + d_colorMatrix [2 ][2 ] * b00 +
296- d_colorMatrix [2 ][3 ];
297- float v01 = d_colorMatrix [2 ][0 ] * r01 +
298- d_colorMatrix [2 ][1 ] * g01 + d_colorMatrix [2 ][2 ] * b01 +
299- d_colorMatrix [2 ][3 ];
300- float v10 = d_colorMatrix [2 ][0 ] * r10 +
301- d_colorMatrix [2 ][1 ] * g10 + d_colorMatrix [2 ][2 ] * b10 +
302- d_colorMatrix [2 ][3 ];
303- float v11 = d_colorMatrix [2 ][0 ] * r11 +
304- d_colorMatrix [2 ][1 ] * g11 + d_colorMatrix [2 ][2 ] * b11 +
305- d_colorMatrix [2 ][3 ];
268+ float u00 = cm. m [1 ][0 ] * r00 +
269+ cm. m [1 ][1 ] * g00 + cm. m [1 ][2 ] * b00 +
270+ cm. m [1 ][3 ];
271+ float u01 = cm. m [1 ][0 ] * r01 +
272+ cm. m [1 ][1 ] * g01 + cm. m [1 ][2 ] * b01 +
273+ cm. m [1 ][3 ];
274+ float u10 = cm. m [1 ][0 ] * r10 +
275+ cm. m [1 ][1 ] * g10 + cm. m [1 ][2 ] * b10 +
276+ cm. m [1 ][3 ];
277+ float u11 = cm. m [1 ][0 ] * r11 +
278+ cm. m [1 ][1 ] * g11 + cm. m [1 ][2 ] * b11 +
279+ cm. m [1 ][3 ];
280+
281+ float v00 = cm. m [2 ][0 ] * r00 +
282+ cm. m [2 ][1 ] * g00 + cm. m [2 ][2 ] * b00 +
283+ cm. m [2 ][3 ];
284+ float v01 = cm. m [2 ][0 ] * r01 +
285+ cm. m [2 ][1 ] * g01 + cm. m [2 ][2 ] * b01 +
286+ cm. m [2 ][3 ];
287+ float v10 = cm. m [2 ][0 ] * r10 +
288+ cm. m [2 ][1 ] * g10 + cm. m [2 ][2 ] * b10 +
289+ cm. m [2 ][3 ];
290+ float v11 = cm. m [2 ][0 ] * r11 +
291+ cm. m [2 ][1 ] * g11 + cm. m [2 ][2 ] * b11 +
292+ cm. m [2 ][3 ];
306293
307294 float uAvg = (u00 + u01 + u10 + u11) * 0 .25f ;
308295 float vAvg = (v00 + v01 + v10 + v11) * 0 .25f ;
@@ -327,12 +314,8 @@ void launchRGBToNV12Kernel(
327314 int uvPitch,
328315 const float colorMatrix[3 ][4 ],
329316 cudaStream_t stream) {
330- cudaMemcpyToSymbol (
331- d_colorMatrix,
332- colorMatrix,
333- sizeof (float ) * 12 ,
334- 0 ,
335- cudaMemcpyHostToDevice);
317+ const auto & cm =
318+ *reinterpret_cast <const ColorMatrix*>(colorMatrix);
336319
337320 dim3 block (32 , 2 );
338321 dim3 grid (
@@ -347,7 +330,8 @@ void launchRGBToNV12Kernel(
347330 height,
348331 rgbPitch,
349332 yPitch,
350- uvPitch);
333+ uvPitch,
334+ cm);
351335}
352336
353337} // namespace facebook::torchcodec
0 commit comments