From 517feee3f10b939e4d13ea90ef6230871e310e43 Mon Sep 17 00:00:00 2001 From: ened Date: Sun, 5 Oct 2025 22:51:27 +0900 Subject: [PATCH] WIP --- .claude/settings.local.json | 5 +- .../LargeResolutionTest.vcxproj | 61 ++++ .../large-resolution/src/D3D12Manager.cpp | 341 ++++++++++++++++++ .../tests/large-resolution/src/D3D12Manager.h | 38 ++ .../tests/large-resolution/src/main.cpp | 222 ++++++++++++ .../src/Decoder/D3D12SurfaceHandler.cpp | 6 + .../src/Decoder/ExternalMemoryCache.cpp | 6 + 7 files changed, 677 insertions(+), 2 deletions(-) create mode 100644 vav2/platforms/windows/tests/large-resolution/LargeResolutionTest.vcxproj create mode 100644 vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.cpp create mode 100644 vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.h create mode 100644 vav2/platforms/windows/tests/large-resolution/src/main.cpp diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 445fd77..a8b433f 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -99,9 +99,10 @@ "Bash(py:*)", "Bash(\"D:/Project/video-av1/vav2/platforms/windows/tests/red-surface-nvdec/bin/Debug/RedSurfaceNVDECTest.exe\" \"D:/Project/video-av1/sample/simple_test.webm\")", "Bash(\"D:/Project/video-av1/vav2/platforms/windows/tests/red-surface-nvdec/bin/Debug/RedSurfaceNVDECTest.exe\" \"D:/Project/video-av1/sample/test_720p_stripe.webm\")", - "Bash(\"/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/MSBuild.exe\" \"D:/Project/video-av1/vav2/platforms/windows/tests/red-surface-nvdec/RedSurfaceNVDECTest.vcxproj\" //p:Configuration=Debug //p:Platform=x64 //p:RebuildV avCore=true //v:minimal)" + "Bash(\"/c/Program Files/Microsoft Visual Studio/2022/Community/MSBuild/Current/Bin/MSBuild.exe\" \"D:/Project/video-av1/vav2/platforms/windows/tests/red-surface-nvdec/RedSurfaceNVDECTest.vcxproj\" //p:Configuration=Debug //p:Platform=x64 //p:RebuildV avCore=true //v:minimal)", + "Bash(\"D:/Project/video-av1/vav2/platforms/windows/tests/large-resolution/bin/Debug/LargeResolutionTest.exe\" \"D:/Project/video-av1/sample/test_2160p_av1.webm\")" ], "deny": [], "ask": [] } -} \ No newline at end of file +} diff --git a/vav2/platforms/windows/tests/large-resolution/LargeResolutionTest.vcxproj b/vav2/platforms/windows/tests/large-resolution/LargeResolutionTest.vcxproj new file mode 100644 index 0000000..a92046c --- /dev/null +++ b/vav2/platforms/windows/tests/large-resolution/LargeResolutionTest.vcxproj @@ -0,0 +1,61 @@ + + + + + Debug + x64 + + + + 17.0 + Win32Proj + {B2C3D4E5-6789-ABCD-EF01-23456789ABCD} + LargeResolutionTest + 10.0 + + + + Application + true + v143 + Unicode + + + + + true + $(ProjectDir)bin\$(Configuration)\ + $(ProjectDir)obj\$(Configuration)\ + LargeResolutionTest + + + + Level3 + true + _DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + stdcpp17 + $(ProjectDir)..\..\vavcore\include + NotUsing + + + Console + true + $(ProjectDir)..\..\vavcore\lib + VavCore-debug.lib;d3d12.lib;dxgi.lib;kernel32.lib;user32.lib;%(AdditionalDependencies) + + + echo Copying VavCore DLL... +copy "$(ProjectDir)..\..\vavcore\lib\VavCore-debug.dll" "$(TargetDir)VavCore-debug.dll" +echo Done. + + + + + + + + + + + diff --git a/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.cpp b/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.cpp new file mode 100644 index 0000000..45e9fe1 --- /dev/null +++ b/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.cpp @@ -0,0 +1,341 @@ +#include "D3D12Manager.h" +#include + +D3D12Manager::D3D12Manager() + : m_device(nullptr) + , m_command_queue(nullptr) + , m_command_allocator(nullptr) + , m_command_list(nullptr) + , m_fence(nullptr) + , m_fence_value(0) + , m_fence_event(nullptr) +{ +} + +D3D12Manager::~D3D12Manager() +{ + Cleanup(); +} + +bool D3D12Manager::Initialize() +{ + if (!CreateDevice()) { + printf("[D3D12Manager] Failed to create D3D12 device\n"); + return false; + } + + if (!CreateCommandObjects()) { + printf("[D3D12Manager] Failed to create command objects\n"); + Cleanup(); + return false; + } + + printf("[D3D12Manager] Initialized successfully\n"); + return true; +} + +void D3D12Manager::Cleanup() +{ + WaitForGPU(); + + if (m_fence_event) { + CloseHandle(m_fence_event); + m_fence_event = nullptr; + } + + if (m_fence) { + m_fence->Release(); + m_fence = nullptr; + } + + if (m_command_list) { + m_command_list->Release(); + m_command_list = nullptr; + } + + if (m_command_allocator) { + m_command_allocator->Release(); + m_command_allocator = nullptr; + } + + if (m_command_queue) { + m_command_queue->Release(); + m_command_queue = nullptr; + } + + if (m_device) { + m_device->Release(); + m_device = nullptr; + } +} + +bool D3D12Manager::CreateDevice() +{ + // Create DXGI factory + IDXGIFactory4* factory = nullptr; + HRESULT hr = CreateDXGIFactory2(0, IID_PPV_ARGS(&factory)); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create DXGI factory: 0x%08X\n", hr); + return false; + } + + // Enumerate adapters and find the first hardware adapter + IDXGIAdapter1* adapter = nullptr; + for (UINT i = 0; factory->EnumAdapters1(i, &adapter) != DXGI_ERROR_NOT_FOUND; ++i) { + DXGI_ADAPTER_DESC1 desc; + adapter->GetDesc1(&desc); + + // Skip software adapter + if (desc.Flags & DXGI_ADAPTER_FLAG_SOFTWARE) { + adapter->Release(); + continue; + } + + // Try to create D3D12 device + hr = D3D12CreateDevice(adapter, D3D_FEATURE_LEVEL_11_0, IID_PPV_ARGS(&m_device)); + if (SUCCEEDED(hr)) { + printf("[D3D12Manager] Created D3D12 device on adapter: %ls\n", desc.Description); + adapter->Release(); + factory->Release(); + return true; + } + + adapter->Release(); + } + + factory->Release(); + printf("[D3D12Manager] No suitable D3D12 adapter found\n"); + return false; +} + +bool D3D12Manager::CreateCommandObjects() +{ + // Create command queue + D3D12_COMMAND_QUEUE_DESC queue_desc = {}; + queue_desc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT; + queue_desc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE; + + HRESULT hr = m_device->CreateCommandQueue(&queue_desc, IID_PPV_ARGS(&m_command_queue)); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create command queue: 0x%08X\n", hr); + return false; + } + + // Create command allocator + hr = m_device->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, + IID_PPV_ARGS(&m_command_allocator)); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create command allocator: 0x%08X\n", hr); + return false; + } + + // Create command list + hr = m_device->CreateCommandList(0, D3D12_COMMAND_LIST_TYPE_DIRECT, + m_command_allocator, nullptr, IID_PPV_ARGS(&m_command_list)); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create command list: 0x%08X\n", hr); + return false; + } + + // Close command list (we'll reset it when needed) + m_command_list->Close(); + + // Create fence + hr = m_device->CreateFence(0, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&m_fence)); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create fence: 0x%08X\n", hr); + return false; + } + + m_fence_value = 1; + + // Create fence event + m_fence_event = CreateEvent(nullptr, FALSE, FALSE, nullptr); + if (m_fence_event == nullptr) { + printf("[D3D12Manager] Failed to create fence event\n"); + return false; + } + + return true; +} + +void D3D12Manager::WaitForGPU() +{ + if (!m_command_queue || !m_fence || !m_fence_event) { + return; + } + + // Signal the fence + const UINT64 fence = m_fence_value; + m_command_queue->Signal(m_fence, fence); + m_fence_value++; + + // Wait for fence + if (m_fence->GetCompletedValue() < fence) { + m_fence->SetEventOnCompletion(fence, m_fence_event); + WaitForSingleObject(m_fence_event, INFINITE); + } +} + +ID3D12Resource* D3D12Manager::CreateNV12Texture(uint32_t width, uint32_t height) +{ + D3D12_RESOURCE_DESC desc = {}; + desc.Dimension = D3D12_RESOURCE_DIMENSION_TEXTURE2D; + desc.Width = width; + desc.Height = height; + desc.DepthOrArraySize = 1; + desc.MipLevels = 1; + desc.Format = DXGI_FORMAT_NV12; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Layout = D3D12_TEXTURE_LAYOUT_UNKNOWN; + desc.Flags = D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS; + + D3D12_HEAP_PROPERTIES heap_props = {}; + heap_props.Type = D3D12_HEAP_TYPE_DEFAULT; + + ID3D12Resource* texture = nullptr; + HRESULT hr = m_device->CreateCommittedResource( + &heap_props, + D3D12_HEAP_FLAG_SHARED, + &desc, + D3D12_RESOURCE_STATE_COMMON, + nullptr, + IID_PPV_ARGS(&texture)); + + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create NV12 texture: 0x%08X\n", hr); + return nullptr; + } + + return texture; +} + +uint8_t* D3D12Manager::ReadbackTexture(ID3D12Resource* texture, uint32_t width, uint32_t height) +{ + // Get texture description + D3D12_RESOURCE_DESC desc = texture->GetDesc(); + + // Calculate layout for both Y and UV planes + D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[2]; + UINT num_rows[2] = { 0 }; + UINT64 row_sizes[2] = { 0 }; + UINT64 total_bytes = 0; + + m_device->GetCopyableFootprints(&desc, 0, 2, 0, layouts, num_rows, row_sizes, &total_bytes); + + // Create readback buffer + D3D12_HEAP_PROPERTIES readback_heap_props = {}; + readback_heap_props.Type = D3D12_HEAP_TYPE_READBACK; + + D3D12_RESOURCE_DESC readback_desc = {}; + readback_desc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + readback_desc.Width = total_bytes; + readback_desc.Height = 1; + readback_desc.DepthOrArraySize = 1; + readback_desc.MipLevels = 1; + readback_desc.Format = DXGI_FORMAT_UNKNOWN; + readback_desc.SampleDesc.Count = 1; + readback_desc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + + ID3D12Resource* readback_buffer = nullptr; + HRESULT hr = m_device->CreateCommittedResource( + &readback_heap_props, + D3D12_HEAP_FLAG_NONE, + &readback_desc, + D3D12_RESOURCE_STATE_COPY_DEST, + nullptr, + IID_PPV_ARGS(&readback_buffer)); + + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to create readback buffer: 0x%08X\n", hr); + return nullptr; + } + + // Reset command list + m_command_allocator->Reset(); + m_command_list->Reset(m_command_allocator, nullptr); + + // Transition texture to COPY_SOURCE + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = texture; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COMMON; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.Subresource = D3D12_RESOURCE_BARRIER_ALL_SUBRESOURCES; + m_command_list->ResourceBarrier(1, &barrier); + + // Copy Y plane (subresource 0) + D3D12_TEXTURE_COPY_LOCATION src_y = {}; + src_y.pResource = texture; + src_y.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_y.SubresourceIndex = 0; + + D3D12_TEXTURE_COPY_LOCATION dst_y = {}; + dst_y.pResource = readback_buffer; + dst_y.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_y.PlacedFootprint = layouts[0]; + + m_command_list->CopyTextureRegion(&dst_y, 0, 0, 0, &src_y, nullptr); + + // Copy UV plane (subresource 1) + D3D12_TEXTURE_COPY_LOCATION src_uv = {}; + src_uv.pResource = texture; + src_uv.Type = D3D12_TEXTURE_COPY_TYPE_SUBRESOURCE_INDEX; + src_uv.SubresourceIndex = 1; + + D3D12_TEXTURE_COPY_LOCATION dst_uv = {}; + dst_uv.pResource = readback_buffer; + dst_uv.Type = D3D12_TEXTURE_COPY_TYPE_PLACED_FOOTPRINT; + dst_uv.PlacedFootprint = layouts[1]; + + m_command_list->CopyTextureRegion(&dst_uv, 0, 0, 0, &src_uv, nullptr); + + // Transition texture back to COMMON + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_COPY_SOURCE; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_COMMON; + m_command_list->ResourceBarrier(1, &barrier); + + // Execute command list + m_command_list->Close(); + ID3D12CommandList* cmd_lists[] = { m_command_list }; + m_command_queue->ExecuteCommandLists(1, cmd_lists); + + // Wait for GPU + WaitForGPU(); + + // Map readback buffer + void* mapped_data = nullptr; + D3D12_RANGE read_range = { 0, static_cast(total_bytes) }; + hr = readback_buffer->Map(0, &read_range, &mapped_data); + if (FAILED(hr)) { + printf("[D3D12Manager] Failed to map readback buffer: 0x%08X\n", hr); + readback_buffer->Release(); + return nullptr; + } + + // Allocate CPU buffer (NV12 format: Y plane + UV plane) + uint32_t y_size = width * height; + uint32_t uv_size = width * (height / 2); + uint8_t* cpu_buffer = new uint8_t[y_size + uv_size]; + + // Copy Y plane + uint8_t* src_y_data = static_cast(mapped_data) + layouts[0].Offset; + uint8_t* dst_y_data = cpu_buffer; + for (UINT row = 0; row < height; ++row) { + memcpy(dst_y_data + row * width, src_y_data + row * layouts[0].Footprint.RowPitch, width); + } + + // Copy UV plane + uint8_t* src_uv_data = static_cast(mapped_data) + layouts[1].Offset; + uint8_t* dst_uv_data = cpu_buffer + y_size; + for (UINT row = 0; row < height / 2; ++row) { + memcpy(dst_uv_data + row * width, src_uv_data + row * layouts[1].Footprint.RowPitch, width); + } + + // Unmap and release readback buffer + readback_buffer->Unmap(0, nullptr); + readback_buffer->Release(); + + return cpu_buffer; +} diff --git a/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.h b/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.h new file mode 100644 index 0000000..6aed114 --- /dev/null +++ b/vav2/platforms/windows/tests/large-resolution/src/D3D12Manager.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include + +class D3D12Manager +{ +public: + D3D12Manager(); + ~D3D12Manager(); + + bool Initialize(); + void Cleanup(); + + // Create NV12 texture for CUDA interop + ID3D12Resource* CreateNV12Texture(uint32_t width, uint32_t height); + + // Readback D3D12 texture to CPU memory + uint8_t* ReadbackTexture(ID3D12Resource* texture, uint32_t width, uint32_t height); + + // Get D3D12 device + ID3D12Device* GetDevice() const { return m_device; } + +private: + ID3D12Device* m_device; + ID3D12CommandQueue* m_command_queue; + ID3D12CommandAllocator* m_command_allocator; + ID3D12GraphicsCommandList* m_command_list; + ID3D12Fence* m_fence; + UINT64 m_fence_value; + HANDLE m_fence_event; + + bool CreateDevice(); + bool CreateCommandObjects(); + void WaitForGPU(); +}; diff --git a/vav2/platforms/windows/tests/large-resolution/src/main.cpp b/vav2/platforms/windows/tests/large-resolution/src/main.cpp new file mode 100644 index 0000000..3b18378 --- /dev/null +++ b/vav2/platforms/windows/tests/large-resolution/src/main.cpp @@ -0,0 +1,222 @@ +#include +#include +#include +#include +#include +#include +#include "D3D12Manager.h" + +using namespace std::chrono; + +struct FrameTask { + int frame_index; + ID3D12Resource* texture; + VavCoreVideoFrame frame; + VavCoreResult result; + uint8_t* cpu_buffer; +}; + +int main(int argc, char* argv[]) +{ + printf("[LargeResolutionTest] Starting test...\n"); + + // Parse command line arguments + if (argc < 2) { + printf("[ERROR] Usage: LargeResolutionTest.exe \n"); + printf("[INFO] Test videos:\n"); + printf(" - D:/Project/video-av1/sample/test_2160p_av1.webm\n"); + printf(" - D:/Project/video-av1/sample/test_1080p_stripe.webm\n"); + return 1; + } + + const char* video_path = argv[1]; + printf("[LargeResolutionTest] Video: %s\n", video_path); + + // Step 1: Initialize VavCore + printf("\n[Step 1] Initializing VavCore...\n"); + VavCoreResult result = vavcore_initialize(); + if (result != VAVCORE_SUCCESS) { + printf("[ERROR] Failed to initialize VavCore: error code %d\n", result); + return 1; + } + printf("[OK] VavCore initialized successfully\n"); + + // Step 2: Create D3D12 device (headless) + printf("\n[Step 2] Creating D3D12 device...\n"); + D3D12Manager d3d12; + if (!d3d12.Initialize()) { + printf("[ERROR] Failed to create D3D12 device\n"); + vavcore_cleanup(); + return 1; + } + printf("[OK] D3D12 device created\n"); + + // Step 3: Create VavCore player + printf("\n[Step 3] Creating VavCore player...\n"); + VavCorePlayer* player = vavcore_create_player(); + if (!player) { + printf("[ERROR] Failed to create VavCore player\n"); + d3d12.Cleanup(); + vavcore_cleanup(); + return 1; + } + printf("[OK] VavCore player created\n"); + + // Step 4: Set decoder type to NVDEC explicitly + printf("\n[Step 4] Setting decoder type to NVDEC...\n"); + result = vavcore_set_decoder_type(player, VAVCORE_DECODER_NVDEC); + if (result != VAVCORE_SUCCESS) { + printf("[ERROR] Failed to set decoder type: error code %d\n", result); + vavcore_destroy_player(player); + d3d12.Cleanup(); + vavcore_cleanup(); + return 1; + } + printf("[OK] Decoder type set to NVDEC\n"); + + // Step 5: Set D3D12 device for zero-copy + printf("\n[Step 5] Setting D3D12 device for VavCore...\n"); + result = vavcore_set_d3d_device(player, d3d12.GetDevice(), VAVCORE_SURFACE_D3D12_RESOURCE); + if (result != VAVCORE_SUCCESS) { + printf("[ERROR] Failed to set D3D12 device: error code %d\n", result); + vavcore_destroy_player(player); + d3d12.Cleanup(); + vavcore_cleanup(); + return 1; + } + printf("[OK] D3D12 device set for VavCore\n"); + + // Step 6: Open video file + printf("\n[Step 6] Opening video file...\n"); + result = vavcore_open_file(player, video_path); + if (result != VAVCORE_SUCCESS) { + printf("[ERROR] Failed to open video file: error code %d\n", result); + vavcore_destroy_player(player); + d3d12.Cleanup(); + vavcore_cleanup(); + return 1; + } + + // Get video metadata + VavCoreVideoMetadata metadata = {}; + result = vavcore_get_metadata(player, &metadata); + if (result != VAVCORE_SUCCESS) { + printf("[ERROR] Failed to get video metadata: error code %d\n", result); + vavcore_close_file(player); + vavcore_destroy_player(player); + d3d12.Cleanup(); + vavcore_cleanup(); + return 1; + } + + printf("[OK] Video opened: %dx%d, %.2f fps, %llu frames\n", + metadata.width, metadata.height, metadata.frame_rate, (unsigned long long)metadata.total_frames); + printf("[LargeResolutionTest] Decoder: NVDEC (explicit)\n"); + printf("[LargeResolutionTest] Surface: D3D12\n"); + + // Step 7: Continuous frame decoding (limited to ~10 seconds) + const int MAX_FRAMES = 300; // ~10 seconds at 30fps + printf("\n[Step 7] Decoding video (limited to %d frames for testing)...\n\n", MAX_FRAMES); + printf("[INFO] NVDEC pipeline priming: Calling decode continuously\n"); + printf("[INFO] First 2 frames will be skipped for priming\n"); + printf("[INFO] Total frames in video: %llu\n\n", (unsigned long long)metadata.total_frames); + + int decode_errors = 0; + int successful_decodes = 0; + int frame_index = 0; + + // Performance measurement + auto start_time = high_resolution_clock::now(); + auto last_report_time = start_time; + int frames_since_last_report = 0; + + // Continuous decode loop - decode limited frames + while (!vavcore_is_end_of_file(player) && frame_index < MAX_FRAMES) { + // Create NV12 texture + ID3D12Resource* texture = d3d12.CreateNV12Texture(metadata.width, metadata.height); + if (!texture) { + printf("[ERROR] Failed to create texture for frame %d\n", frame_index); + decode_errors++; + frame_index++; + continue; + } + + // Decode frame to D3D12 surface + VavCoreVideoFrame frame; + VavCoreResult result = vavcore_decode_to_surface( + player, + VAVCORE_SURFACE_D3D12_RESOURCE, + texture, + &frame + ); + + if (result != VAVCORE_SUCCESS) { + printf("Frame %3d: Decode failed (error code %d)\n", frame_index, result); + texture->Release(); + decode_errors++; + frame_index++; + continue; + } + + // Skip first 2 frames (priming) + if (frame_index < 2) { + printf("Frame %3d: PRIMING (decoded but skipped)\n", frame_index); + } else { + successful_decodes++; + frames_since_last_report++; + + // Print performance report every 30 frames + if (frame_index % 30 == 0) { + auto current_time = high_resolution_clock::now(); + auto elapsed_ms = duration_cast(current_time - last_report_time).count(); + double fps = (frames_since_last_report * 1000.0) / elapsed_ms; + + printf("Frame %3d: Decoded successfully (progress: %d/%llu, FPS: %.1f)\n", + frame_index, frame_index, (unsigned long long)metadata.total_frames, fps); + + last_report_time = current_time; + frames_since_last_report = 0; + } + } + + // Cleanup texture immediately to prevent memory buildup + texture->Release(); + frame_index++; + } + + // Calculate overall performance + auto end_time = high_resolution_clock::now(); + auto total_ms = duration_cast(end_time - start_time).count(); + double overall_fps = (successful_decodes * 1000.0) / total_ms; + double decode_time_per_frame = (double)total_ms / successful_decodes; + + // Step 8: Print results + printf("\n[LargeResolutionTest] Results:\n"); + printf(" Resolution: %dx%d\n", metadata.width, metadata.height); + printf(" Total frames in video: %llu\n", (unsigned long long)metadata.total_frames); + printf(" Total frames decoded: %d\n", frame_index); + printf(" Priming frames: 2\n"); + printf(" Successful decodes (after priming): %d\n", successful_decodes); + printf(" Decode errors: %d\n", decode_errors); + printf("\n[LargeResolutionTest] Performance:\n"); + printf(" Total time: %.2f seconds\n", total_ms / 1000.0); + printf(" Average FPS: %.1f fps\n", overall_fps); + printf(" Average decode time per frame: %.2f ms\n", decode_time_per_frame); + printf(" Target FPS (30fps): %s\n", overall_fps >= 30.0 ? "PASS" : "FAIL"); + + bool test_passed = (decode_errors == 0 && successful_decodes == (frame_index - 2) && overall_fps >= 30.0); + + if (test_passed) { + printf("\n[LargeResolutionTest] Test SUCCESS - All frames decoded successfully\n"); + } else { + printf("\n[LargeResolutionTest] Test FAILED - Some frames failed to decode\n"); + } + + // Cleanup + vavcore_close_file(player); + vavcore_destroy_player(player); + d3d12.Cleanup(); + vavcore_cleanup(); + + return test_passed ? 0 : 1; +} diff --git a/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp b/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp index 4450316..ab85972 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp +++ b/vav2/platforms/windows/vavcore/src/Decoder/D3D12SurfaceHandler.cpp @@ -32,6 +32,8 @@ bool D3D12SurfaceHandler::CopyNV12Frame(CUdeviceptr src_frame, return false; } + LOGF_DEBUG("[D3D12SurfaceHandler] dst_ptr (base from ExternalMemory)=0x%llX", dst_ptr); + // Get D3D12 texture layout for both Y and UV planes D3D12_RESOURCE_DESC desc = dst_texture->GetDesc(); D3D12_PLACED_SUBRESOURCE_FOOTPRINT layouts[2]; @@ -55,6 +57,10 @@ bool D3D12SurfaceHandler::CopyNV12Frame(CUdeviceptr src_frame, LOGF_DEBUG("[D3D12SurfaceHandler] Texture descriptor: allocated height=%u (logical video height=%u)", (uint32_t)desc.Height, height); + LOGF_DEBUG("[D3D12SurfaceHandler] Y plane offset: 0x%llX", layouts[0].Offset); + LOGF_DEBUG("[D3D12SurfaceHandler] UV plane offset: 0x%llX", layouts[1].Offset); + LOGF_DEBUG("[D3D12SurfaceHandler] Total texture size: %llu bytes", total_bytes); + LOGF_DEBUG("[D3D12SurfaceHandler] Y plane: width=%u, height=%u, srcPitch=%u, dstPitch=%u, rows=%u", width, height, src_pitch, y_dst_pitch, y_rows); diff --git a/vav2/platforms/windows/vavcore/src/Decoder/ExternalMemoryCache.cpp b/vav2/platforms/windows/vavcore/src/Decoder/ExternalMemoryCache.cpp index fb812a5..67f4c0f 100644 --- a/vav2/platforms/windows/vavcore/src/Decoder/ExternalMemoryCache.cpp +++ b/vav2/platforms/windows/vavcore/src/Decoder/ExternalMemoryCache.cpp @@ -92,6 +92,9 @@ bool ExternalMemoryCache::ImportD3D12Resource(ID3D12Resource* resource, D3D12_RESOURCE_DESC desc = resource->GetDesc(); D3D12_RESOURCE_ALLOCATION_INFO alloc_info = m_device->GetResourceAllocationInfo(0, 1, &desc); + LOGF_DEBUG("[ExternalMemoryCache] Resource allocation info: size=%llu, alignment=%llu", + alloc_info.SizeInBytes, alloc_info.Alignment); + // Import external memory cudaExternalMemoryHandleDesc mem_desc = {}; mem_desc.type = cudaExternalMemoryHandleTypeD3D12Resource; // Use resource type for individual textures @@ -126,6 +129,9 @@ bool ExternalMemoryCache::ImportD3D12Resource(ID3D12Resource* resource, return false; } + LOGF_DEBUG("[ExternalMemoryCache] Successfully mapped external memory: device_ptr=0x%llX, size=%llu", + device_ptr, buffer_desc.size); + *out_ext_mem = external_memory; *out_ptr = device_ptr;