Add Rendering - #16
Draft
itsafuu wants to merge 76 commits into
Draft
Conversation
- New include/processingbase/vulkan_init_guard.hpp with a process-wide, header-declared magic-static mutex accessor sgns::sgprocessing::VulkanInitMutex() - Serves as the single synchronization primitive for all Vulkan instance/device-creation call sites in this process (MNN's 3 existing sites plus RenderProcessor's future site)
- Remove the file-scoped, function-local static mnn_vulkan_mutex from MNN_Image::Process() - Acquire sgns::sgprocessing::VulkanInitMutex() at the same point in the function body (top of Process()), preserving the same lock span
- Both createSession(MNN_FORWARD_VULKAN) call sites previously had zero synchronization, unlike MNN_Image's now-shared guard - Wrap each createSession call in a scope guarded by sgns::sgprocessing::VulkanInitMutex(), hoisting the MNN::Session* declaration outside the lock scope so the existing !session failure check is unaffected
…ext, vk-bootstrap init, deterministic device selection
…h, require shader for RENDER passes
… backend - Flip config.type from MNN_FORWARD_CPU to MNN_FORWARD_VULKAN in 4 processor files - Wrap createSession() calls in shared VulkanInitMutex() lock-guard, matching the already-migrated string/image/volume pattern - Downstream tensor-copy logic, numThread, backendConfig left unchanged
… backend - Flip config.type from MNN_FORWARD_CPU to MNN_FORWARD_VULKAN in 4 processor files - Wrap createSession() calls in shared VulkanInitMutex() lock-guard - Each file's own nullptr failure-return convention preserved unchanged
…ssors to Vulkan backend
- Flip config.type from MNN_FORWARD_CPU to MNN_FORWARD_VULKAN across 5 files
- Wrap createSession() calls in shared VulkanInitMutex() lock-guard
- texturecube.cpp has two independent call sites; each gets its own
lock-guard scope, single shared include added once
- Each file's own failure-return convention (nullptr / ProcessingResult{})
preserved unchanged
…he guarded pattern, not a stale count
- Removes the stale, undercounting call-site count ("MNN's 3 existing... sites")
- Describes the guarded set as a pattern instead: every MNN Vulkan-backend
createSession() call site, plus RenderProcessor's lazy-init path
- Points readers at 'grep MNN_FORWARD_VULKAN src/processors/*.cpp' for the
current authoritative count rather than trusting a comment that can drift
- Mutex implementation (VulkanInitMutex()) is byte-identical, unchanged
- Fix pre-existing JSON syntax error in shader_config.type (missing comma, trailing comma) that made the schema file invalid JSON - Narrow shader-language enum to glsl/spirv only via new shared shader_source_type definition (drops hlsl/metal entirely, D-10) - Add render_shader_config + shader_stage (multi-stage vertex+fragment shader pipeline, D-11/D-12) - Add render_target (all-required framebuffer config, D-15) - Add vertex_layout_entry + vertex_buffer (D-16/D-16 Amendment) and index_buffer (D-17) - Add pipeline_state (curated topology/cull/winding/depth-test subset, D-13/D-14) - pass gains six new optional render-only properties; pass.allOf split into separate compute/render conditional branches (documentation only - quicktype does not enforce allOf/if/then required)
- Full quicktype regeneration (--source-style multi-source rewrites every currently-referenced type's header) from the fixed/extended gnus-processing-schema.json - New headers: RenderShaderConfig, ShaderStage, RenderTarget, VertexLayoutEntry, VertexBuffer, IndexBuffer, PipelineState, ShaderSourceType, RenderShaderUniform, ShaderUniform (renamed from Uniform), Stage, Topology, CullMode, FrontFace, DepthTest, ColorFormat, DepthFormat, VertexLayoutFormat, IndexType - Pass.hpp gains boost::optional accessors: get_/set_render_shader(), get_/set_render_target(), get_/set_vertex_layout(), get_/set_vertex_buffer(), get_/set_index_buffer(), get_/set_pipeline_state() - RenderTarget's six fields and VertexBuffer's source are plain (non-optional) required members, confirmed via generated output - Deleted orphaned generated/ShaderType.hpp and generated/Uniform.hpp (superseded, zero references outside generated/ confirmed before deletion)
- Adds sgns::sgprocessing::ShaderCompiler with CompileAndValidate(), a Vulkan-device-free component (zero VkInstance/VkDevice/VkPhysicalDevice) that compiles job-supplied GLSL to SPIR-V via shaderc and unconditionally validates all SPIR-V (compiled or directly-submitted) via SPIRV-Tools before it can ever reach vkCreateShaderModule. - Both the GLSL-compiled path and the direct-SPIR-V path call spvtools::SpirvTools::Validate() explicitly -- shaderc's CompileGlslToSpv() success does not imply SPIRV-Tools validation. - New standalone SGShaderCompiler CMake target linking shaderc::shaderc/SPIRV-Tools::SPIRV-Tools, wired into src/CMakeLists.txt.
…r validity checks - Add Error::SHADER_COMPILE_FAILED/SPIRV_VALIDATION_FAILED, wired into the OUTCOME_CPP_DEFINE_CATEGORY_3 switch - Init()'s JSON-parsing catch broadened to also catch std::exception, closing the newly-live crash vector from quicktype's narrowed ShaderSourceType enum's from_json (throws plain std::runtime_error, not nlohmann::json::exception) - CheckProcessValidity()'s PassType::RENDER branch now checks render_shader/ render_target/vertex_buffer/vertex_layout presence (replacing the obsolete get_shader() check, which is compute-only after plan 02-01) - GetCidForProc() extended: for render passes, fetches each render_shader stage's source (queued alongside the existing image fetch, single ioc->run() unchanged), then runs every stage through ShaderCompiler::CompileAndValidate() before mainbuffers->first is populated via a new SerializeCompiledStages() helper (provisional wire format, documented inline for Phase 3's RenderProcessor to consume/revise) - src/processingbase/CMakeLists.txt links SGShaderCompiler Verified via a real MSVC /Zs syntax+semantic check against the project's actual include paths (full link build blocked by pre-existing missing vendored shaderc/SPIRV-Tools/vk-bootstrap installs in this session, same constraint documented in 02-03-SUMMARY.md).
…ped shader compilation get_render_shader() returns boost::optional<RenderShaderConfig> by value (quicktype's standard convention). Binding `stages` as a reference through a chained .value().get_stages() call left it pointing at a temporary that was destroyed at the end of the statement, so the render-stage loop always iterated zero times. This meant shader compile/validate was never actually reached during dispatch, and the malformed-GLSL/invalid-SPIR-V rejection tests silently fell through to an unrelated missing-input error instead of exercising the SHADER_COMPILE_FAILED/SPIRV_VALIDATION_FAILED paths. Copy the optional into a named local first so its lifetime covers the loop. Found via real build+test verification (not caught by code review or the isolated MinGW spike used during planning, since neither actually ran the project's own MSVC toolchain against the real dispatch path).
- ProcessingResult gains a new optional error field (ProcessingErrorStage enum + ProcessingError struct, D-25/D-26) carrying per-stage VkResult/ context detail without changing StartProcessing()'s signature - ProcessingManager::Error gains PROCESSING_FAILED = 9 for the dispatch gate Task 2 will add
…oint - ProcessingManager::Process() now checks processResult.error / hash.empty() immediately after StartProcessing() returns and skips FileManager::SaveASync entirely on failure, returning Error::PROCESSING_FAILED (D-27/D-28). Covers both the render path (new error field) and the existing MNN path (pre-existing empty-hash-on-failure sentinel) with a single gate -- zero changes needed to any of the 15 MNN processor files. - SerializeCompiledStages()/its GetCidForProc() call site now carry each stage's real entry_point string (length-prefixed UTF-8) instead of dropping it, closing the SPIR-V wire-format gap RESEARCH.md's Pitfall 6 flagged for plan 03-03's RenderProcessor parser.
…nder-pass config Extends GetCidForProc()'s render branch to fetch vertex_buffer/index_buffer as independently-named "input:" references (not the coincidental single model-index input the current fixture happens to reuse), and packs render_target/pipeline_state/vertex_layout/uniforms/data_transform_count alongside the vertex/index bytes into a new SerializeRenderPassConfig() wire format -- the only channel this Pass-level data has to reach RenderProcessor under StartProcessing()'s fixed signature (D-25). - New anonymous-namespace SerializeRenderPassConfig() helper, wire format documented in the function's header comment - GetCidForProc()'s isRender branch now independently resolves vertex_buffer/ index_buffer sources via the existing GetInputIndex()/m_inputMap mechanism - The old unconditional GetSubCidForProc(ioc, imageUrl, mainbuffers->second) fetch is now guarded by if (!isRender), since mainbuffers->second is populated by SerializeRenderPassConfig() for render passes instead - Preserves the pre-existing INPUT_UNAVAIL failure semantics via an explicit vertexBuffer->empty() check, since mainbuffers->second is no longer ever empty for a render pass regardless of fetch success
…er passes Adds defensive Create()-time rejection of vertex_buffer/index_buffer/uniform source strings this phase has no real resolution path for, closing T-03-02-01/T-03-02-02 from the plan's threat register. - vertex_buffer.source / index_buffer.source (when index_buffer's source is present) must start with "input:" -- output:/internal:/parameter: sources fail with a clear, documented reason (no cross-pass dependency graph exists, no parameter:-sourced raw-buffer codec exists) - Each uniform declaring a source must use the "parameter:" prefix (Pitfall 8 -- the schema itself does not constrain this string); a uniform with neither a source nor a usable value also fails cleanly - Both checks share a single log-message lambda so the vertex_buffer/ index_buffer message text is not duplicated in source
…ssor - ParseCompiledStages()/ParseRenderPassConfig() invert plans 03-01/03-02's wire formats byte-for-byte, bounds-checking every read against buffer size so a malformed/truncated buffer returns a RESOURCE_RESOLUTION error instead of reading out-of-bounds. - ParseRenderPassConfig() is the only method that reconstructs real sgns::RenderTarget/PipelineState/VertexLayoutEntry/uniform-map instances inside RenderProcessor, and the only source of data_transform_count. - ResolveUniforms() resolves each uniform's literal value or parameter:-sourced value, packs bytes per declared DataType at a 16-byte-aligned offset per uniform (std430-avoidance per D-29/D-30), and applies the fixed 128-byte push-constant/descriptor-set threshold. - MakeError() constructs a structured ProcessingResult error (D-25/D-26).
… + ordered teardown - CreateBufferDedicated()/CreateImageDedicated() each perform exactly one vkAllocateMemory call, sized to the object's own memory requirements (D-18/D-19, no sub-allocation), and register their teardown via PushTeardown() on success. A failed vkAllocateMemory/vkBind*Memory destroys the just-created buffer/image before returning the error (D-24), since it isn't registered on m_teardown yet. - CheckFormatSupport() queries vkGetPhysicalDeviceFormatProperties and fails with a structured FORMAT_UNSUPPORTED error naming the specific format (RESEARCH.md Pitfall 7) rather than letting image/render-pass creation fail with an opaque VkResult. - PushTeardown()/RunTeardown() implement the single ordered-teardown stack (D-22/D-24) every later plan in this phase reuses -- unwinds in reverse order via rbegin()/rend(). - No new code in this task takes VulkanInitMutex() -- confirmed the lock remains scoped to InitializeContext()'s existing instance/device creation only, per RESEARCH.md's anti-pattern warning.
…it clears) - BuildRenderPass(): bounds-checks render_target width/height against a new kMaxRenderDimension (8192), format-support-checks color/depth via plan 03-03's CheckFormatSupport(), then creates a VkRenderPass with explicit VK_ATTACHMENT_LOAD_OP_CLEAR on both color/depth attachments (never DONT_CARE except the unused stencil aspect), VK_SAMPLE_COUNT_1_BIT unconditionally per DETV-02, and the color attachment's finalLayout set to VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL for plan 03-05's readback. - BuildFramebuffer(): allocates dedicated color+depth VkImage/VkImageView pairs via plan 03-03's CreateImageDedicated() (DEVICE_LOCAL) and builds the VkFramebuffer referencing the render pass. - New ToVkFormat(ColorFormat)/ToVkFormat(DepthFormat) schema-to-Vulkan mapping helpers. - Every created object registers teardown via PushTeardown() in creation order (D-22/D-24).
…ant/descriptor-set layout) - BuildPipeline(): one VkShaderModule + VkPipelineShaderStageCreateInfo per parsed shader stage, using each stage's real entry_point (plan 03-01), never a hard-coded "main"; per-stage module-creation failure is isolated via SHADER_MODULE_CREATION and cannot leak an earlier stage's module (D-24) since teardown is registered immediately after each successful vkCreateShaderModule call. - Vertex input binding/attributes auto-computed from vertex_layout's scalar-component reading (stride = sum of per-entry scalar byte sizes, location = array index) via new ToVkFormat(VertexLayoutFormat)/ VertexFormatByteSize() helpers. - Fixed (never VK_DYNAMIC_STATE_*) topology/cull-mode/front-face/depth-test baked from pipeline_state (or schema defaults) via new ToVkTopology()/ToVkCullMode()/ToVkFrontFace()/ToVkBool() helpers; depthCompareOp fixed at VK_COMPARE_OP_LESS (D-14); multisample rasterizationSamples fixed at VK_SAMPLE_COUNT_1_BIT (DETV-02); viewport/ scissor sized from plan 03-04 Task 1's validated render-target dimensions. - Pipeline layout branches on D-29/D-30's fixed 128-byte push-constant threshold: push-constant range when uniforms fit and are non-empty, a single descriptor-set-layout/pool/set (maxSets=1) UBO when they don't, zero of both when no uniforms are declared. - Every created object (shader modules, descriptor set layout/pool, pipeline layout, pipeline) registers teardown via PushTeardown() in creation order (D-22/D-24).
Adds RenderProcessor::UploadBuffers()/RecordAndSubmit()/Readback()/ ColorFormatByteSize() -- validates vertex/index buffer byte lengths against the pipeline's computed stride/index-type BEFORE any draw call is recorded (closes T-03-03-02), uploads vertex/index/uniform bytes into dedicated HOST_VISIBLE|HOST_COHERENT buffers with direct vkMapMemory/memcpy (D-20/D-21, no manual flush), and records+submits a single command buffer (bind pipeline/buffers, push-constants or descriptor-set bind, draw(Indexed), the vkCmdCopyImageToBuffer readback copy recorded inline before vkEndCommandBuffer per Pitfall 4 -- no extra layout-transition barrier needed since the color attachment's finalLayout is already VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL) plus a synchronous vkDeviceWaitIdle (D-23). StartProcessing() is intentionally still the pre-existing stub -- wiring these methods together is Task 2's job.
…orm stance Fully rewrites RenderProcessor::StartProcessing(), replacing the stub's hard-coded zero-hash return with the real call sequence: ParseCompiledStages() -> ParseRenderPassConfig() -> ResolveUniforms() -> BuildRenderPass() -> BuildFramebuffer() -> BuildPipeline() -> UploadBuffers() -> data_transform gate -> RecordAndSubmit() -> Readback() -> sha256(readback bytes) -> ProcessingResult. Every exit path (success and every intermediate failure) calls RunTeardown() before returning, so no per-job Vulkan object is ever leaked (D-22/D-24) -- including the RENDER-07 data_transform gate: absent/ empty data_transforms is a no-op passthrough, any non-empty data_transforms fails cleanly with a structured DATA_TRANSFORM_UNSUPPORTED error (no executor exists anywhere in this codebase, per RESEARCH.md Pitfall 9). Satisfies RENDER-01/03/06/07/08/09 and DETV-02's code-level guards -- the only remaining phase work is DETV-01's same-node repeat-run determinism proof (plan 03-06).
…rProcessor InitializeContext()'s PhysicalDeviceSelector left require_present at its default (true), which rejects every physical device with no_surface_provided since RenderProcessor never creates a VkSurfaceKHR (headless/offscreen, no swapchain -- CTX-01/D-23). This was never exercised until this plan's happy-path test became the first fixture to actually reach InitializeContext() with a real, fetchable render pass (all prior fixtures failed earlier, at the fetch stage, before dispatch ever reached StartProcessing()). Disabling require_present is the correct fix for a headless renderer with no presentation surface.
…visibility - Move RenderProcessor::IsAcceptable from private to public so vulkan_gpu_probe.cpp can call it directly instead of duplicating the DISCRETE_GPU/INTEGRATED_GPU filter - Add sgns::sgprocessing::HasUsableVulkanDevice(): builds a throwaway VkInstance under the shared VulkanInitMutex(), enumerates devices headlessly (require_present(false)), filters via RenderProcessor::IsAcceptable, tears down the instance on every path, never throws - Register vulkan_gpu_probe.cpp/.hpp in SGProcessors's CMake source list
- Add rawOutputCapture std::function field (quantized bytes, pre-quantize bytes), mirroring progressCallback's opt-in injection pattern via ExecutionContext - NoOp() deliberately leaves it unset, unlike progressCallback, so production/no-op callers pay zero capture-path cost; documented inline to prevent a future "fix" toward parity - Add missing <vector> include needed by the new field's signature
…ed-combined hash sites - Insert locally-owned copy + QuantizeFloatBuffer + rawOutputCapture guard at each file's per-chunk hash call site, without mutating MNN-owned data in place - Insert pre-quantize snapshot + in-place QuantizeFloatBuffer + rawOutputCapture guard at each file's stitched-combined hash call site (stitchedOutput is locally owned) - Add #include "util/quantization.hpp" to all 3 files
…ched-combined hash sites - Insert locally-owned copy + QuantizeFloatBuffer + rawOutputCapture guard at each file's per-chunk hash call site, without mutating MNN-owned data in place - Insert pre-quantize snapshot + in-place QuantizeFloatBuffer + rawOutputCapture guard at each file's stitched-combined hash call site (stitchedOutput is locally owned) - Add #include "util/quantization.hpp" to all 3 files - Verified SGProcessors target builds cleanly (build/Windows/Debug, MSBuild)
…h sites - Insert locally-owned std::vector<float> copy + QuantizeFloatBuffer + rawOutputCapture guard before each file's chunk-hash sha256 call - Redirect chunk-hash first argument from raw MNN data pointer to the quantized local copy - Leave rolling combined-hash call sites untouched (hash-of-hashes, not re-quantizable)
…nk-hash sites - Insert locally-owned std::vector<float> copy + QuantizeFloatBuffer + rawOutputCapture guard before each file's chunk-hash sha256 call - Redirect chunk-hash first argument from raw MNN data pointer to the quantized local copy - Leave rolling combined-hash call sites untouched (hash-of-hashes, not re-quantizable)
…sites - Insert per-branch locally-owned std::vector<float> copy + QuantizeFloatBuffer + rawOutputCapture guard before each of the two independent chunk-hash sha256 calls - Redirect each branch's chunk-hash first argument to its own quantized local copy - Leave both rolling combined-hash call sites untouched (hash-of-hashes, not re-quantizable)
- Insert QuantizeByteBuffer + rawOutputCapture before the single combined-hash call in RenderProcessor::StartProcessing - readbackBytes is locally-owned, so quantization mutates it in place (no copy-before-mutate constraint, unlike MNN tensor memory) - Phase 10 CAPT-02
….cpp) - New sgns::sgproccapture namespace: CaptureRecord, CaptureFile, SerializeCaptureFile, DeserializeCaptureFile - Reuses SerializeArtifact/SerializeManifest unmodified for the metadata+hash portion (D-01); appends a new length-prefixed raw-bytes section per rawOutputCapture invocation - DeserializeCaptureFile validates every declared length/count against remaining buffer size and a 1 GiB cap before allocating (T-10-02), and returns false (never throws) on malformed/truncated/oversized input (T-10-01a) - Round-trip serialize/deserialize and truncation/oversized-length rejection verified via a standalone scratch build (1 artifact, 2 chunk-hash-count, 2 capture records) - Phase 10 CAPT-01, CAPT-02
- New tools/ and tools/capture/ CMake subdirectories, wired via add_subdirectory(tools) in SGProcessingManager/CMakeLists.txt - New sgproccapture static library wrapping capture_file_format.hpp/.cpp (Plan 10-04), linked against sgprocmanagersha + SGArtifacts - New capture_harness executable: runs a Phase 09 fixture --repeat N times via ProcessingManager::Process()'s 5-arg ExecutionContext overload, independently re-hashes every captured buffer against the paired chunk/combined hash (CAPT-02 self-check), verifies same-node stability across all N runs (CAPT-03/D-04/D-05), and writes one machine/fixture/ timestamp-named .cap file only when both checks pass - Neither target is CTest-gated (Pattern 5) -- a meaningful cross-machine pass/fail needs Phase 11's physical machines
- New capture_diff executable: reads two .cap files, reports DIFF-01/02 per-element numeric divergence (absolute delta, relative delta, ULP distance, whole-buffer max/percentage-exceeding-threshold stats) over the final CaptureRecord's quantizedBytes, plus DIFF-03 hash-match booleans (contentHash/chunkHashes/combinedHash) computed independently from artifact/manifest metadata, to both console and a JSON report - Fixed named thresholds per D-07 (not CLI-configurable this phase): kRelativeDeltaEpsilonFloor (1e-6f), kDefaultFloatRelativeThreshold (1e-4), kDefaultByteAbsoluteThreshold (1) - Not CTest-gated (Pattern 5); links against Plan 10-05 Task 1's sgproccapture library
- Add guarded add_subdirectory(test) to SGProcessingManager/CMakeLists.txt under if(BUILD_TESTING), after the existing add_subdirectory(src) - Add add_subdirectory(capture) to test/CMakeLists.txt alongside the existing capability/execution/artifacts subdirectories
- test/capture/CMakeLists.txt: add_executable(capture_smoke_test) linked against SGProcessors (HasUsableVulkanDevice) + sgproccapture (DeserializeCaptureFile), registered via add_test(NAME CaptureSmokeTest) - test/capture/capture_smoke_test.cpp: runs capture_harness as a subprocess against the mnn-float fixture, asserts exit 0, exactly one well-formed output .cap file, and a successful DeserializeCaptureFile round-trip (artifacts.size()==1, combinedHash.size()==32) -- deliberately does not assert any specific hash value or cross-machine equality (Phase 11's job) - GTEST_SKIP()s (not fails) when HasUsableVulkanDevice() reports no usable GPU on the host, mirroring the existing Phase 09 conformance-suite convention - Verified: cmake configure + build succeeds; ctest -R CaptureSmokeTest passes (7.21s, real Vulkan device present on this host)
Repeated local/CI runs against the same OUTPUT_DIR accumulated prior runs' timestamped .cap files (D-02), so the 'exactly one file' assertion matched all of them instead of just this run's. Clean matching files before invoking capture_harness so the test is idempotent across reruns. Found during Phase 10 regression-gate re-verification.
…unit tests - QuantizeFloatBuffer: IEEE-754 canonicalization (denormal/NaN/Inf/signed-zero, D-06/D-07/D-08/D-09) followed by fixed-point scale-round-cast at S=2^20 (D-03/D-05), cited against Phase 11's measured Mac-vs-Windows divergence - QuantizeByteBuffer stays byte-identity for the render path, now documented as a deliberate Phase-11-data-justified decision, not an inherited stub - New quantization_test.cpp (CTest QuantizationTest) with 7 TEST_F cases covering every <behavior> bullet, exact bit-pattern comparisons only - New test/util/ CMakeLists.txt mirrors test/artifacts/'s shape; wired into test/CMakeLists.txt via add_subdirectory(util)
Phase 13 gap-closure attempt for VALD-01's MNN cross-hardware hash divergence: the original S=2^20 grid step gave only a ~9x margin over Phase 11's measured cross-machine maxAbsDelta and Phase 13's fresh re-validation showed 12/15 MNN chunk hashes still diverging. A local binary search over power-of-two S values against Secv01CounterTest.MnnCorruptedModelStillDiverges found S=2^14 (the plan's originally-proposed 64x-wider value) regresses SECV-01 deterministically -- the corrupted-model fixture's artifactId collides bit-for-bit with the correct model's at that grid coarseness. S=2^15 is the widest power-of-two grid step confirmed safe (one full power-of-two step of margin above the S=2^14 failure boundary), giving 32x the old grid step (~292x Phase 11's original maxAbsDelta) while QuantizationTest (7/7) and both SECV-01 cases still pass locally.
- Add chunkStats loop numeric-diffing rawRecordsPerArtifact[0][j] for each chunk (j < chunkHashCount), reusing ComputeFloat32Diff/ComputeUint8Diff unmodified - Add bounds-guarded fallback (sizeMismatch=true + stderr warning) for malformed/truncated capture files missing a chunk's raw record - Add chunkDiffs JSON array (index-aligned with chunkHashesMatch) and matching console output lines - Update header and inline doc comments to note the extension, preserving original trailing-record-only pass description as historically accurate - Purely additive: no pre-existing top-level JSON field renamed/removed
…FP16-opportunism hypothesis BackendConfig was previously unset (nullptr), leaving MNN at its default Precision_Normal, which permits GPU backends to opportunistically use FP16 for intermediate ops even on FP32-declared tensors. Different Vulkan implementations (Mac vs Windows) may make different FP16-vs-FP32 choices under that default, which is a plausible source of the cross-hardware divergence characterized in Plan 13-06 (chunk 10, exactly one S=2^15 grid step). This sets backendConfig.precision = Precision_High to force FP32 throughout and test whether that reduces or closes the divergence. Experimental -- not yet validated by a fresh cross-machine capture. Scoped to processing_processor_mnn_float.cpp only (the processor used by the float32 fixture under investigation); the other 6 MNN processors are untouched pending this experiment's outcome.
…sor — zero measured effect Forcing Precision_High produced a bit-for-bit identical chunk-10 divergence vs. default Precision_Normal, ruling out FP16 backend opportunism as the divergence source. No correctness benefit, only a potential perf cost, so reverting to nullptr (MNN default). Kept as a documented, dated comment so this dead end isn't re-tried blind. See STATE.md Blockers/Concerns.
…/maskBits through Quantize*Buffer - ResolveQuantScale/ResolveByteQuantMode added to quantization.hpp/.cpp, reading the job schema's generic parameters array (quantScale/byteQuantMode) with silent fallback to v2.1's exact prior constants (32768.0f / 0) on any invalid/missing declaration (D-04/D-05/D-07/D-08) - Power-of-two validation for quantScale uses only the integer bit-trick (never log2/pow), avoiding platform-dependent transcendental behavior - QuantizeFloatBuffer/QuantizeByteBuffer gain a new required third parameter (scale/maskBits); no defaulted overload, so every call site must resolve explicitly before calling - sgprocmanagerquant CMake target gains the generated/ include path and nlohmann_json::nlohmann_json link needed to compile against the new generated/Parameter.hpp dependency - All 7 pre-existing quantization_test.cpp TEST_F cases updated to the new 3-arg signatures; QuantizationTest suite (7/7) passes locally
…ack and boundary case - Added MakeParameters() test helper building a one-element std::vector<sgns::Parameter> via Parameter's public setters - 11 new TEST_F cases covering: null/missing/non-numeric/non-positive/non-power-of-two quantScale fallback (D-04/D-05), valid quantScale passthrough, null/negative byteQuantMode fallback (D-08), valid byteQuantMode passthrough, and the explicit N=8 (valid boundary) vs N=9 (falls back) boundary pair (D-07/D-08) - QuantizationTest suite now 18/18 passing locally (7 pre-existing + 11 new)
… processors Wire ResolveQuantScale into mnn_float, mnn_buffer, mnn_bool, mnn_image, mnn_string (6 QuantizeFloatBuffer call sites total). Replaces vestigial (void)parameters; suppression with a resolved scale passed as the required 3rd argument, matching Plan 14-01's new QuantizeFloatBuffer signature. mnn_string.cpp already used parameters for maxLength; the resolve call was inserted immediately before that block.
…ssors Wire ResolveQuantScale into mnn_mat4, mnn_mat3, mnn_mat2, mnn_int, mnn_tensor (10 QuantizeFloatBuffer call sites total: per-chunk-loop + stitched-output pair per file). Identical shape/recipe to Task 1 -- replace the vestigial (void)parameters; suppression with a resolved scale, thread it through both existing calls unchanged otherwise.
…p byte path Wire ResolveQuantScale into mnn_volume (1 call site), mnn_texture1d (1 call site), mnn_texturecube (2 call sites) -- all three already consume `parameters` via the existing ParseLayout call, so the vestigial (void)parameters; suppression was genuinely redundant. Wire ResolveByteQuantMode into render.cpp's single QuantizeByteBuffer call site (the one byte-path call in this milestone), resolved right after the existing ResolveUniforms call succeeds. All 21 QuantizeFloatBuffer/QuantizeByteBuffer call sites across all 14 processor files now resolve their scale/maskBits value from the job's own schema via ResolveQuantScale/ResolveByteQuantMode -- zero call sites remain on the old 2-arg signature. SGProcessors compiles clean (cmake --build SuperGenius/build/Windows/Debug --target SGProcessors --config Debug).
…ary) Closes a verification gap: ResolveByteQuantMode's N-value resolution was already tested, but QuantizeByteBuffer's actual masking arithmetic (value &= ~((1<<N)-1)) had zero automated coverage for maskBits > 0.
… add D-03/D-04 tolerance derivation - diff_utils.hpp/.cpp: ComputeFloat32Diff/ComputeUint8Diff/ElementDiffStats/ UlpDistanceFloat/OrderedFloatBits moved verbatim from capture_diff.cpp's unnamed namespace into namespace sgns::sgprocmanagerdiff, now header-exported and linkable (not file-local) - New ResolveChunkElementTypeHint/IsFloatChunkWithinTolerance/ IsByteChunkWithinTolerance implement D-03 (grid-step/mask-bound when quantScale/byteQuantMode validly declared) and D-04 (capture_diff's fixed kDefaultFloatRelativeThreshold/kDefaultByteAbsoluteThreshold otherwise) - Isolated TryGetDeclaredQuantScale/TryGetDeclaredByteQuantMode duplicate quantization.cpp's lookup loop but return boost::none on invalid/missing, since ResolveQuantScale/ResolveByteQuantMode's return type cannot distinguish "declared" from "fell back" - diff_utils_test.cpp: 18 TEST_F cases covering extraction correctness, element-type-hint defaults, and every D-03/D-04 pass/fail boundary
….cpp, register diff_utils_test - src/util/CMakeLists.txt: new add_library(sgprocmanagerdiff ...) target, mirroring sgprocmanagerquant's include/link/install shape verbatim - src/processors/CMakeLists.txt: SGProcessors' PUBLIC link list gains sgprocmanagerdiff alongside sgprocmanagerquant -- makes diff_utils.hpp transitively reachable from processing_service with zero further CMakeLists.txt edits (processing_service -> ProcessingBase -> SGProcessors -> sgprocmanagerdiff, all PUBLIC) - tools/capture/CMakeLists.txt: capture_diff links sgprocmanagerdiff - tools/capture/capture_diff.cpp: removed the unnamed-namespace diff- primitive definitions (moved to diff_utils in Plan 15-01 Task 1); now #includes util/diff_utils.hpp and calls sgns::sgprocmanagerdiff::ComputeFloat32Diff/ComputeUint8Diff explicitly qualified. main()/JSON-report logic unchanged. - test/util/CMakeLists.txt: registers diff_utils_test / DiffUtilsTest, mirroring quantization_test's block exactly Verified: diff_utils_test (18/18) and QuantizationTest pass; capture_diff and SGProcessors both build cleanly against the new shared library.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.