implementing foundations of xeon phi daemon
Build / build (push) Has been cancelled
Test / build_and_test (push) Has been cancelled

This commit is contained in:
2026-07-06 02:58:03 +02:00
parent b6ef13c198
commit 9fa97919b3
19 changed files with 1541 additions and 123 deletions
+295
View File
@@ -0,0 +1,295 @@
---
BasedOnStyle: Mozilla
AccessModifierOffset: 0
AlignAfterOpenBracket: Align
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: true
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: true
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveShortCaseStatements:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCaseArrows: false
AlignCaseColons: false
AlignConsecutiveTableGenBreakingDAGArgColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenCondOperatorColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignConsecutiveTableGenDefinitionColons:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
AlignFunctionDeclarations: false
AlignFunctionPointers: false
PadOperators: false
AlignEscapedNewlines: Right
AlignOperands: Align
AlignTrailingComments:
Kind: Always
OverEmptyLines: 0
AllowAllArgumentsOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowBreakBeforeNoexceptSpecifier: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseExpressionOnASingleLine: true
AllowShortCaseLabelsOnASingleLine: false
AllowShortCompoundRequirementOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: None
AllowShortIfStatementsOnASingleLine: Never
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: false
AllowShortNamespacesOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AttributeMacros:
- __capability
BinPackArguments: false
BinPackLongBracedList: true
BinPackParameters: OnePerLine
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Never
AfterEnum: true
AfterFunction: true
AfterNamespace: true
AfterObjCDeclaration: false
AfterStruct: true
AfterUnion: true
AfterExternBlock: true
BeforeCatch: true
BeforeElse: true
BeforeLambdaBody: false
BeforeWhile: true
IndentBraces: true
SplitEmptyFunction: true
SplitEmptyRecord: false
SplitEmptyNamespace: true
BracedInitializerIndentWidth: -1
BreakAdjacentStringLiterals: true
BreakAfterAttributes: Leave
BreakAfterJavaFieldAnnotations: false
BreakAfterReturnType: None
BreakArrays: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Allman
BreakBeforeConceptDeclarations: Always
BreakBeforeInlineASMColon: OnlyMultiline
BreakBeforeTemplateCloser: false
BreakBeforeTernaryOperators: true
BreakBinaryOperations: Never
BreakConstructorInitializers: BeforeComma
BreakFunctionDefinitionParameters: false
BreakInheritanceList: BeforeComma
BreakStringLiterals: true
BreakTemplateDeclarations: Yes
ColumnLimit: 128
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: false
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
EnumTrailingComma: Leave
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ^(<|"(gtest|gmock|isl|json)/)
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: .*
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentCaseLabels: true
IndentExportBlock: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 4
IndentWrappedFunctionNames: false
InsertBraces: false
InsertNewlineAtEOF: false
InsertTrailingCommas: None
IntegerLiteralSeparator:
Binary: 0
BinaryMinDigits: 0
Decimal: 0
DecimalMinDigits: 0
Hex: 0
HexMinDigits: 0
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLines:
AtEndOfFile: false
AtStartOfBlock: true
AtStartOfFile: true
KeepFormFeed: false
LambdaBodyIndentation: Signature
LineEnding: DeriveLF
MacroBlockBegin: ""
MacroBlockEnd: ""
MainIncludeChar: Quote
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 4
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: true
ObjCSpaceBeforeProtocolList: false
OneLineFormatOffRegex: ""
PPIndentWidth: -1
PackConstructorInitializers: BinPack
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakBeforeMemberAccess: 150
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakScopeResolution: 500
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: Always
RemoveBracesLLVM: false
RemoveEmptyLinesInUnwrappedLines: false
RemoveParentheses: Leave
RemoveSemicolon: false
RequiresClausePosition: OwnLine
RequiresExpressionIndentation: OuterScope
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SkipMacroDefinitionBody: false
SortIncludes:
Enabled: true
IgnoreCase: false
SortJavaStaticImport: Before
SortUsingDeclarations: LexicographicNumeric
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterOperatorKeyword: false
SpaceAfterTemplateKeyword: false
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeJsonColon: false
SpaceBeforeParens: Never
SpaceBeforeParensOptions:
AfterControlStatements: false
AfterForeachMacros: false
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: true
AfterNot: false
AfterOverloadedOperator: false
AfterPlacementOperator: true
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParens: Never
SpacesInParensOptions:
ExceptDoubleParentheses: false
InConditionalStatements: false
InCStyleCasts: false
InEmptyParentheses: false
Other: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 4
TableGenBreakInsideDAGArg: DontBreak
UseTab: ForIndentation
VerilogBreakBetweenInstancePorts: true
WhitespaceSensitiveMacros:
- BOOST_PP_STRINGIZE
- CF_SWIFT_NAME
- NS_SWIFT_NAME
- PP_STRINGIZE
- STRINGIZE
WrapNamespaceBodyWithEmptyLines: Leave
+200 -1
View File
@@ -14,7 +14,7 @@ To understand Vulkan - not as a humble API mere mortals call upon, but as a laby
It does not seek to produce a performant or production-worthy driver. \
*The gods are merciful, but not that merciful.*
## Soft [software implementation]
## Soft [software]
Soft be a software implementation of the Vulkan specification, abiding within this driver's own codebase.\
It maketh use of a bespoke [SPIR-V interpreter](https://git.kbz8.me/kbz_8/SPIRV-Interpreter) and renderer, by whose workings its labours are carried forth.
@@ -218,6 +218,205 @@ vkWaitForFences | ✅ Implemented
[Here](https://vulkan-driver.kbz8.me/cts/soft/) shalt thou find a most meticulous account of the Vulkan 1.0 conformance trials, set forth for thy scrutiny.
## Phi [Xeon Phi KNC]
Phi be an implementation of the Vulkan specification, wrought for the Xeon Phi Knights Corner cards.
Whether the Knights Landing cards shall one day receive the same providence remaineth to be seen.
### Build
If thou art truly determined:
```
zig build phi --release=[fast|safe|small]
```
And should thou seek additional build options with:
```
zig build --help
```
The same rites apply as for the Soft build.
#### Vulkan 1.0 specification
<details>
<summary>
Here standeth the present reckoning of thy Vulkan 1.0 implementation
</summary>
\
⚠️ Implemented, yet perchance not fully tested nor proven conformant, but rather working in a manner most general to thee and thine.\
Assume thou that functions lacking in this array are, for now, not intended to be wrought.
Name | Status
-------------------------------------------------|--------
vkAcquireNextImage2KHR | ⚙️ WIP
vkAcquireNextImageKHR | ⚙️ WIP
vkAllocateCommandBuffers | ⚙️ WIP
vkAllocateDescriptorSets | ⚙️ WIP
vkAllocateMemory | ✅ Implemented
vkBeginCommandBuffer | ⚙️ WIP
vkBindBufferMemory | ⚙️ WIP
vkBindImageMemory | ⚙️ WIP
vkCmdBeginQuery | ⚙️ WIP
vkCmdBeginRenderPass | ⚙️ WIP
vkCmdBindDescriptorSets | ⚙️ WIP
vkCmdBindIndexBuffer | ⚙️ WIP
vkCmdBindPipeline | ⚙️ WIP
vkCmdBindVertexBuffers | ⚙️ WIP
vkCmdBlitImage | ⚙️ WIP
vkCmdClearAttachments | ⚙️ WIP
vkCmdClearColorImage | ⚙️ WIP
vkCmdClearDepthStencilImage | ⚙️ WIP
vkCmdCopyBuffer | ⚙️ WIP
vkCmdCopyBufferToImage | ⚙️ WIP
vkCmdCopyImage | ⚙️ WIP
vkCmdCopyImageToBuffer | ⚙️ WIP
vkCmdCopyQueryPoolResults | ⚙️ WIP
vkCmdDispatch | ⚙️ WIP
vkCmdDispatchBaseKHR | ⚙️ WIP
vkCmdDispatchIndirect | ⚙️ WIP
vkCmdDraw | ⚙️ WIP
vkCmdDrawIndexed | ⚙️ WIP
vkCmdDrawIndexedIndirect | ⚙️ WIP
vkCmdDrawIndirect | ⚙️ WIP
vkCmdEndQuery | ⚙️ WIP
vkCmdEndRenderPass | ⚙️ WIP
vkCmdExecuteCommands | ⚙️ WIP
vkCmdFillBuffer | ⚙️ WIP
vkCmdNextSubpass | ⚙️ WIP
vkCmdPipelineBarrier | ⚙️ WIP
vkCmdPushConstants | ⚙️ WIP
vkCmdResetEvent | ⚙️ WIP
vkCmdResetQueryPool | ⚙️ WIP
vkCmdResolveImage | ⚙️ WIP
vkCmdSetBlendConstants | ⚙️ WIP
vkCmdSetDepthBias | ⚙️ WIP
vkCmdSetDepthBounds | ⚙️ WIP
vkCmdSetDeviceMaskKHR | ⚙️ WIP
vkCmdSetEvent | ⚙️ WIP
vkCmdSetLineWidth | ⚙️ WIP
vkCmdSetScissor | ⚙️ WIP
vkCmdSetStencilCompareMask | ⚙️ WIP
vkCmdSetStencilReference | ⚙️ WIP
vkCmdSetStencilWriteMask | ⚙️ WIP
vkCmdSetViewport | ⚙️ WIP
vkCmdUpdateBuffer | ⚙️ WIP
vkCmdWaitEvents | ⚙️ WIP
vkCmdWriteTimestamp | ⚙️ WIP
vkCreateBuffer | ⚙️ WIP
vkCreateBufferView | ⚙️ WIP
vkCreateCommandPool | ⚙️ WIP
vkCreateComputePipelines | ⚙️ WIP
vkCreateDescriptorPool | ⚙️ WIP
vkCreateDescriptorSetLayout | ⚙️ WIP
vkCreateDevice | ✅ Implemented
vkCreateEvent | ⚙️ WIP
vkCreateFence | ⚙️ WIP
vkCreateFramebuffer | ⚙️ WIP
vkCreateGraphicsPipelines | ⚙️ WIP
vkCreateImage | ⚙️ WIP
vkCreateImageView | ⚙️ WIP
vkCreateInstance | ✅ Implemented
vkCreatePipelineCache | ⚙️ WIP
vkCreatePipelineLayout | ⚙️ WIP
vkCreateQueryPool | ⚙️ WIP
vkCreateRenderPass | ⚙️ WIP
vkCreateSampler | ⚙️ WIP
vkCreateSemaphore | ⚙️ WIP
vkCreateShaderModule | ⚙️ WIP
vkCreateSwapchainKHR | ⚙️ WIP
vkCreateWaylandSurfaceKHR | ⚙️ WIP
vkCreateWin32SurfaceKHR | ⚙️ WIP
vkCreateXcbSurfaceKHR | ⚙️ WIP
vkCreateXlibSurfaceKHR | ⚙️ WIP
vkDestroyBuffer | ⚙️ WIP
vkDestroyBufferView | ⚙️ WIP
vkDestroyCommandPool | ⚙️ WIP
vkDestroyDescriptorPool | ⚙️ WIP
vkDestroyDescriptorSetLayout | ⚙️ WIP
vkDestroyDevice | ✅ Implemented
vkDestroyEvent | ⚙️ WIP
vkDestroyFence | ⚙️ WIP
vkDestroyFramebuffer | ⚙️ WIP
vkDestroyImage | ⚙️ WIP
vkDestroyImageView | ⚙️ WIP
vkDestroyInstance | ✅ Implemented
vkDestroyPipeline | ⚙️ WIP
vkDestroyPipelineCache | ⚙️ WIP
vkDestroyPipelineLayout | ⚙️ WIP
vkDestroyQueryPool | ⚙️ WIP
vkDestroyRenderPass | ⚙️ WIP
vkDestroySampler | ⚙️ WIP
vkDestroySemaphore | ⚙️ WIP
vkDestroyShaderModule | ⚙️ WIP
vkDestroySurfaceKHR | ⚙️ WIP
vkDestroySwapchainKHR | ⚙️ WIP
vkDeviceWaitIdle | ⚙️ WIP
vkEndCommandBuffer | ⚙️ WIP
vkEnumerateDeviceExtensionProperties | ⚙️ WIP
vkEnumerateDeviceLayerProperties | ⚙️ WIP
vkEnumerateInstanceExtensionProperties | ⚙️ WIP
vkEnumerateInstanceLayerProperties | ⚙️ WIP
vkEnumeratePhysicalDeviceGroupsKHR | ⚙️ WIP
vkEnumeratePhysicalDevices | ✅ Implemented
vkFlushMappedMemoryRanges | ⚙️ WIP
vkFreeCommandBuffers | ⚙️ WIP
vkFreeDescriptorSets | ⚙️ WIP
vkFreeMemory | ✅ Implemented
vkGetBufferDeviceAddress | ⚙️ WIP
vkGetBufferDeviceAddressEXT | ⚙️ WIP
vkGetBufferDeviceAddressKHR | ⚙️ WIP
vkGetBufferMemoryRequirements | ⚙️ WIP
vkGetDeviceGroupPeerMemoryFeaturesKHR | ⚙️ WIP
vkGetDeviceGroupPresentCapabilitiesKHR | ⚙️ WIP
vkGetDeviceGroupSurfacePresentModesKHR | ⚙️ WIP
vkGetDeviceMemoryCommitment | ⚙️ WIP
vkGetDeviceProcAddr | ⚙️ WIP
vkGetDeviceQueue | ⚙️ WIP
vkGetEventStatus | ⚙️ WIP
vkGetFenceStatus | ⚙️ WIP
vkGetImageMemoryRequirements | ⚙️ WIP
vkGetImageSparseMemoryRequirements | ⚙️ WIP
vkGetImageSubresourceLayout | ⚙️ WIP
vkGetInstanceProcAddr | ⚙️ WIP
vkGetPhysicalDeviceFeatures | ✅ Implemented
vkGetPhysicalDeviceFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceImageFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceMemoryProperties | ✅ Implemented
vkGetPhysicalDeviceProperties | ✅ Implemented
vkGetPhysicalDeviceQueueFamilyProperties | ⚙️ WIP
vkGetPhysicalDeviceSparseImageFormatProperties | ⚙️ WIP
vkGetPhysicalDeviceSurfaceCapabilitiesKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfaceFormatsKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfacePresentModesKHR | ⚙️ WIP
vkGetPhysicalDeviceSurfaceSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWaylandPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceWin32PresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXcbPresentationSupportKHR | ⚙️ WIP
vkGetPhysicalDeviceXlibPresentationSupportKHR | ⚙️ WIP
vkGetPipelineCacheData | ⚙️ WIP
vkGetQueryPoolResults | ⚙️ WIP
vkGetRenderAreaGranularity | ⚙️ WIP
vkGetSwapchainImagesKHR | ⚙️ WIP
vkInvalidateMappedMemoryRanges | ⚙️ WIP
vkMapMemory | ⚙️ WIP
vkMergePipelineCaches | ⚙️ WIP
vkQueueBindSparse | ⚙️ WIP
vkQueuePresentKHR | ⚙️ WIP
vkQueueSubmit | ⚙️ WIP
vkQueueWaitIdle | ⚙️ WIP
vkResetCommandBuffer | ⚙️ WIP
vkResetCommandPool | ⚙️ WIP
vkResetDescriptorPool | ⚙️ WIP
vkResetEvent | ⚙️ WIP
vkResetFences | ⚙️ WIP
vkResetQueryPool | ⚙️ WIP
vkSetEvent | ⚙️ WIP
vkUnmapMemory | ⚙️ WIP
vkUpdateDescriptorSets | ⚙️ WIP
vkWaitForFences | ⚙️ WIP
</details>
## License
Released unto the world as MIT for study, experimentation, and the occasional horrified whisper.
+213 -114
View File
@@ -218,120 +218,6 @@ pub fn build(b: *std.Build) !void {
docs_step.dependOn(&install_docs.step);
}
fn customApe(
b: *std.Build,
lib: *Step.Compile,
lib_mod: *std.Build.Module,
base_mod: *std.Build.Module,
vulkan: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
for (implementations) |impl| {
if (std.mem.eql(u8, impl.name, "ape"))
continue;
const mod = b.createModule(.{
.root_source_file = b.path(impl.root_source_file),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "base", .module = base_mod },
.{ .name = "vulkan", .module = vulkan },
},
});
if (impl.custom) |func| {
func(b, lib, mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue;
}
lib_mod.addImport(impl.name, mod);
}
}
fn customSoft(
b: *std.Build,
_: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
const spv = b.lazyDependency("SPIRV_Interpreter", .{
.target = target,
.optimize = optimize,
.@"use-llvm" = use_llvm,
}) orelse return error.UnresolvedDependency;
lib_mod.addImport("soft_c", base_c_mod);
lib_mod.addImport("spv", spv.module("spv"));
}
fn optionsSoft(b: *std.Build, options: *Step.Options) !void {
const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false;
const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true;
const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation");
const compute_dump_final_results_table_option = b.option(u32, "soft-compute-dump-final-results-table", "Dump compute shaders results table after invocation");
const approxiamte_rgb_option = b.option(bool, "soft-approximates-rgb", "Approximate sRGB <-> RGB conversions") orelse true;
options.addOption(bool, "soft_single_threaded", single_threaded_option);
options.addOption(bool, "soft_shaders_simd", shaders_simd_option);
options.addOption(?u32, "soft_compute_dump_early_results_table", compute_dump_early_results_table_option);
options.addOption(?u32, "soft_compute_dump_final_results_table", compute_dump_final_results_table_option);
options.addOption(bool, "soft_approximates_rgb", approxiamte_rgb_option);
}
fn customFlint(
_: *std.Build,
_: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
_: std.Build.ResolvedTarget,
_: std.builtin.OptimizeMode,
_: bool,
) !void {
lib_mod.addImport("intel_c", base_c_mod);
}
fn optionsFlint(b: *std.Build, options: *Step.Options) !void {
_ = b;
_ = options;
}
fn customPhi(
b: *std.Build,
_: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
lib_mod.addImport("phi_c", base_c_mod);
const miclib = b.lazyDependency("miclib", .{
.target = target,
.optimize = optimize,
.@"use-llvm" = use_llvm,
}) orelse return error.UnresolvedDependency;
lib_mod.addImport("miclib", miclib.module("miclib"));
}
fn optionsPhi(b: *std.Build, options: *Step.Options) !void {
_ = b;
_ = options;
}
fn addCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *const ImplementationDesc, impl_lib: *Step.Compile, comptime mode: RunningMode) !*Step {
const cts = b.dependency("cts_bin", .{});
@@ -502,3 +388,216 @@ fn addMultithreadedCTS(b: *std.Build, target: std.Build.ResolvedTarget, impl: *c
return &run.step;
}
// Ape specialized functions
fn customApe(
b: *std.Build,
lib: *Step.Compile,
lib_mod: *std.Build.Module,
base_mod: *std.Build.Module,
vulkan: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
for (implementations) |impl| {
if (std.mem.eql(u8, impl.name, "ape"))
continue;
const mod = b.createModule(.{
.root_source_file = b.path(impl.root_source_file),
.target = target,
.optimize = optimize,
.imports = &.{
.{ .name = "base", .module = base_mod },
.{ .name = "vulkan", .module = vulkan },
},
});
if (impl.custom) |func| {
func(b, lib, mod, base_mod, vulkan, base_c_mod, target, optimize, use_llvm) catch continue;
}
lib_mod.addImport(impl.name, mod);
}
}
// Soft specialized functions
fn customSoft(
b: *std.Build,
_: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
const spv = b.lazyDependency("SPIRV_Interpreter", .{
.target = target,
.optimize = optimize,
.@"use-llvm" = use_llvm,
}) orelse return error.UnresolvedDependency;
lib_mod.addImport("soft_c", base_c_mod);
lib_mod.addImport("spv", spv.module("spv"));
}
fn optionsSoft(b: *std.Build, options: *Step.Options) !void {
const single_threaded_option = b.option(bool, "soft-single-threaded", "Single threaded runtime mode") orelse false;
const shaders_simd_option = b.option(bool, "soft-shader-simd", "Shaders SIMD acceleration") orelse true;
const compute_dump_early_results_table_option = b.option(u32, "soft-compute-dump-early-results-table", "Dump compute shaders results table before invocation");
const compute_dump_final_results_table_option = b.option(u32, "soft-compute-dump-final-results-table", "Dump compute shaders results table after invocation");
const approxiamte_rgb_option = b.option(bool, "soft-approximates-rgb", "Approximate sRGB <-> RGB conversions") orelse true;
options.addOption(bool, "soft_single_threaded", single_threaded_option);
options.addOption(bool, "soft_shaders_simd", shaders_simd_option);
options.addOption(?u32, "soft_compute_dump_early_results_table", compute_dump_early_results_table_option);
options.addOption(?u32, "soft_compute_dump_final_results_table", compute_dump_final_results_table_option);
options.addOption(bool, "soft_approximates_rgb", approxiamte_rgb_option);
}
// Flint specialized functions
fn customFlint(
_: *std.Build,
_: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
_: std.Build.ResolvedTarget,
_: std.builtin.OptimizeMode,
_: bool,
) !void {
lib_mod.addImport("intel_c", base_c_mod);
}
fn optionsFlint(b: *std.Build, options: *Step.Options) !void {
_ = b;
_ = options;
}
// Phi specialized functions
fn customPhi(
b: *std.Build,
lib: *Step.Compile,
lib_mod: *std.Build.Module,
_: *std.Build.Module,
_: *std.Build.Module,
base_c_mod: *std.Build.Module,
target: std.Build.ResolvedTarget,
optimize: std.builtin.OptimizeMode,
use_llvm: bool,
) !void {
lib_mod.addImport("phi_c", base_c_mod);
const miclib = b.lazyDependency("miclib", .{
.target = target,
.optimize = optimize,
.@"use-llvm" = use_llvm,
}) orelse return error.UnresolvedDependency;
lib_mod.addImport("miclib", miclib.module("miclib"));
const phi_protocol_c = b.addTranslateC(.{
.root_source_file = b.path("src/phi/shared/Protocol.h"),
.target = target,
.optimize = optimize,
.link_libc = false,
});
lib_mod.addImport("phi_protocol_c", phi_protocol_c.createModule());
// To avoid duplicated options due to Ape's custom function
if (!std.mem.eql(u8, lib.name, "vulkan_phi"))
return;
const build_card = b.option(
bool,
"phi-build-card",
"Build Xeon Phi card daemon",
) orelse true;
if (!build_card)
return;
const cc = b.option(
[]const u8,
"phi-card-cc",
"Path to k1om-mpss-linux-gcc",
) orelse "k1om-mpss-linux-gcc";
const sysroot = b.option(
[]const u8,
"phi-card-sysroot",
"MPSS sysroot path",
);
const daemon = try addPhiCardDaemon(b, optimize, cc, sysroot);
const install_daemon = b.addInstallFile(daemon, "lib/phi_device.mic");
lib.step.dependOn(&install_daemon.step);
}
fn optionsPhi(b: *std.Build, options: *Step.Options) !void {
_ = b;
_ = options;
}
fn addPhiCardDaemon(
b: *std.Build,
optimize: std.builtin.OptimizeMode,
cc: []const u8,
sysroot: ?[]const u8,
) !std.Build.LazyPath {
const cmd = b.addSystemCommand(&.{cc});
cmd.addArgs(&.{
"-std=c11",
"-Wall",
"-Wextra",
"-Wno-unused-parameter",
"-pthread",
});
cmd.addArg("-I");
cmd.addDirectoryArg(b.path("src/phi/mic"));
cmd.addArg("-I");
cmd.addDirectoryArg(b.path("src/phi/shared"));
if (sysroot) |path| {
cmd.addArg("--sysroot");
cmd.addArg(path);
}
switch (optimize) {
.Debug => cmd.addArgs(&.{ "-O0", "-g3" }),
.ReleaseSafe => cmd.addArgs(&.{ "-O2", "-g", "-DNDEBUG" }),
.ReleaseFast => cmd.addArgs(&.{ "-O3", "-DNDEBUG" }),
.ReleaseSmall => cmd.addArgs(&.{ "-Os", "-DNDEBUG" }),
}
const sources = [_][]const u8{
"src/phi/mic/main.c",
"src/phi/mic/Daemon.c",
"src/phi/mic/Logger.c",
"src/phi/mic/Memory.c",
// Add new files here
};
for (sources) |source| {
cmd.addFileArg(b.path(source));
}
cmd.addArgs(&.{
"-lscif",
"-o",
});
return cmd.addOutputFileArg("phi_device.mic");
}
+5
View File
@@ -0,0 +1,5 @@
-xc
-std=c11
-Isrc/phi/shared
-Isrc/phi/mic
-isystem/opt/mpss/3.8.6/sysroots/k1om-mpss-linux/usr/include/
+8
View File
@@ -3,6 +3,8 @@ const vk = @import("vulkan");
const base = @import("base");
const PhiQueue = @import("PhiQueue.zig");
const PhiPhysicalDevice = @import("PhiPhysicalDevice.zig");
const PhiTransport = @import("PhiTransport.zig");
pub const PhiBinarySemaphore = @import("PhiBinarySemaphore.zig");
pub const PhiBuffer = @import("PhiBuffer.zig");
@@ -32,6 +34,7 @@ const Self = @This();
pub const Interface = base.Device;
interface: Interface,
transport: PhiTransport,
pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, allocator: std.mem.Allocator, info: *const vk.DeviceCreateInfo) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -71,8 +74,12 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
.getDeviceGroupSurfacePresentModesKHR = getDeviceGroupSurfacePresentModesKHR,
};
const phi_physical_device: *PhiPhysicalDevice = @alignCast(@fieldParentPtr("interface", physical_device));
const transport = try PhiTransport.init(phi_physical_device.scif_node_id);
self.* = .{
.interface = interface,
.transport = transport,
};
try self.interface.createQueues(allocator, info);
@@ -81,6 +88,7 @@ pub fn create(instance: *base.Instance, physical_device: *base.PhysicalDevice, a
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
self.transport.deinit();
allocator.destroy(self);
}
+45 -4
View File
@@ -11,6 +11,8 @@ const Self = @This();
pub const Interface = base.DeviceMemory;
interface: Interface,
remote_handle: u64,
data: ?[]u8,
pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceSize, memory_type_index: u32) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
@@ -26,14 +28,44 @@ pub fn create(device: *PhiDevice, allocator: std.mem.Allocator, size: vk.DeviceS
.invalidateRange = invalidateRange,
};
if (memory_type_index >= device.interface.physical_device.mem_props.memory_type_count) {
return VkError.ValidationFailed;
}
const memory_type = device.interface.physical_device.mem_props.memory_types[memory_type_index];
const host_visible = memory_type.property_flags.host_visible_bit;
const device_local = memory_type.property_flags.device_local_bit;
const allocation_size = std.math.cast(usize, size) orelse return VkError.OutOfDeviceMemory;
const remote_handle = if (device_local) blk: {
const remote = try device.transport.allocMemory(size, memory_type_index);
break :blk remote.remote_handle;
} else 0;
errdefer if (remote_handle != 0) device.transport.freeMemory(remote_handle);
const data = if (host_visible)
device.interface.device_allocator.allocator().alloc(u8, allocation_size) catch return VkError.OutOfDeviceMemory
else
null;
self.* = .{
.interface = interface,
.remote_handle = remote_handle,
.data = data,
};
return self;
}
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
const device: *PhiDevice = @alignCast(@fieldParentPtr("interface", interface.owner));
if (self.data) |data| {
interface.owner.device_allocator.allocator().free(data);
}
if (self.remote_handle != 0) {
device.transport.freeMemory(self.remote_handle);
}
allocator.destroy(self);
}
@@ -51,10 +83,19 @@ pub fn invalidateRange(interface: *Interface, offset: vk.DeviceSize, size: vk.De
pub fn map(interface: *Interface, offset: vk.DeviceSize, size: vk.DeviceSize) VkError![]u8 {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
_ = self;
_ = offset;
_ = size;
return VkError.Unknown;
const data = self.data orelse return VkError.MemoryMapFailed;
const map_offset = std.math.cast(usize, offset) orelse return VkError.MemoryMapFailed;
if (map_offset >= data.len) {
return VkError.MemoryMapFailed;
}
const map_size = if (size == vk.WHOLE_SIZE)
data.len - map_offset
else
std.math.cast(usize, size) orelse return VkError.MemoryMapFailed;
if (map_size > data.len - map_offset) {
return VkError.MemoryMapFailed;
}
return data[map_offset..(map_offset + map_size)];
}
pub fn unmap(_: *Interface) void {}
+1 -1
View File
@@ -97,7 +97,7 @@ fn requestPhysicalDevices(interface: *Interface, allocator: std.mem.Allocator, _
};
defer device.deinit();
const physical_device = try PhiPhysicalDevice.create(allocator, interface, device);
const physical_device = try PhiPhysicalDevice.create(allocator, interface, device, device_num);
errdefer physical_device.interface.release(allocator) catch {};
const dispatchable = try Dispatchable(base.PhysicalDevice).wrap(allocator, &physical_device.interface);
+9 -3
View File
@@ -31,8 +31,9 @@ pub const EXTENSIONS = [_]vk.ExtensionProperties{
};
interface: Interface,
scif_node_id: u16,
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: mic.Device) VkError!*Self {
pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device: mic.Device, mic_device_num: u32) VkError!*Self {
const self = allocator.create(Self) catch return VkError.OutOfHostMemory;
errdefer allocator.destroy(self);
@@ -233,12 +234,12 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device
.size = memory.size() catch 0,
.flags = .{ .device_local_bit = true },
};
interface.mem_props.memory_heaps[0] = .{
interface.mem_props.memory_heaps[1] = .{
.size = std.process.totalSystemMemory() catch 0,
.flags = .{},
};
} else |err| {
std.log.scoped(.MIC).err("Failed to fetch device PCI config: {s}", .{@errorName(err)});
std.log.scoped(.MIC).err("Failed to fetch device memory infos: {s}", .{@errorName(err)});
return VkError.InitializationFailed;
}
@@ -260,11 +261,16 @@ pub fn create(allocator: std.mem.Allocator, instance: *base.Instance, mic_device
self.* = .{
.interface = interface,
.scif_node_id = deviceNumToScifNode(mic_device_num),
};
return self;
}
fn deviceNumToScifNode(device_num: u32) u16 {
return @intCast(device_num + 1);
}
pub fn destroy(interface: *Interface, allocator: std.mem.Allocator) VkError!void {
const self: *Self = @alignCast(@fieldParentPtr("interface", interface));
allocator.destroy(self);
+155
View File
@@ -0,0 +1,155 @@
const std = @import("std");
const base = @import("base");
const lib = @import("lib.zig");
const scif = @import("scif.zig");
const VkError = base.VkError;
const proto = lib.proto;
const Self = @This();
epd: scif.epd_t,
sequence: u64 = 1,
mutex: base.SpinMutex = .{},
pub fn init(node_id: u16) VkError!Self {
try scif.load();
errdefer scif.unload();
const epd = scif.open();
if (epd < 0) {
std.log.scoped(.PhiTransport).err("SCIF open failed", .{});
return VkError.InitializationFailed;
}
errdefer _ = scif.close(epd);
var dst: scif.PortId = .{
.node = node_id,
.port = @intCast(proto.PHI_SCIF_PORT),
};
if (scif.connect(epd, &dst) < 0) {
std.log.scoped(.PhiTransport).err("SCIF connection to node {d} port {d} failed", .{ dst.node, dst.port });
return VkError.InitializationFailed;
}
var self: Self = .{ .epd = epd };
try self.handshake();
return self;
}
pub fn deinit(self: *Self) void {
_ = scif.close(self.epd);
scif.unload();
}
pub fn allocMemory(self: *Self, size: u64, memory_type_index: u32) VkError!proto.PhiAllocMemoryReply {
self.mutex.lock();
defer self.mutex.unlock();
const alloc_request: proto.PhiAllocMemoryRequest = .{
.size = size,
.memory_type_index = memory_type_index,
.flags = 0,
};
var reply: proto.PhiAllocMemoryReply = undefined;
try self.request(proto.PHI_COMMAND_ALLOC_MEMORY, std.mem.asBytes(&alloc_request), std.mem.asBytes(&reply));
if (reply.result.status != proto.PHI_STATUS_OK) {
return mapStatus(reply.result.status);
}
return reply;
}
pub fn freeMemory(self: *Self, remote_handle: u64) void {
self.mutex.lock();
defer self.mutex.unlock();
const request_payload: proto.PhiFreeMemoryRequest = .{
.remote_handle = remote_handle,
};
var reply: proto.PhiFreeMemoryReply = undefined;
self.request(proto.PHI_COMMAND_FREE_MEMORY, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply)) catch |err| {
std.log.scoped(.PhiTransport).err("Remote free failed: {s}", .{@errorName(err)});
return;
};
if (reply.result.status != proto.PHI_STATUS_OK) {
std.log.scoped(.PhiTransport).err("Remote free returned status {d}", .{reply.result.status});
}
}
fn handshake(self: *Self) VkError!void {
const request_payload: proto.PhiHelloRequest = .{
.host_protocol_version = proto.PHI_PROTOCOL_VERSION,
.reserved = 0,
};
var reply: proto.PhiHelloReply = undefined;
try self.request(proto.PHI_COMMAND_HELLO, std.mem.asBytes(&request_payload), std.mem.asBytes(&reply));
if (reply.result.status != proto.PHI_STATUS_OK) {
return mapStatus(reply.result.status);
}
if (reply.device_protocol_version != proto.PHI_PROTOCOL_VERSION) {
std.log.scoped(.PhiTransport).err("Unsupported Phi protocol version {d}", .{reply.device_protocol_version});
return VkError.InitializationFailed;
}
}
fn request(self: *Self, command: c_uint, payload: []const u8, reply_payload: []u8) VkError!void {
const sequence = self.sequence;
self.sequence += 1;
const header: proto.PhiMessageHeader = .{
.magic = proto.PHI_PROTOCOL_MAGIC,
.version = proto.PHI_PROTOCOL_VERSION,
.type = @intCast(command),
.sequence = sequence,
.payload_size = payload.len,
};
try self.writeAll(std.mem.asBytes(&header));
try self.writeAll(payload);
var reply_header: proto.PhiMessageHeader = undefined;
try self.readAll(std.mem.asBytes(&reply_header));
if (reply_header.magic != proto.PHI_PROTOCOL_MAGIC or
reply_header.version != proto.PHI_PROTOCOL_VERSION or
reply_header.type != header.type or
reply_header.sequence != sequence or
reply_header.payload_size != reply_payload.len)
{
std.log.scoped(.PhiTransport).err("Invalid Phi reply header", .{});
return VkError.InitializationFailed;
}
try self.readAll(reply_payload);
}
fn writeAll(self: *Self, bytes: []const u8) VkError!void {
var offset: usize = 0;
while (offset < bytes.len) {
const written = scif.send(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.SEND_BLOCK);
if (written <= 0) {
return VkError.InitializationFailed;
}
offset += @intCast(written);
}
}
fn readAll(self: *Self, bytes: []u8) VkError!void {
var offset: usize = 0;
while (offset < bytes.len) {
const read = scif.recv(self.epd, bytes[offset..].ptr, bytes.len - offset, scif.RECV_BLOCK);
if (read <= 0) {
return VkError.InitializationFailed;
}
offset += @intCast(read);
}
}
fn mapStatus(status: c_int) VkError {
return switch (status) {
proto.PHI_STATUS_OUT_OF_MEMORY => VkError.OutOfDeviceMemory,
proto.PHI_STATUS_UNSUPPORTED_VERSION => VkError.InitializationFailed,
else => VkError.Unknown,
};
}
+5
View File
@@ -3,13 +3,16 @@ const vk = @import("vulkan");
pub const base = @import("base");
pub const c = @import("phi_c");
pub const proto = @import("phi_protocol_c");
pub const config = base.config;
pub const mic = @import("miclib");
pub const scif = @import("scif.zig");
pub const PhiInstance = @import("PhiInstance.zig");
pub const PhiDevice = @import("PhiDevice.zig");
pub const PhiPhysicalDevice = @import("PhiPhysicalDevice.zig");
pub const PhiQueue = @import("PhiQueue.zig");
pub const PhiTransport = @import("PhiTransport.zig");
pub const PhiBinarySemaphore = @import("PhiBinarySemaphore.zig");
pub const PhiBuffer = @import("PhiBuffer.zig");
@@ -70,6 +73,8 @@ test {
std.testing.refAllDecls(PhiImageView);
std.testing.refAllDecls(PhiInstance);
std.testing.refAllDecls(PhiPhysicalDevice);
std.testing.refAllDecls(PhiTransport);
std.testing.refAllDecls(scif);
std.testing.refAllDecls(PhiPipeline);
std.testing.refAllDecls(PhiPipelineCache);
std.testing.refAllDecls(PhiPipelineLayout);
+193
View File
@@ -0,0 +1,193 @@
#include <Daemon.h>
#include <Logger.h>
#include <Memory.h>
static int HandleHello(scif_epd_t endpoint, const PhiMessageHeader* header)
{
PhiHelloRequest request;
PhiHelloReply reply = {
.result = {
.status = PHI_STATUS_OK,
.reserved = 0,
},
.device_protocol_version = PHI_PROTOCOL_VERSION,
.pointer_bits = (uint32_t)(sizeof(void *) * 8u),
};
if(header->payload_size != sizeof(request))
{
if(DrainPayload(endpoint, header->payload_size) < 0)
return -1;
reply.result.status = PHI_STATUS_BAD_MESSAGE;
return SendReply(endpoint, header, &reply, sizeof(reply));
}
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
return -1;
if(request.host_protocol_version != PHI_PROTOCOL_VERSION)
reply.result.status = PHI_STATUS_UNSUPPORTED_VERSION;
return SendReply(endpoint, header, &reply, sizeof(reply));
}
scif_epd_t StartDaemon()
{
PhiLogInfo("Starting the daemon...");
scif_epd_t endpoint = scif_open();
if(endpoint < 0)
{
PhiLogError("Failed to create SCIF endpoint");
return 0;
}
if(scif_bind(endpoint, PHI_SCIF_PORT) < 0)
{
PhiLogError("Failed to bind SCIF port");
scif_close(endpoint);
return 0;
}
if(scif_listen(endpoint, 1) < 0)
{
PhiLogError("Could not listen to SCIF port");
scif_close(endpoint);
return 0;
}
return endpoint;
}
void ShutdownDaemon(scif_epd_t endpoint)
{
PhiLogInfo("Shuting down the daemon...");
scif_close(endpoint);
}
int HandlePacket(scif_epd_t endpoint)
{
for(;;)
{
PhiMessageHeader header;
if(ReadAll(endpoint, &header, sizeof(header)) < 0)
return -1;
if(header.magic != PHI_PROTOCOL_MAGIC || header.version != PHI_PROTOCOL_VERSION)
{
if(DrainPayload(endpoint, header.payload_size) < 0)
return -1;
if(SendStatus(endpoint, &header, PHI_STATUS_BAD_MESSAGE) < 0)
return -1;
continue;
}
switch((PhiCommandType)header.type)
{
case PHI_COMMAND_HELLO:
if(HandleHello(endpoint, &header) < 0)
return -1;
break;
case PHI_COMMAND_ALLOC_MEMORY:
if(HandleAllocMemory(endpoint, &header) < 0)
return -1;
break;
case PHI_COMMAND_FREE_MEMORY:
if(HandleFreeMemory(endpoint, &header) < 0)
return -1;
break;
case PHI_COMMAND_SHUTDOWN:
if(DrainPayload(endpoint, header.payload_size) < 0)
return -1;
if(SendStatus(endpoint, &header, PHI_STATUS_OK) < 0)
return -1;
return 0;
default:
if(DrainPayload(endpoint, header.payload_size) < 0)
return -1;
if(SendStatus(endpoint, &header, PHI_STATUS_UNSUPPORTED_COMMAND) < 0)
return -1;
break;
}
}
}
int ReadAll(scif_epd_t endpoint, void* data, size_t size)
{
uint8_t* bytes = data;
size_t offset = 0;
while(offset < size)
{
int got = scif_recv(endpoint, bytes + offset, size - offset, SCIF_RECV_BLOCK);
if(got <= 0)
return -1;
offset += (size_t)got;
}
return 0;
}
int WriteAll(scif_epd_t endpoint, const void* data, size_t size)
{
const uint8_t* bytes = data;
size_t offset = 0;
while(offset < size)
{
int sent = scif_send(endpoint, (void*)(bytes + offset), size - offset, SCIF_SEND_BLOCK);
if(sent <= 0)
return -1;
offset += (size_t)sent;
}
return 0;
}
int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size)
{
PhiMessageHeader reply = {
.magic = PHI_PROTOCOL_MAGIC,
.version = PHI_PROTOCOL_VERSION,
.type = request->type,
.sequence = request->sequence,
.payload_size = payload_size,
};
if(WriteAll(endpoint, &reply, sizeof(reply)) < 0)
return -1;
return WriteAll(endpoint, payload, (size_t)payload_size);
}
int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status)
{
PhiFreeMemoryReply reply = {
.result = {
.status = status,
.reserved = 0,
},
};
return SendReply(endpoint, request, &reply, sizeof(reply));
}
int DrainPayload(scif_epd_t endpoint, uint64_t size)
{
uint8_t buffer[256];
while(size > 0)
{
size_t chunk = size < sizeof(buffer) ? (size_t)size : sizeof(buffer);
if(ReadAll(endpoint, buffer, chunk) < 0)
return -1;
size -= chunk;
}
return 0;
}
+20
View File
@@ -0,0 +1,20 @@
#ifndef APE_PHI_DAEMON_H
#define APE_PHI_DAEMON_H
#include <sys/types.h>
#include <scif.h>
#include <Protocol.h>
scif_epd_t StartDaemon();
void ShutdownDaemon(scif_epd_t endpoint);
int DrainPayload(scif_epd_t endpoint, uint64_t size);
int HandlePacket(scif_epd_t endpoint);
int ReadAll(scif_epd_t endpoint, void* data, size_t size);
int SendReply(scif_epd_t endpoint, const PhiMessageHeader* request, const void* payload, uint64_t payload_size);
int SendStatus(scif_epd_t endpoint, const PhiMessageHeader* request, PhiStatus status);
int WriteAll(scif_epd_t endpoint, const void* data, size_t size);
#endif
+93
View File
@@ -0,0 +1,93 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
#include <Logger.h>
#define RED 31
#define GREEN 32
#define BLUE 34
#define DEF 0
#define BLACK 30
#define YELLOW 33
#define MAGENTA 35
#define CYAN 36
#define WHITE 37
#define BG_RED 41
#define BG_GREEN 42
#define BG_BLUE 44
#define BG_DEF 0
#define BG_BLACK 40
#define BG_YELLOW 43
#define BG_MAGENTA 45
#define BG_CYAN 46
#define BG_WHITE 47
#define RESET 0
#define BOLD 1
#define UNDERLINE 4
#define INVERSE 7
#define BOLD_OFF 21
#define UNDERLINE_OFF 24
#define INVERSE_OFF 27
inline static void SetConsoleColor(FILE* file, int code)
{
fprintf(file, "\033[1;%dm", code);
}
void PhiLog(PhiLogLevel level, const char* fmt, const char* file, const char* function, int line, ...)
{
time_t now = time(0);
struct tm tstruct = *localtime(&now);
char buffer[128];
strftime(buffer, sizeof(buffer), "[%X] ", &tstruct);
FILE* out = stdout;
if(level != PHI_LOG_LEVEL_INFO)
out = stderr;
// Way too much printf calls
SetConsoleColor(out, MAGENTA);
fprintf(out, "[Phi device ");
SetConsoleColor(out, GREEN);
fprintf(out, "Phi");
SetConsoleColor(out, YELLOW);
fprintf(out, "%s", buffer);
SetConsoleColor(out, MAGENTA);
fputc(']', out);
switch(level)
{
case PHI_LOG_LEVEL_INFO:
SetConsoleColor(out, BLUE);
fprintf(out, "[info] ");
break;
case PHI_LOG_LEVEL_WARN:
SetConsoleColor(out, MAGENTA);
fprintf(out, "[warn] ");
break;
case PHI_LOG_LEVEL_ERR:
case PHI_LOG_LEVEL_FATAL:
SetConsoleColor(out, RED);
fprintf(out, "[err] ");
break;
}
va_list argptr;
va_start(argptr, line);
SetConsoleColor(out, RESET);
fprintf(out, fmt, argptr);
fputc('\n', out);
if(level == PHI_LOG_LEVEL_FATAL)
{
SetConsoleColor(out, BG_RED);
fprintf(out, "Fatal Error: emergency exit\n");
SetConsoleColor(out, BG_DEF);
abort();
}
}
+24
View File
@@ -0,0 +1,24 @@
#ifndef APE_PHI_LOGGER_H
#define APE_PHI_LOGGER_H
typedef enum PhiLogLevel
{
PHI_LOG_LEVEL_INFO = 0,
PHI_LOG_LEVEL_WARN = 1,
PHI_LOG_LEVEL_ERR = 2,
PHI_LOG_LEVEL_FATAL = 3,
} PhiLogLevel;
void PhiLog(PhiLogLevel level, const char* fmt, const char* file, const char* function, int line, ...);
#define PhiLogError(msg) PhiLog(PHI_LOG_LEVEL_ERR, msg, __FILE__, __FUNCTION__, __LINE__)
#define PhiLogWarning(msg) PhiLog(PHI_LOG_LEVEL_WARN, msg, __FILE__, __FUNCTION__, __LINE__)
#define PhiLogInfo(msg) PhiLog(PHI_LOG_LEVEL_INFO, msg, __FILE__, __FUNCTION__, __LINE__)
#define PhiLogFatal(msg) PhiLog(PHI_LOG_LEVEL_FATAL, msg, __FILE__, __FUNCTION__, __LINE__)
#define PhiLogErrorFmt(msg, ...) PhiLog(PHI_LOG_LEVEL_ERR, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#define PhiLogWarningFmt(msg, ...) PhiLog(PHI_LOG_LEVEL_WARN, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#define PhiLogInfoFmt(msg, ...) PhiLog(PHI_LOG_LEVEL_INFO, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#define PhiLogFatalFmt(msg, ...) PhiLog(PHI_LOG_LEVEL_FATAL, msg, __FILE__, __FUNCTION__, __LINE__, __VA_ARGS__)
#endif
+73
View File
@@ -0,0 +1,73 @@
#include <stdlib.h>
#include <Logger.h>
#include <Memory.h>
int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header)
{
PhiAllocMemoryRequest request;
PhiAllocMemoryReply reply = {
.result = {
.status = PHI_STATUS_OK,
.reserved = 0,
},
.remote_handle = 0,
.size = 0,
};
void* memory;
if(header->payload_size != sizeof(request))
{
if(DrainPayload(endpoint, header->payload_size) < 0)
return -1;
reply.result.status = PHI_STATUS_BAD_MESSAGE;
return SendReply(endpoint, header, &reply, sizeof(reply));
}
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
return -1;
memory = calloc(1, (size_t)request.size);
if(memory == NULL)
reply.result.status = PHI_STATUS_OUT_OF_MEMORY;
else
{
reply.remote_handle = (uint64_t)(uintptr_t)memory;
reply.size = request.size;
PhiLogInfoFmt("Allocated %zu bytes", (size_t)request.size);
}
return SendReply(endpoint, header, &reply, sizeof(reply));
}
int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header)
{
PhiFreeMemoryRequest request;
PhiFreeMemoryReply reply = {
.result = {
.status = PHI_STATUS_OK,
.reserved = 0,
},
};
if(header->payload_size != sizeof(request))
{
if(DrainPayload(endpoint, header->payload_size) < 0)
return -1;
reply.result.status = PHI_STATUS_BAD_MESSAGE;
return SendReply(endpoint, header, &reply, sizeof(reply));
}
if(ReadAll(endpoint, &request, sizeof(request)) < 0)
return -1;
if(request.remote_handle == 0)
{
reply.result.status = PHI_STATUS_INVALID_HANDLE;
}
else
{
free((void*)(uintptr_t)request.remote_handle);
}
return SendReply(endpoint, header, &reply, sizeof(reply));
}
+9
View File
@@ -0,0 +1,9 @@
#ifndef APE_PHI_MEMORY_H
#define APE_PHI_MEMORY_H
#include <Daemon.h>
int HandleAllocMemory(scif_epd_t endpoint, const PhiMessageHeader* header);
int HandleFreeMemory(scif_epd_t endpoint, const PhiMessageHeader* header);
#endif
+32
View File
@@ -0,0 +1,32 @@
#include <Daemon.h>
#include <Logger.h>
int main(void)
{
scif_epd_t endpoint = StartDaemon();
if(endpoint == 0)
return 1;
for(;;)
{
struct scif_portID peer;
scif_epd_t client;
if(scif_accept(endpoint, &peer, &client, SCIF_ACCEPT_SYNC) < 0)
{
if(errno == EINTR)
continue;
PhiLogError("Could not accept SCIF connection");
break;
}
(void)HandlePacket(client);
scif_close(client);
}
ShutdownDaemon(endpoint);
return 0;
}
+77
View File
@@ -0,0 +1,77 @@
const std = @import("std");
const base = @import("base");
const VkError = base.VkError;
pub const epd_t = c_int;
pub const PortId = extern struct {
node: u16,
port: u16,
};
pub const SEND_BLOCK = 1;
pub const RECV_BLOCK = 1;
var scif_open: *const fn () callconv(.c) epd_t = undefined;
var scif_close: *const fn (epd: epd_t) callconv(.c) c_int = undefined;
var scif_connect: *const fn (epd: epd_t, dst: *const PortId) callconv(.c) c_int = undefined;
var scif_send: *const fn (epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
var scif_recv: *const fn (epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) callconv(.c) isize = undefined;
var module: std.DynLib = undefined;
var ref_count = std.atomic.Value(usize).init(0);
var load_mutex: base.SpinMutex = .{};
pub fn load() VkError!void {
load_mutex.lock();
defer load_mutex.unlock();
if (ref_count.load(.monotonic) != 0) {
_ = ref_count.fetchAdd(1, .monotonic);
return;
}
module = std.DynLib.open("libscif.so") catch {
std.log.scoped(.SCIF).err("Could not open libscif.so", .{});
return VkError.InitializationFailed;
};
errdefer module.close();
scif_open = module.lookup(@TypeOf(scif_open), "scif_open") orelse return VkError.InitializationFailed;
scif_close = module.lookup(@TypeOf(scif_close), "scif_close") orelse return VkError.InitializationFailed;
scif_connect = module.lookup(@TypeOf(scif_connect), "scif_connect") orelse return VkError.InitializationFailed;
scif_send = module.lookup(@TypeOf(scif_send), "scif_send") orelse return VkError.InitializationFailed;
scif_recv = module.lookup(@TypeOf(scif_recv), "scif_recv") orelse return VkError.InitializationFailed;
_ = ref_count.fetchAdd(1, .monotonic);
}
pub fn unload() void {
load_mutex.lock();
defer load_mutex.unlock();
if (ref_count.fetchSub(1, .release) == 1) {
module.close();
}
}
pub inline fn open() epd_t {
return scif_open();
}
pub inline fn close(epd: epd_t) c_int {
return scif_close(epd);
}
pub inline fn connect(epd: epd_t, dst: *const PortId) c_int {
return scif_connect(epd, dst);
}
pub inline fn send(epd: epd_t, msg: ?*const anyopaque, len: usize, flags: c_int) isize {
return scif_send(epd, msg, len, flags);
}
pub inline fn recv(epd: epd_t, msg: ?*anyopaque, len: usize, flags: c_int) isize {
return scif_recv(epd, msg, len, flags);
}
+84
View File
@@ -0,0 +1,84 @@
#ifndef APE_PHI_PROTOCOL_H
#define APE_PHI_PROTOCOL_H
#include <stdint.h>
#define PHI_PROTOCOL_MAGIC 0x50484941u
#define PHI_PROTOCOL_VERSION 1u
#define PHI_RPOTOCOL_VERSION PHI_PROTOCOL_VERSION
#define PHI_SCIF_PORT 43616u
typedef enum PhiCommandType
{
PHI_COMMAND_HELLO = 1,
PHI_COMMAND_ALLOC_MEMORY = 2,
PHI_COMMAND_FREE_MEMORY = 3,
PHI_COMMAND_UPLOAD = 4,
PHI_COMMAND_DOWNLOAD = 5,
PHI_COMMAND_SUBMIT = 6,
PHI_COMMAND_SHUTDOWN = 7,
} PhiCommandType;
typedef enum PhiStatus
{
PHI_STATUS_OK = 0,
PHI_STATUS_BAD_MESSAGE = 1,
PHI_STATUS_UNSUPPORTED_VERSION = 2,
PHI_STATUS_UNSUPPORTED_COMMAND = 3,
PHI_STATUS_OUT_OF_MEMORY = 4,
PHI_STATUS_INVALID_HANDLE = 5,
} PhiStatus;
typedef struct PhiMessageHeader
{
uint32_t magic;
uint16_t version;
uint16_t type;
uint64_t sequence;
uint64_t payload_size;
} PhiMessageHeader;
typedef struct PhiResult
{
int32_t status;
uint32_t reserved;
} PhiResult;
typedef struct PhiHelloRequest
{
uint32_t host_protocol_version;
uint32_t reserved;
} PhiHelloRequest;
typedef struct PhiHelloReply
{
PhiResult result;
uint32_t device_protocol_version;
uint32_t pointer_bits;
} PhiHelloReply;
typedef struct PhiAllocMemoryRequest
{
uint64_t size;
uint32_t memory_type_index;
uint32_t flags;
} PhiAllocMemoryRequest;
typedef struct PhiAllocMemoryReply
{
PhiResult result;
uint64_t remote_handle;
uint64_t size;
} PhiAllocMemoryReply;
typedef struct PhiFreeMemoryRequest
{
uint64_t remote_handle;
} PhiFreeMemoryRequest;
typedef struct PhiFreeMemoryReply
{
PhiResult result;
} PhiFreeMemoryReply;
#endif