diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 0a13278..2a23ec9 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -91,7 +91,10 @@ "Bash(tasklist)", "Bash(\"/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/MSBuild.exe\" \"D:/Project/video-av1/vav2/platforms/windows/applications/vav2player/Vav2Player/Vav2Player.vcxproj\" //p:Configuration=Debug //p:Platform=x64 //t:Clean)", "Bash(./Vav2Player.exe)", - "Bash(\"/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/MSBuild.exe\" Vav2Player.vcxproj //p:Configuration=Debug //p:Platform=x64 //v:minimal)" + "Bash(\"/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/MSBuild.exe\" Vav2Player.vcxproj //p:Configuration=Debug //p:Platform=x64 //v:minimal)", + "Bash(git checkout:*)", + "Bash(python:*)", + "Bash(\"C:\\Users\\emocr\\AppData\\Local\\Microsoft\\WindowsApps\\python.exe\" fix_logf.py)" ], "deny": [], "ask": [] diff --git a/vav2/CLAUDE.md b/vav2/CLAUDE.md index 92a7633..384ef8a 100644 --- a/vav2/CLAUDE.md +++ b/vav2/CLAUDE.md @@ -51,6 +51,25 @@ size_t required_size = frame.width * frame.height * 4; // [ERROR] Failed to initialize D3D12 device ``` +### πŸ§ͺ **ν…ŒμŠ€νŠΈ μ½”λ“œ κ·œμΉ™ (REQUIRED)** +**🚨 μ€‘μš”**: ν…ŒμŠ€νŠΈ μ½”λ“œλŠ” **μ ˆλŒ€λ‘œ ν”„λ‘œλ•μ…˜ μ½”λ“œμ— μž‘μ„±ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€**. + +#### κΈˆμ§€ 사항 +- ❌ `App.xaml.cpp`에 ν…ŒμŠ€νŠΈ ν•¨μˆ˜ μΆ”κ°€ κΈˆμ§€ +- ❌ `MainWindow.xaml.cpp`에 ν…ŒμŠ€νŠΈ μ½”λ“œ μΆ”κ°€ κΈˆμ§€ +- ❌ ν”„λ‘œλ•μ…˜ ν΄λž˜μŠ€μ— `Test*()` ν•¨μˆ˜ μΆ”κ°€ κΈˆμ§€ +- ❌ ν”„λ‘œλ•μ…˜ μ½”λ“œμ— μž„μ‹œ 검증 둜직 μΆ”κ°€ κΈˆμ§€ + +#### ν…ŒμŠ€νŠΈ μ½”λ“œ μž‘μ„± μœ„μΉ˜ +βœ… **λ°˜λ“œμ‹œ 별도 ν…ŒμŠ€νŠΈ ν”„λ‘œμ νŠΈμ— μž‘μ„±**: +- `vav2/platforms/windows/tests/unit-tests/` - λ‹¨μœ„ ν…ŒμŠ€νŠΈ +- `vav2/platforms/windows/tests/headless/` - ν—€λ“œλ¦¬μŠ€ 톡합 ν…ŒμŠ€νŠΈ +- `vav2/platforms/windows/tests/integration/` - 톡합 ν…ŒμŠ€νŠΈ + +#### 이유 +- ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό ν”„λ‘œλ•μ…˜ νŒŒμΌμ— μž‘μ„± β†’ λΉŒλ“œ ν›„ 제거λ₯Ό μžŠμ–΄λ²„λ¦Ό β†’ 반볡적인 문제 λ°œμƒ +- λͺ…ν™•ν•œ 뢄리λ₯Ό ν†΅ν•œ μ½”λ“œ 관리 및 μœ μ§€λ³΄μˆ˜μ„± ν–₯상 + --- ## 🎯 **ν˜„μž¬ ν”„λ‘œμ νŠΈ μƒνƒœ** (2025-10-01) diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/App.xaml.cpp b/vav2/platforms/windows/applications/vav2player/Vav2Player/App.xaml.cpp index b31063c..22a0b4b 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/App.xaml.cpp +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/App.xaml.cpp @@ -9,43 +9,21 @@ using namespace winrt::Microsoft::UI::Xaml; namespace winrt::Vav2Player::implementation { - // Simple VavCore test function - void TestVavCoreIntegration() - { - // Test VavCore C API - VavCoreResult result = vavcore_initialize(); - if (result == VAVCORE_SUCCESS) - { - const char* version = vavcore_get_version_string(); - LOGF_INFO("[App] VavCore initialized successfully, version: %s", version); - - // Test creating a player - VavCorePlayer* player = vavcore_create_player(); - if (player) - { - LOGF_INFO("[App] VavCore player created successfully"); - vavcore_destroy_player(player); - } - - // C++ wrapper test disabled for now (only using C API) - // VavCore::VideoPlayer cppPlayer; - // LOGF_INFO("[App] VavCore C++ player created successfully"); - - vavcore_cleanup(); - LOGF_INFO("[App] VavCore cleanup completed"); - } - else - { - LOGF_ERROR("[App] Failed to initialize VavCore"); - } - } - App::App() { InitializeComponent(); - // Test VavCore integration on startup - // TestVavCoreIntegration(); // Disabled for logging system test + // Initialize VavCore on startup + VavCoreResult result = vavcore_initialize(); + if (result == VAVCORE_SUCCESS) + { + const char* version = vavcore_get_version_string(); + ::Vav2Player::SimpleLogger::GetInstance().LogInfoF("[App] VavCore initialized successfully, version: %s", version); + } + else + { + ::Vav2Player::SimpleLogger::GetInstance().LogErrorF("[App] Failed to initialize VavCore: error code %d", result); + } #if defined _DEBUG && !defined DISABLE_XAML_GENERATED_BREAK_ON_UNHANDLED_EXCEPTION UnhandledException([](IInspectable const&, UnhandledExceptionEventArgs const& e) diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/LogManager.h b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/LogManager.h index 8ccff43..129a273 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/LogManager.h +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/LogManager.h @@ -123,15 +123,15 @@ namespace Vav2Player } // Convenience macros for easier logging -#define LOG_DEBUG(message) Vav2Player::LogManager::LogDebug(message, __FUNCTIONW__) -#define LOG_INFO(message) Vav2Player::LogManager::LogInfo(message, __FUNCTIONW__) -#define LOG_WARNING(message) Vav2Player::LogManager::LogWarning(message, __FUNCTIONW__) -#define LOG_ERROR(message) Vav2Player::LogManager::LogError(message, __FUNCTIONW__) +#define LOG_MAN_DEBUG(message) Vav2Player::LogManager::LogDebug(message, __FUNCTIONW__) +#define LOG_MAN_INFO(message) Vav2Player::LogManager::LogInfo(message, __FUNCTIONW__) +#define LOG_MAN_WARNING(message) Vav2Player::LogManager::LogWarning(message, __FUNCTIONW__) +#define LOG_MAN_ERROR(message) Vav2Player::LogManager::LogError(message, __FUNCTIONW__) -#define LOG_VIDEO_LOAD(filename, success) Vav2Player::LogManager::LogVideoLoad(filename, success) -#define LOG_VIDEO_PLAY(filename) Vav2Player::LogManager::LogVideoPlay(filename) -#define LOG_VIDEO_PAUSE(filename) Vav2Player::LogManager::LogVideoPause(filename) -#define LOG_VIDEO_STOP(filename) Vav2Player::LogManager::LogVideoStop(filename) -#define LOG_VIDEO_ERROR(error, filename) Vav2Player::LogManager::LogVideoError(error, filename) -#define LOG_DECODER_INFO(type, info) Vav2Player::LogManager::LogDecoderInfo(type, info) -#define LOG_FRAME_INFO(index, total, fps) Vav2Player::LogManager::LogFrameInfo(index, total, fps) \ No newline at end of file +#define LOG_MAN_VIDEO_LOAD(filename, success) Vav2Player::LogManager::LogVideoLoad(filename, success) +#define LOG_MAN_VIDEO_PLAY(filename) Vav2Player::LogManager::LogVideoPlay(filename) +#define LOG_MAN_VIDEO_PAUSE(filename) Vav2Player::LogManager::LogVideoPause(filename) +#define LOG_MAN_VIDEO_STOP(filename) Vav2Player::LogManager::LogVideoStop(filename) +#define LOG_MAN_VIDEO_ERROR(error, filename) Vav2Player::LogManager::LogVideoError(error, filename) +#define LOG_MAN_DECODER_INFO(type, info) Vav2Player::LogManager::LogDecoderInfo(type, info) +#define LOG_MAN_FRAME_INFO(index, total, fps) Vav2Player::LogManager::LogFrameInfo(index, total, fps) \ No newline at end of file diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/SimpleLogger.h b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/SimpleLogger.h index 9e91329..794d465 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/SimpleLogger.h +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Logger/SimpleLogger.h @@ -1,16 +1,10 @@ #pragma once #include #include +#include "LogManager.h" // Use LogLevel from LogManager.h namespace Vav2Player { -enum class LogLevel { - Debug = 0, - Info = 1, - Warning = 2, - Error = 3 -}; - /** * Simple logger with support for both wstring and variadic arguments * Thread-safe singleton logger for both console and WinUI3 environments @@ -73,13 +67,6 @@ private: // ===== Logging Macros ===== // Use these macros instead of creating new logging functions -// LOG_* : For std::wstring messages with optional source parameter -// Usage: LOG_INFO(L"Video loaded", L"VideoPlayer") -#define LOG_DEBUG(msg, source) Vav2Player::SimpleLogger::GetInstance().LogDebug(msg, source) -#define LOG_INFO(msg, source) Vav2Player::SimpleLogger::GetInstance().LogInfo(msg, source) -#define LOG_WARNING(msg, source) Vav2Player::SimpleLogger::GetInstance().LogWarning(msg, source) -#define LOG_ERROR(msg, source) Vav2Player::SimpleLogger::GetInstance().LogError(msg, source) - // LOGF_* : For printf-style formatted messages (const char* format, ...) // Usage: LOGF_INFO("[Component] Value: %d", value) #define LOGF_DEBUG(...) Vav2Player::SimpleLogger::GetInstance().LogDebugF(__VA_ARGS__) diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/D3D12VideoRenderer.cpp b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/D3D12VideoRenderer.cpp index ca445a5..4fd77ff 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/D3D12VideoRenderer.cpp +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/D3D12VideoRenderer.cpp @@ -206,8 +206,6 @@ HRESULT D3D12VideoRenderer::RenderFrame(const VavCoreVideoFrame& frame) return E_INVALIDARG; } - return S_OK; - // Execute command list ID3D12CommandList* ppCommandLists[] = { m_commandList.Get() }; m_commandQueue->ExecuteCommandLists(_countof(ppCommandLists), ppCommandLists); diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/GlobalD3D12SyncManager.cpp b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/GlobalD3D12SyncManager.cpp index d7267fb..927dd1e 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/GlobalD3D12SyncManager.cpp +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/GlobalD3D12SyncManager.cpp @@ -1,5 +1,6 @@ #include "pch.h" #include "GlobalD3D12SyncManager.h" +#include "../Logger/SimpleLogger.h" #include namespace Vav2Player { @@ -26,8 +27,7 @@ void GlobalD3D12SyncManager::Initialize(size_t numThreads) { m_workerThreads.emplace_back(&GlobalD3D12SyncManager::WorkerThreadFunc, this); } - OutputDebugStringA("[GlobalD3D12SyncManager] Initialized with "); - OutputDebugStringA((std::to_string(numThreads) + " worker threads\n").c_str()); + LOGF_INFO("[GlobalD3D12SyncManager] Initialized with %zu worker threads", numThreads); } void GlobalD3D12SyncManager::Shutdown() { @@ -54,7 +54,7 @@ void GlobalD3D12SyncManager::Shutdown() { m_taskQueue.pop(); } - OutputDebugStringA("[GlobalD3D12SyncManager] Shutdown completed\n"); + LOGF_INFO("[GlobalD3D12SyncManager] Shutdown completed"); } std::future GlobalD3D12SyncManager::SubmitTask(std::function task) { @@ -114,13 +114,11 @@ void GlobalD3D12SyncManager::WorkerThreadFunc() { } catch (const std::exception& e) { task.completion.set_exception(std::current_exception()); - OutputDebugStringA("[GlobalD3D12SyncManager] Task exception: "); - OutputDebugStringA(e.what()); - OutputDebugStringA("\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] Task exception: %s", e.what()); } catch (...) { task.completion.set_exception(std::current_exception()); - OutputDebugStringA("[GlobalD3D12SyncManager] Unknown task exception\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] Unknown task exception"); } --m_activeTasks; @@ -141,7 +139,7 @@ void GlobalD3D12SyncManager::WaitForFenceInternal(ComPtr fence, UIN // Set event for completion HRESULT hr = fence->SetEventOnCompletion(targetValue, fenceEvent); if (FAILED(hr)) { - OutputDebugStringA("[GlobalD3D12SyncManager] SetEventOnCompletion failed\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] SetEventOnCompletion failed"); return; } @@ -161,7 +159,7 @@ void GlobalD3D12SyncManager::WaitForFrameCompletionInternal(ComPtr while (fence->GetCompletedValue() < targetValue) { HRESULT hr = fence->SetEventOnCompletion(targetValue, fenceEvent); if (FAILED(hr)) { - OutputDebugStringA("[GlobalD3D12SyncManager] SetEventOnCompletion failed for frame\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] SetEventOnCompletion failed for frame"); break; } @@ -169,12 +167,12 @@ void GlobalD3D12SyncManager::WaitForFrameCompletionInternal(ComPtr if (result == WAIT_TIMEOUT) { auto elapsed = std::chrono::high_resolution_clock::now() - startTime; if (elapsed >= timeoutDuration) { - OutputDebugStringA("[GlobalD3D12SyncManager] Frame completion timeout exceeded\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] Frame completion timeout exceeded"); break; } } else if (result != WAIT_OBJECT_0) { - OutputDebugStringA("[GlobalD3D12SyncManager] WaitForSingleObject failed for frame\n"); + LOGF_ERROR("[GlobalD3D12SyncManager] WaitForSingleObject failed for frame"); break; } } diff --git a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/SimpleGPURenderer.cpp b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/SimpleGPURenderer.cpp index 4894418..a42524f 100644 --- a/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/SimpleGPURenderer.cpp +++ b/vav2/platforms/windows/applications/vav2player/Vav2Player/src/Rendering/SimpleGPURenderer.cpp @@ -680,14 +680,12 @@ HRESULT SimpleGPURenderer::CreateNV12TextureR8Layout(uint32_t videoWidth, uint32 UINT64 requiredBytes = 0; m_device->GetCopyableFootprints(&nv12TextureDesc, 0, 2, 0, layouts, numRows, rowSizes, &requiredBytes); - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] GetCopyableFootprints requires: "); - << requiredBytes << " bytes" << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] GetCopyableFootprints requires: %llu bytes", requiredBytes); // Query actual allocation size for this descriptor D3D12_RESOURCE_ALLOCATION_INFO allocInfo = m_device->GetResourceAllocationInfo(0, 1, &nv12TextureDesc); - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] GetResourceAllocationInfo returns: "); - << allocInfo.SizeInBytes << " bytes" << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] GetResourceAllocationInfo returns: %llu bytes", allocInfo.SizeInBytes); // If allocation is too small, increase texture height until we have enough space if (allocInfo.SizeInBytes < requiredBytes) @@ -699,20 +697,17 @@ HRESULT SimpleGPURenderer::CreateNV12TextureR8Layout(uint32_t videoWidth, uint32 nv12TextureDesc.Height = videoHeight + extraHeight; allocInfo = m_device->GetResourceAllocationInfo(0, 1, &nv12TextureDesc); - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Testing height %d", nv12TextureDesc.Height); - << ": " << allocInfo.SizeInBytes << " bytes" << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Testing height %d: %llu bytes", nv12TextureDesc.Height, allocInfo.SizeInBytes); if (allocInfo.SizeInBytes >= requiredBytes) { - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Found sufficient height: "); - << nv12TextureDesc.Height << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Found sufficient height: %d", nv12TextureDesc.Height); break; } } } - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Final NV12 texture: %dx", videoWidth); - << nv12TextureDesc.Height << ", allocation: " << allocInfo.SizeInBytes << " bytes" << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Final NV12 texture: %dx%d, allocation: %llu bytes", videoWidth, nv12TextureDesc.Height, allocInfo.SizeInBytes); D3D12_HEAP_PROPERTIES sharedHeapProps = {}; sharedHeapProps.Type = D3D12_HEAP_TYPE_DEFAULT; @@ -728,13 +723,11 @@ HRESULT SimpleGPURenderer::CreateNV12TextureR8Layout(uint32_t videoWidth, uint32 if (FAILED(hr)) { - LOGF_ERROR("[SimpleGPURenderer::CreateNV12Texture] Failed to create NV12 shared texture: 0x"); - << std::hex << hr << std::endl; + LOGF_ERROR("[SimpleGPURenderer::CreateNV12Texture] Failed to create NV12 shared texture: 0x%08X", hr); return hr; } - LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Created NV12 shared texture ("); - << videoWidth << "x" << videoHeight << ") for VavCore zero-copy decode" << std::endl; + LOGF_INFO("[SimpleGPURenderer::CreateNV12Texture] Created NV12 shared texture (%dx%d) for VavCore zero-copy decode", videoWidth, videoHeight); return S_OK; } @@ -824,8 +817,7 @@ float4 PSMain(PSInput input) : SV_TARGET "VSMain", "vs_5_0", compileFlags, 0, &m_nv12VertexShaderBlob, &errorBlob); if (FAILED(hr)) { if (errorBlob) { - LOGF_INFO("[SimpleGPURenderer] NV12 Vertex shader compilation error: "); - << (char*)errorBlob->GetBufferPointer() << std::endl; + LOGF_ERROR("[SimpleGPURenderer] NV12 Vertex shader compilation error: %s", (char*)errorBlob->GetBufferPointer()); } return hr; } @@ -835,8 +827,7 @@ float4 PSMain(PSInput input) : SV_TARGET "PSMain", "ps_5_0", compileFlags, 0, &m_nv12PixelShaderBlob, &errorBlob); if (FAILED(hr)) { if (errorBlob) { - LOGF_INFO("[SimpleGPURenderer] NV12 Pixel shader compilation error: "); - << (char*)errorBlob->GetBufferPointer() << std::endl; + LOGF_ERROR("[SimpleGPURenderer] NV12 Pixel shader compilation error: %s", (char*)errorBlob->GetBufferPointer()); } return hr; } @@ -900,8 +891,7 @@ HRESULT SimpleGPURenderer::CreateNV12RootSignature() HRESULT hr = D3D12SerializeVersionedRootSignature(&rootSigDesc, &signature, &error); if (FAILED(hr)) { if (error) { - LOGF_INFO("[SimpleGPURenderer] NV12 Root signature serialization error: "); - << (char*)error->GetBufferPointer() << std::endl; + LOGF_ERROR("[SimpleGPURenderer] NV12 Root signature serialization error: %s", (char*)error->GetBufferPointer()); } return hr; } @@ -1005,8 +995,7 @@ HRESULT SimpleGPURenderer::CreateNV12GraphicsPipeline() if (FAILED(hr)) { - LOGF_ERROR("[SimpleGPURenderer] Failed to create NV12 constant buffer: 0x"); - << std::hex << hr << std::endl; + LOGF_ERROR("[SimpleGPURenderer] Failed to create NV12 constant buffer: 0x%08X", hr); return hr; } @@ -1618,8 +1607,7 @@ HRESULT SimpleGPURenderer::CreateComputeRootSignature() { if (error) { - LOGF_INFO("[SimpleGPURenderer] Root signature serialization error: "); - << (char*)error->GetBufferPointer() << std::endl; + LOGF_ERROR("[SimpleGPURenderer] Root signature serialization error: %s", (char*)error->GetBufferPointer()); } return hr; } @@ -1716,8 +1704,7 @@ void main(uint3 id : SV_DispatchThreadID) { if (errorBlob) { - LOGF_ERROR("[SimpleGPURenderer] Shader compilation failed: "); - << (char*)errorBlob->GetBufferPointer() << std::endl; + LOGF_ERROR("[SimpleGPURenderer] Shader compilation failed: %s", (char*)errorBlob->GetBufferPointer()); } return hr; } @@ -1745,8 +1732,7 @@ HRESULT SimpleGPURenderer::CreateComputePipelineState() HRESULT hr = m_device->CreateComputePipelineState(&psoDesc, IID_PPV_ARGS(&m_computePipelineState)); if (FAILED(hr)) { - LOGF_ERROR("[SimpleGPURenderer] Failed to create compute pipeline state: 0x"); - << std::hex << hr << std::endl; + LOGF_ERROR("[SimpleGPURenderer] Failed to create compute pipeline state: 0x%08X", hr); return hr; } diff --git a/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp b/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp index 02f05bb..a31c9c7 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp +++ b/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp @@ -32,39 +32,42 @@ bool D3D12SurfaceHandler::CopyNV12Frame(CUdeviceptr src_frame, } // Get D3D12 texture layout for both Y and UV planes - // CRITICAL: Must use the ACTUAL texture descriptor as-is (including any padding) - // DO NOT override height - GetCopyableFootprints needs the real allocation size D3D12_RESOURCE_DESC desc = dst_texture->GetDesc(); D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[2]; UINT num_rows[2] = {0}; UINT64 row_sizes[2] = {0}; UINT64 total_bytes = 0; - // Use descriptor directly without modification (preserves allocated height/pitch) + // CRITICAL: Use the ACTUAL allocated texture descriptor (including padding) + // SimpleGPURenderer may have allocated extra height to satisfy GetCopyableFootprints requirements + // We MUST use the real descriptor to get correct Y/UV plane offsets + // Query BOTH subresources (plane 0: Y, plane 1: UV) in a SINGLE call m_device->GetCopyableFootprints(&desc, 0, 2, 0, layouts, num_rows, row_sizes, &total_bytes); uint32_t y_dst_pitch = layouts[0].Footprint.RowPitch; uint32_t uv_dst_pitch = layouts[1].Footprint.RowPitch; UINT64 uv_offset = layouts[1].Offset; - - // Get actual row counts from GetCopyableFootprints uint32_t y_rows = num_rows[0]; uint32_t uv_rows = num_rows[1]; - // Debug logging char buf[512]; - sprintf_s(buf, "[D3D12SurfaceHandler] Video: %ux%u, Y: pitch=%u rows=%u, UV: pitch=%u rows=%u offset=%llu\n", - width, height, y_dst_pitch, y_rows, uv_dst_pitch, uv_rows, uv_offset); + sprintf_s(buf, "[D3D12SurfaceHandler] Texture descriptor: allocated height=%u (logical video height=%u)\n", + (uint32_t)desc.Height, height); OutputDebugStringA(buf); - sprintf_s(buf, "[D3D12SurfaceHandler] Source: pitch=%u, Y ptr=0x%llX, UV ptr=0x%llX\n", - src_pitch, src_frame, src_frame + (static_cast(src_pitch) * height)); + + sprintf_s(buf, "[D3D12SurfaceHandler] Y plane: width=%u, height=%u, srcPitch=%u, dstPitch=%u, rows=%u\n", + width, height, src_pitch, y_dst_pitch, y_rows); + OutputDebugStringA(buf); + + sprintf_s(buf, "[D3D12SurfaceHandler] UV plane: width=%u, height=%u, srcPitch=%u, dstPitch=%u, rows=%u, offset=%llu\n", + width, height / 2, src_pitch, uv_dst_pitch, uv_rows, uv_offset); OutputDebugStringA(buf); // Copy Y plane if (!CopyYPlane(src_frame, src_pitch, dst_ptr, y_dst_pitch, - width, y_rows)) { + width, height)) { return false; } @@ -74,10 +77,11 @@ bool D3D12SurfaceHandler::CopyNV12Frame(CUdeviceptr src_frame, if (!CopyUVPlane(src_uv, src_pitch, dst_uv, uv_dst_pitch, - width, uv_rows)) { + width, height / 2)) { return false; } + OutputDebugStringA("[D3D12SurfaceHandler] NV12 frame copied successfully\n"); return true; } @@ -97,10 +101,12 @@ bool D3D12SurfaceHandler::CopyYPlane(CUdeviceptr src, uint32_t src_pitch, CUdeviceptr dst, uint32_t dst_pitch, uint32_t width, uint32_t height) { + // Copy Y plane: single 8-bit channel + // Width parameter is in bytes (same as pixel width for 8-bit format) cudaError_t err = cudaMemcpy2D( (void*)dst, dst_pitch, (void*)src, src_pitch, - width, height, // Use the logical width, not the pitch, for the copy width. + width, height, cudaMemcpyDeviceToDevice ); @@ -111,6 +117,8 @@ bool D3D12SurfaceHandler::CopyYPlane(CUdeviceptr src, uint32_t src_pitch, OutputDebugStringA(buf); return false; } + + OutputDebugStringA("[D3D12SurfaceHandler] Y plane copied\n"); return true; } @@ -118,11 +126,13 @@ bool D3D12SurfaceHandler::CopyUVPlane(CUdeviceptr src, uint32_t src_pitch, CUdeviceptr dst, uint32_t dst_pitch, uint32_t width, uint32_t height) { - // For interleaved NV12, the byte width of the UV plane is the same as the Y plane. + // Copy UV plane: interleaved U and V (NV12 format) + // Width in bytes = width of Y plane (because U and V are interleaved) + // Height = half of Y plane height cudaError_t err = cudaMemcpy2D( (void*)dst, dst_pitch, (void*)src, src_pitch, - width, height, // Use the logical width, not the pitch, for the copy width. + width, height, cudaMemcpyDeviceToDevice ); @@ -133,6 +143,8 @@ bool D3D12SurfaceHandler::CopyUVPlane(CUdeviceptr src, uint32_t src_pitch, OutputDebugStringA(buf); return false; } + + OutputDebugStringA("[D3D12SurfaceHandler] UV plane copied\n"); return true; }