|
1 | 1 | # Copyright (c) 2025, NVIDIA CORPORATION. |
2 | 2 | # SPDX-License-Identifier: BSD-3-Clause |
| 3 | +import os |
| 4 | +import threading |
3 | 5 | import warnings |
4 | 6 | from typing import Literal |
5 | 7 |
|
@@ -70,10 +72,10 @@ def __init__( |
70 | 72 | self.decode_params = nvimgcodec.DecodeParams( |
71 | 73 | color_spec=color_space_map[color_space.replace("8", "")] |
72 | 74 | ) |
73 | | - self.decoder = nvimgcodec.Decoder( |
74 | | - device_id=device, |
75 | | - max_num_cpu_threads=1, |
76 | | - ) |
| 75 | + self.device = device |
| 76 | + |
| 77 | + self._thread_local = threading.local() |
| 78 | + self._creator_pid = os.getpid() |
77 | 79 |
|
78 | 80 | def __call__(self, key: str, data: bytes) -> torch.Tensor | None: |
79 | 81 | """Decode image data using the GPU accelerated decoder |
@@ -106,7 +108,26 @@ def __call__(self, key: str, data: bytes) -> torch.Tensor | None: |
106 | 108 | ) |
107 | 109 | ): |
108 | 110 | return None |
109 | | - nv_img = self.decoder.decode(data, params=self.decode_params) |
| 111 | + |
| 112 | + if os.getpid() != self._creator_pid: |
| 113 | + raise RuntimeError( |
| 114 | + "GPU image decoding requires thread-based dataloader workers, set worker_type='thread' or worker_type='main'." |
| 115 | + ) |
| 116 | + |
| 117 | + decoder = getattr(self._thread_local, "decoder", None) |
| 118 | + if decoder is None: |
| 119 | + decoder = self._thread_local.decoder = nvimgcodec.Decoder( |
| 120 | + device_id=self.device, |
| 121 | + max_num_cpu_threads=1, |
| 122 | + ) |
| 123 | + self.thread_local.stream = torch.cuda.Stream(self.device) |
| 124 | + |
| 125 | + stream = self._thread_local.stream |
| 126 | + |
| 127 | + nv_img = self.decoder.decode( |
| 128 | + data, params=self.decode_params, cuda_stream=stream.cuda_stream |
| 129 | + ) |
| 130 | + stream.synchronize() # ensure nv_img lands on the default cuda stream |
110 | 131 |
|
111 | 132 | if hasattr(nv_img, "__dlpack__"): |
112 | 133 | tensor_img = torch.from_dlpack(nv_img).permute(2, 0, 1) |
|
0 commit comments