DML Lock fixed for cuda and CPU

This commit is contained in:
Kenneth Estanislao
2026-04-01 23:56:01 +08:00
parent 1f3668f7c1
commit 1edc4bc298
3 changed files with 28 additions and 76 deletions
+10 -71
View File
@@ -1097,41 +1097,10 @@ def _capture_thread_func(cap, capture_queue, stop_event):
pass
def _detection_thread_func(latest_frame_holder, detection_result, detection_lock, stop_event):
"""Detection thread: continuously runs face detection on the latest
captured frame and stores results in detection_result under detection_lock.
This decouples face detection (~15-30ms) from face swapping (~5-10ms)
so the swap loop never blocks on detection, significantly improving
live mode FPS."""
while not stop_event.is_set():
with detection_lock:
frame = latest_frame_holder[0]
if frame is None:
time.sleep(0.2)
continue
if modules.globals.many_faces:
many = get_many_faces(frame)
with detection_lock:
detection_result['target_face'] = None
detection_result['many_faces'] = many
else:
face = get_one_face(frame)
with detection_lock:
detection_result['target_face'] = face
detection_result['many_faces'] = None
def _processing_thread_func(capture_queue, processed_queue, stop_event,
latest_frame_holder, detection_result, detection_lock):
"""Processing thread: takes raw frames from capture_queue, reads the
latest detection result from the shared detection_result dict, applies
face swap/enhancement, and puts results into processed_queue.
Face detection runs concurrently in _detection_thread_func — this thread
only reads cached results so it never blocks on detection."""
def _processing_thread_func(capture_queue, processed_queue, stop_event):
"""Processing thread: takes raw frames from capture_queue, runs face
detection (throttled to every 3rd frame), applies face swap/enhancement,
and puts results into processed_queue."""
frame_processors = get_frame_processors_modules(modules.globals.frame_processors)
source_image = None
last_source_path = None
@@ -1139,6 +1108,9 @@ def _processing_thread_func(capture_queue, processed_queue, stop_event,
fps_update_interval = 0.5
frame_count = 0
fps = 0
det_count = 0
cached_target_face = None
cached_many_faces = None
while not stop_event.is_set():
try:
@@ -1151,34 +1123,20 @@ def _processing_thread_func(capture_queue, processed_queue, stop_event,
if modules.globals.live_mirror:
temp_frame = gpu_flip(temp_frame, 1)
# Publish the mirrored frame for the detection thread to pick up
with detection_lock:
latest_frame_holder[0] = temp_frame
if not modules.globals.map_faces:
if modules.globals.source_path and modules.globals.source_path != last_source_path:
last_source_path = modules.globals.source_path
source_image = get_one_face(cv2.imread(modules.globals.source_path))
# Read latest detection results (brief lock to avoid blocking detection thread)
# Run detection inline since detection thread is disabled
# Run detection every 3 frames, reuse cached result otherwise
if not hasattr(_processing_thread_func, '_det_count'):
_processing_thread_func._det_count = 0
_processing_thread_func._det_count += 1
if _processing_thread_func._det_count % 3 == 0:
det_count += 1
if det_count % 3 == 0:
if modules.globals.many_faces:
cached_target_face = None
cached_many_faces = get_many_faces(temp_frame)
detection_result['many_faces'] = cached_many_faces
else:
cached_target_face = get_one_face(temp_frame)
cached_many_faces = None
detection_result['target_face'] = cached_target_face
else:
cached_target_face = detection_result.get('target_face')
cached_many_faces = detection_result.get('many_faces')
for frame_processor in frame_processors:
if frame_processor.NAME == "DLC.FACE-ENHANCER":
@@ -1271,14 +1229,6 @@ def create_webcam_preview(camera_index: int):
processed_queue = queue.Queue(maxsize=2)
stop_event = threading.Event()
# Shared state for the detection pipeline.
# latest_frame_holder[0] is the most recent raw frame for the detection
# thread; detection_result holds the last detected faces for the
# processing thread to read. Both are guarded by detection_lock.
detection_lock = threading.Lock()
latest_frame_holder = [None]
detection_result = {'target_face': None, 'many_faces': None}
# Start capture thread
cap_thread = threading.Thread(
target=_capture_thread_func,
@@ -1287,20 +1237,10 @@ def create_webcam_preview(camera_index: int):
)
cap_thread.start()
# Start detection thread — runs face detection asynchronously so the
# processing/swap thread never blocks on it
det_thread = threading.Thread(
target=_detection_thread_func,
args=(latest_frame_holder, detection_result, detection_lock, stop_event),
daemon=True,
)
# det_thread.start()
# Start processing thread
proc_thread = threading.Thread(
target=_processing_thread_func,
args=(capture_queue, processed_queue, stop_event,
latest_frame_holder, detection_result, detection_lock),
args=(capture_queue, processed_queue, stop_event),
daemon=True,
)
proc_thread.start()
@@ -1309,7 +1249,6 @@ def create_webcam_preview(camera_index: int):
def _cleanup():
stop_event.set()
cap_thread.join(timeout=2.0)
det_thread.join(timeout=2.0)
proc_thread.join(timeout=2.0)
cap.release()
PREVIEW.withdraw()