20 #if defined(_WIN32) && !defined(__MINGW32__)
24 #define isatty _isatty
25 #define STDIN_FILENO _fileno(stdin)
33 #include <readline/history.h>
34 #include <readline/readline.h>
37 #include <spirv/unified1/spirv.h>
58 #define CONTEXT_SIZE 3
64 static thread_local
bool IsWorkerThread =
false;
65 static thread_local Workgroup *CurrentGroup;
66 static thread_local Invocation *CurrentInvocation;
110 : Dev(Dev), CurrentCommand(nullptr), CurrentStage(nullptr)
120 std::thread::hardware_concurrency());
145 for (uint32_t LZ = 0; LZ < GroupSize.
Z; LZ++)
147 for (uint32_t LY = 0; LY < GroupSize.
Y; LY++)
149 for (uint32_t LX = 0; LX < GroupSize.
X; LX++)
151 Dim3 LocalId(LX, LY, LZ);
152 Dim3 GlobalId = LocalId + GroupId * GroupSize;
153 uint32_t LocalIndex = LX + (LY + (LZ * GroupSize.Y)) * GroupSize.
X;
154 std::vector<Object> InitialObjects =
Objects;
157 std::shared_ptr<Memory> PipelineMemory =
161 const Type *Ty = Var->getType();
166 uint64_t Address = PipelineMemory->allocate(Sz);
167 switch (Var->getDecoration(SpvDecorationBuiltIn))
169 case SpvBuiltInGlobalInvocationId:
170 PipelineMemory->store(Address, Sz, (uint8_t *)GlobalId.
Data);
172 case SpvBuiltInLocalInvocationId:
173 PipelineMemory->store(Address, Sz, (uint8_t *)LocalId.
Data);
175 case SpvBuiltInLocalInvocationIndex:
176 PipelineMemory->store(Address, Sz, (uint8_t *)&LocalIndex);
178 case SpvBuiltInNumWorkgroups:
179 PipelineMemory->store(Address, Sz,
182 case SpvBuiltInWorkgroupId:
183 PipelineMemory->store(Address, Sz, (uint8_t *)GroupId.
Data);
186 std::cerr <<
"Unimplemented input variable builtin: "
187 << Var->getDecoration(SpvDecorationBuiltIn) << std::endl;
192 InitialObjects[Var->getId()] =
Object(Ty, Address);
197 std::make_unique<Invocation>(Dev, *
CurrentStage, InitialObjects,
198 PipelineMemory, Group, GlobalId));
208 return CurrentInvocation;
225 assert(PL !=
nullptr);
230 uint64_t PushConstantAddress =
250 {BaseGroup.
X + GX, BaseGroup.
Y + GY, BaseGroup.
Z + GZ});
254 doWork([&]() { runComputeWorker(); });
256 finalizeVariables(PC.getComputeDescriptors());
257 GlobalMem.release(PushConstantAddress);
259 PendingGroups.clear();
260 CurrentCommand =
nullptr;
265 assert(CurrentCommand ==
nullptr);
266 CurrentCommand = &Cmd;
272 assert(PL !=
nullptr);
280 Memory &GlobalMem = Dev.getGlobalMemory();
281 uint64_t PushConstantAddress =
282 GlobalMem.
allocate(PipelineContext::PUSH_CONSTANT_MEM_SIZE);
283 GlobalMem.
store(PushConstantAddress, PipelineContext::PUSH_CONSTANT_MEM_SIZE,
291 for (uint32_t Instance = 0; Instance < Cmd.
getNumInstances(); Instance++)
302 doWork([&]() { runVertexWorker(&State, InstanceIndex); });
312 assert(CurrentStage &&
"rendering without fragment shader not implemented");
313 Objects = CurrentStage->getObjects();
320 case VK_PRIMITIVE_TOPOLOGY_POINT_LIST:
326 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST:
334 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP:
342 rasterizeTriangle(Cmd, Viewport, A, B, C);
348 rasterizeTriangle(Cmd, Viewport, B, D, C);
352 case VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN:
359 rasterizeTriangle(Cmd, Viewport, A, B, Center);
364 std::cerr <<
"Unimplemented primitive topology: " << Topology
372 GlobalMem.
release(PushConstantAddress);
374 CurrentStage =
nullptr;
375 CurrentCommand =
nullptr;
378 void PipelineExecutor::runComputeWorker()
380 IsWorkerThread =
true;
381 CurrentInvocation =
nullptr;
390 if (!RunningGroups.empty())
392 assert(NumThreads == 1);
393 CurrentGroup = RunningGroups.back();
394 RunningGroups.pop_back();
396 else if (NextWorkIndex < PendingGroups.size())
398 size_t GroupIndex = NextWorkIndex++;
399 if (GroupIndex >= PendingGroups.size())
401 CurrentGroup = createWorkgroup(PendingGroups[GroupIndex]);
402 Dev.reportWorkgroupBegin(CurrentGroup);
422 std::find_if(WorkItems.begin(), WorkItems.end(), [](
const auto &I) {
423 return I->getState() == Invocation::READY;
425 if (I == WorkItems.end())
427 CurrentInvocation = I->get();
430 while (CurrentInvocation->
getState() == Invocation::READY)
432 CurrentInvocation->
step();
435 CurrentInvocation =
nullptr;
441 size_t BarrierCount =
442 std::count_if(WorkItems.begin(), WorkItems.end(), [](
const auto &I) {
443 return I->getState() == Invocation::BARRIER;
445 if (BarrierCount > 0)
450 if (BarrierCount != WorkItems.size())
454 std::cerr <<
"Barrier not reached by every invocation." << std::endl;
459 for (
auto &WI : WorkItems)
461 Dev.reportWorkgroupBarrier(CurrentGroup);
466 Dev.reportWorkgroupComplete(CurrentGroup);
468 CurrentGroup =
nullptr;
476 int XMinFB,
int XMaxFB,
int YMinFB,
484 XMinFB = std::clamp(XMinFB, 0, (
int)(FB.
getWidth() - 1));
485 XMaxFB = std::clamp(XMaxFB, 0, (
int)(FB.
getWidth() - 1));
486 YMinFB = std::clamp(YMinFB, 0, (
int)(FB.
getHeight() - 1));
487 YMaxFB = std::clamp(YMaxFB, 0, (
int)(FB.
getHeight() - 1));
493 XMinFB = std::max<int>(XMinFB, Scissor.offset.x);
494 XMaxFB = std::min<int>(XMaxFB, Scissor.offset.x + Scissor.extent.width - 1);
495 YMinFB = std::max<int>(YMinFB, Scissor.offset.y);
496 YMaxFB = std::min<int>(YMaxFB, Scissor.offset.y + Scissor.extent.height - 1);
499 assert(PendingFragments.empty());
500 for (
int YFB = YMinFB; YFB <= YMaxFB; YFB++)
501 for (
int XFB = XMinFB; XFB <= XMaxFB; XFB++)
502 PendingFragments.push_back({(uint32_t)XFB, (uint32_t)YFB, 0});
519 float BW,
float CW,
float InvW,
float a,
float b,
float c,
520 bool Flat,
bool Perspective)
535 float A = *(
float *)(FA.
getData() + Offset);
536 float B = *(
float *)(FB.
getData() + Offset);
537 float C = *(
float *)(FC.
getData() + Offset);
540 F = ((a * A / AW) + (b * B / BW) + (c * C / CW)) / InvW;
542 F = (a * A) + (b * B) + (c * C);
544 *(
float *)(Output.
getData() + Offset) = F;
552 bool FlatElement = Flat;
553 bool PerspectiveElement = Perspective;
559 PerspectiveElement =
false;
563 FA, FB, FC, AW, BW, CW, InvW, a, b, c, FlatElement,
570 return ((Viewport.width / 2.f) * Xd) + (Viewport.x + Viewport.width / 2.f);
575 return ((Xfb + 0.5f) - (Viewport.x + Viewport.width / 2.f)) /
576 (Viewport.width / 2.f);
581 return ((Viewport.height / 2.f) * Yd) + (Viewport.y + Viewport.height / 2.f);
586 return ((Yfb + 0.5f) - (Viewport.y + Viewport.height / 2.f)) /
587 (Viewport.height / 2.f);
592 const VkPipelineColorBlendAttachmentState &Blend,
593 const std::array<float, 4> &BlendConstants)
599 auto GetColorBlendFactor = [BlendConstants, Src, Dst](VkBlendFactor Factor,
604 case VK_BLEND_FACTOR_ZERO:
607 case VK_BLEND_FACTOR_ONE:
610 case VK_BLEND_FACTOR_SRC_COLOR:
611 R = Src.
get<
float>(0);
612 G = Src.get<
float>(1);
613 B = Src.get<
float>(2);
615 case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
616 R = 1.f - Src.get<
float>(0);
617 G = 1.f - Src.get<
float>(1);
618 B = 1.f - Src.get<
float>(2);
620 case VK_BLEND_FACTOR_DST_COLOR:
621 R = Dst.
get<
float>(0);
622 G = Dst.
get<
float>(1);
623 B = Dst.
get<
float>(2);
625 case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
626 R = 1.f - Dst.
get<
float>(0);
627 G = 1.f - Dst.
get<
float>(1);
628 B = 1.f - Dst.
get<
float>(2);
630 case VK_BLEND_FACTOR_SRC_ALPHA:
631 R = G = B = Src.get<
float>(3);
633 case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
634 R = G = B = 1.f - Src.get<
float>(3);
636 case VK_BLEND_FACTOR_DST_ALPHA:
637 R = G = B = Dst.
get<
float>(3);
639 case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
640 R = G = B = 1.f - Dst.
get<
float>(3);
642 case VK_BLEND_FACTOR_CONSTANT_COLOR:
643 R = BlendConstants[0];
644 G = BlendConstants[1];
645 B = BlendConstants[2];
647 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
648 R = 1.f - BlendConstants[0];
649 G = 1.f - BlendConstants[1];
650 B = 1.f - BlendConstants[2];
652 case VK_BLEND_FACTOR_CONSTANT_ALPHA:
653 R = G = B = BlendConstants[3];
655 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
656 R = G = B = 1.f - BlendConstants[3];
658 case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
659 R = G = B = std::min(Src.get<
float>(3), 1.f - Dst.
get<
float>(3));
662 std::cerr <<
"Unhandled color blend factor: " << Factor << std::endl;
670 GetColorBlendFactor(Blend.srcColorBlendFactor, Sr, Sg, Sb);
671 GetColorBlendFactor(Blend.dstColorBlendFactor, Dr, Dg, Db);
672 switch (Blend.colorBlendOp)
674 case VK_BLEND_OP_ADD:
675 NewTexel.
set(0, Src.get<
float>(0) * Sr + Dst.
get<
float>(0) * Dr);
676 NewTexel.
set(1, Src.get<
float>(1) * Sg + Dst.
get<
float>(1) * Dg);
677 NewTexel.
set(2, Src.get<
float>(2) * Sb + Dst.
get<
float>(2) * Db);
679 case VK_BLEND_OP_SUBTRACT:
680 NewTexel.
set(0, Src.get<
float>(0) * Sr - Dst.
get<
float>(0) * Dr);
681 NewTexel.
set(1, Src.get<
float>(1) * Sg - Dst.
get<
float>(1) * Dg);
682 NewTexel.
set(2, Src.get<
float>(2) * Sb - Dst.
get<
float>(2) * Db);
684 case VK_BLEND_OP_REVERSE_SUBTRACT:
685 NewTexel.
set(0, Dst.
get<
float>(0) * Dr - Src.get<
float>(0) * Sr);
686 NewTexel.
set(1, Dst.
get<
float>(1) * Dg - Src.get<
float>(1) * Sg);
687 NewTexel.
set(2, Dst.
get<
float>(2) * Db - Src.get<
float>(2) * Sb);
689 case VK_BLEND_OP_MIN:
690 NewTexel.
set(0, std::min(Src.get<
float>(0), Dst.
get<
float>(0)));
691 NewTexel.
set(1, std::min(Src.get<
float>(1), Dst.
get<
float>(1)));
692 NewTexel.
set(2, std::min(Src.get<
float>(2), Dst.
get<
float>(2)));
694 case VK_BLEND_OP_MAX:
695 NewTexel.
set(0, std::max(Src.get<
float>(0), Dst.
get<
float>(0)));
696 NewTexel.
set(1, std::max(Src.get<
float>(1), Dst.
get<
float>(1)));
697 NewTexel.
set(2, std::max(Src.get<
float>(2), Dst.
get<
float>(2)));
700 std::cerr <<
"Unhandled color blend operation: " << Blend.colorBlendOp
706 auto GetAlphaBlendFactor = [BlendConstants, Src, Dst](VkBlendFactor Factor,
710 case VK_BLEND_FACTOR_ZERO:
713 case VK_BLEND_FACTOR_ONE:
714 case VK_BLEND_FACTOR_SRC_ALPHA_SATURATE:
717 case VK_BLEND_FACTOR_SRC_COLOR:
718 case VK_BLEND_FACTOR_SRC_ALPHA:
719 A = Src.get<
float>(3);
721 case VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR:
722 case VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA:
723 A = 1.f - Src.get<
float>(3);
725 case VK_BLEND_FACTOR_DST_COLOR:
726 case VK_BLEND_FACTOR_DST_ALPHA:
727 A = Dst.
get<
float>(3);
729 case VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR:
730 case VK_BLEND_FACTOR_ONE_MINUS_DST_ALPHA:
731 A = 1.f - Dst.
get<
float>(3);
733 case VK_BLEND_FACTOR_CONSTANT_COLOR:
734 case VK_BLEND_FACTOR_CONSTANT_ALPHA:
735 A = BlendConstants[3];
737 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR:
738 case VK_BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA:
739 A = 1.f - BlendConstants[3];
742 std::cerr <<
"Unhandled alpha blend factor: " << Factor << std::endl;
750 GetAlphaBlendFactor(Blend.srcAlphaBlendFactor, Sa);
751 GetAlphaBlendFactor(Blend.dstAlphaBlendFactor, Da);
752 switch (Blend.alphaBlendOp)
754 case VK_BLEND_OP_ADD:
755 NewTexel.
set(3, Src.get<
float>(3) * Sa + Dst.
get<
float>(3) * Da);
757 case VK_BLEND_OP_SUBTRACT:
758 NewTexel.
set(3, Src.get<
float>(3) * Sa - Dst.
get<
float>(3) * Da);
760 case VK_BLEND_OP_REVERSE_SUBTRACT:
761 NewTexel.
set(3, Dst.
get<
float>(3) * Da - Src.get<
float>(3) * Sa);
763 case VK_BLEND_OP_MIN:
764 NewTexel.
set(3, std::min(Src.get<
float>(3), Dst.
get<
float>(3)));
766 case VK_BLEND_OP_MAX:
767 NewTexel.
set(3, std::max(Src.get<
float>(3), Dst.
get<
float>(3)));
770 std::cerr <<
"Unhandled alpha blend operation: " << Blend.alphaBlendOp
776 void PipelineExecutor::processFragment(
778 std::function<
void(uint32_t, uint32_t,
const Variable *,
const Type *,
788 struct FragmentOutput
796 std::vector<Object> InitialObjects = Objects;
797 std::shared_ptr<Memory> PipelineMemory =
798 std::make_shared<Memory>(Dev, MemoryScope::Invocation);
799 std::map<const Variable *, FragmentOutput> Outputs;
800 for (
auto Var : CurrentStage->getEntryPoint()->getVariables())
802 const Type *PtrTy = Var->getType();
807 uint64_t Address = PipelineMemory->allocate(VarTy->
getSize());
808 InitialObjects[Var->getId()] =
Object(PtrTy, Address);
811 if (Var->hasDecoration(SpvDecorationLocation))
813 uint32_t Location = Var->getDecoration(SpvDecorationLocation);
814 uint32_t Component = 0;
815 if (Var->hasDecoration(SpvDecorationComponent))
816 Component = Var->getDecoration(SpvDecorationComponent);
817 GenLocData(Location, Component, Var, VarTy, &*PipelineMemory, Address);
819 else if (Var->hasDecoration(SpvDecorationBuiltIn))
821 switch (Var->getDecoration(SpvDecorationBuiltIn))
823 case SpvBuiltInFragCoord:
827 float FragCoord[4] = {Frag.
X + 0.5f, Frag.
Y + 0.5f, Frag.
Depth,
829 PipelineMemory->store(Address, 16, (
const uint8_t *)FragCoord);
833 assert(
false &&
"Unhandled fragment input builtin");
838 assert(
false &&
"Unhandled input variable type");
844 uint64_t Address = PipelineMemory->allocate(VarTy->
getSize());
845 InitialObjects[Var->getId()] =
Object(PtrTy, Address);
848 assert(Var->hasDecoration(SpvDecorationLocation));
849 uint32_t Location = Var->getDecoration(SpvDecorationLocation);
850 uint32_t Component = 0;
851 if (Var->hasDecoration(SpvDecorationComponent))
852 Component = Var->getDecoration(SpvDecorationComponent);
853 Outputs[Var] = {Address, Location, Component};
858 CurrentInvocation =
new Invocation(Dev, *CurrentStage, InitialObjects,
859 PipelineMemory,
nullptr,
Dim3(0, 0, 0));
863 while (CurrentInvocation->
getState() == Invocation::READY)
865 CurrentInvocation->
step();
871 delete CurrentInvocation;
872 CurrentInvocation =
nullptr;
878 std::vector<uint32_t> ColorAttachments =
880 std::map<uint32_t, Image::Texel> OutTexels;
881 for (
auto Output : Outputs)
883 uint32_t Location = Output.second.Location;
884 assert(Location < ColorAttachments.size());
887 const Object &OutputData =
888 Object::load(Output.first->getType()->getElementType(), *PipelineMemory,
889 Output.second.Address);
892 assert(OutputData.getType()->isScalar() ||
893 OutputData.getType()->isVector());
894 assert(OutputData.getType()->getScalarType()->getSize() == 4);
896 if (OutTexels.count(Location))
897 T = OutTexels.at(Location);
898 for (uint32_t i = 0; i < OutputData.getType()->getElementCount(); i++)
899 T.set(Output.second.Component + i, OutputData.get<uint32_t>(i));
900 OutTexels[Location] = T;
905 assert(BlendAttachmentStates.size() == ColorAttachments.size());
908 for (
auto OT : OutTexels)
910 uint32_t Ref = ColorAttachments[OT.first];
919 Attach->read(OldTexel, Frag.
X, Frag.
Y);
923 OldTexel.
set(3, 1.f);
926 const VkPipelineColorBlendAttachmentState &Blend =
927 BlendAttachmentStates[OT.first];
928 if (Blend.blendEnable == VK_TRUE)
937 if (!(Blend.colorWriteMask & VK_COLOR_COMPONENT_R_BIT))
938 NewTexel.
set(0, OldTexel.
get<uint32_t>(0));
939 if (!(Blend.colorWriteMask & VK_COLOR_COMPONENT_G_BIT))
940 NewTexel.
set(1, OldTexel.
get<uint32_t>(1));
941 if (!(Blend.colorWriteMask & VK_COLOR_COMPONENT_B_BIT))
942 NewTexel.
set(2, OldTexel.
get<uint32_t>(2));
943 if (!(Blend.colorWriteMask & VK_COLOR_COMPONENT_A_BIT))
944 NewTexel.
set(3, OldTexel.
get<uint32_t>(3));
947 Attach->write(NewTexel, Frag.
X, Frag.
Y);
951 void PipelineExecutor::runWorker()
953 uint32_t NextTaskID = 1;
958 std::unique_lock<std::mutex> Lock(WorkerMutex);
963 if (CurrentTaskID == NextTaskID)
965 WorkerSignal.wait(Lock);
974 if (++NumWorkersFinished == NumThreads)
977 MasterSignal.notify_one();
978 WorkerMutex.unlock();
985 void PipelineExecutor::doWork(std::function<
void()> Task)
988 if (WorkerThreads.empty())
990 for (
unsigned i = 0; i < NumThreads; i++)
991 WorkerThreads.push_back(std::thread(&PipelineExecutor::runWorker,
this));
995 NumWorkersFinished = 0;
999 WorkerSignal.notify_all();
1000 WorkerMutex.unlock();
1004 std::unique_lock<std::mutex> Lock(WorkerMutex);
1005 MasterSignal.wait(Lock, [&]() {
return NumWorkersFinished == NumThreads; });
1008 CurrentTask = std::function<void()>();
1014 IsWorkerThread =
true;
1015 CurrentInvocation =
nullptr;
1021 uint32_t WorkIndex = (uint32_t)NextWorkIndex++;
1022 if (WorkIndex >= PendingFragments.size())
1026 Frag.
X = PendingFragments[WorkIndex].X;
1027 Frag.
Y = PendingFragments[WorkIndex].Y;
1032 float S = 0.5f + (Frag.
X + 0.5f - Primitive.
X) / Primitive.
PointSize;
1033 float T = 0.5f + (Frag.
Y + 0.5f - Primitive.
Y) / Primitive.
PointSize;
1036 if (S < 0 || T < 0 || S > 1 || T > 1)
1040 auto GenLocData = [&](uint32_t Location, uint32_t Component,
1044 Mem->store(Address, VarTy->getSize(), Out.
getData());
1047 processFragment(Frag, RPI, GenLocData);
1054 const VkViewport &Viewport)
1056 IsWorkerThread =
true;
1057 CurrentInvocation =
nullptr;
1060 const VkPipelineRasterizationStateCreateInfo &RasterizationState =
1069 auto TriArea2 = [](
const Vec4 &A,
const Vec4 &B,
const Vec4 &C) {
1070 return (C.
X - A.
X) * (B.Y - A.
Y) - (B.X - A.
X) * (C.
Y - A.
Y);
1074 float Area2 = TriArea2(A, B, C);
1078 switch (RasterizationState.frontFace)
1080 case VK_FRONT_FACE_COUNTER_CLOCKWISE:
1081 FrontFacing = Area2 > 0;
1083 case VK_FRONT_FACE_CLOCKWISE:
1084 FrontFacing = Area2 < 0;
1087 std::cerr <<
"Invalid front-facing sign value" << std::endl;
1092 if ((FrontFacing && RasterizationState.cullMode & VK_CULL_MODE_FRONT_BIT) ||
1093 (!FrontFacing && RasterizationState.cullMode & VK_CULL_MODE_BACK_BIT))
1100 uint32_t WorkIndex = (uint32_t)NextWorkIndex++;
1101 if (WorkIndex >= PendingFragments.size())
1105 Frag.
X = PendingFragments[WorkIndex].X;
1106 Frag.
Y = PendingFragments[WorkIndex].Y;
1110 float a = TriArea2(B, C, DevCoord) / Area2;
1111 float b = TriArea2(C, A, DevCoord) / Area2;
1112 float c = TriArea2(A, B, DevCoord) / Area2;
1117 if (fabs(a) < 1.e-7f)
1119 if (fabs(b) < 1.e-7f)
1121 if (fabs(c) < 1.e-7f)
1125 if (!(a >= 0 && b >= 0 && c >= 0))
1129 float BCX = C.
X - B.X;
1130 float BCY = C.
Y - B.Y;
1131 float CAX = A.
X - C.
X;
1132 float CAY = A.
Y - C.
Y;
1133 float ABX = B.X - A.
X;
1134 float ABY = B.Y - A.
Y;
1148 if (!((BCY == 0 && BCX < 0) || BCY > 0))
1153 if (!((CAY == 0 && CAX < 0) || CAY > 0))
1158 if (!((ABY == 0 && ABX < 0) || ABY > 0))
1163 Frag.
Depth = (a * A.
Z) + (b * B.Z) + (c * C.
Z);
1164 Frag.
InvW = (a / A.
W) + (b / B.W) + (c / C.
W);
1167 auto GenLocData = [&](uint32_t Location, uint32_t Component,
1177 interpolate(VarObj, VarTy, 0, FA, FB, FC, A.
W, B.W, C.
W, Frag.
InvW, a, b,
1178 c, Var->hasDecoration(SpvDecorationFlat),
1179 !Var->hasDecoration(SpvDecorationNoPerspective));
1180 VarObj.
store(*Mem, Address);
1183 processFragment(Frag, RPI, GenLocData);
1188 uint32_t InstanceIndex)
1190 IsWorkerThread =
true;
1191 CurrentInvocation =
nullptr;
1199 uint32_t WorkIndex = (uint32_t)NextWorkIndex++;
1204 uint32_t VertexIndex;
1210 case Command::DRAW_INDEXED:
1217 case VK_INDEX_TYPE_UINT16:
1219 uint16_t VertexIndex16;
1220 Dev.getGlobalMemory().load(
1221 (uint8_t *)&VertexIndex16,
1223 VertexIndex = VertexIndex16;
1226 case VK_INDEX_TYPE_UINT32:
1227 Dev.getGlobalMemory().load(
1228 (uint8_t *)&VertexIndex,
1232 assert(
false &&
"Unhandled vertex index type");
1233 VertexIndex = UINT32_MAX;
1240 assert(
false &&
"Unhandled draw type");
1243 std::vector<Object> InitialObjects = Objects;
1246 std::shared_ptr<Memory> PipelineMemory =
1247 std::make_shared<Memory>(Dev, MemoryScope::Invocation);
1248 std::map<const Variable *, uint64_t> OutputAddresses;
1249 for (
auto Var : CurrentStage->getEntryPoint()->getVariables())
1251 const Type *Ty = Var->getType();
1256 size_t ElemSize = ElemTy->
getSize();
1257 uint64_t Address = PipelineMemory->allocate(ElemSize);
1258 InitialObjects[Var->getId()] =
Object(Ty, Address);
1261 if (Var->hasDecoration(SpvDecorationLocation))
1263 uint32_t Location = Var->getDecoration(SpvDecorationLocation);
1264 uint32_t Component = 0;
1265 if (Var->hasDecoration(SpvDecorationComponent))
1266 Component = Var->getDecoration(SpvDecorationComponent);
1270 assert(Component == 0);
1273 size_t ColSize = ColTy->
getSize();
1279 Address + Col * ColSize, VertexIndex,
1280 InstanceIndex, Location + Col, 0, ColTy);
1286 VertexIndex, InstanceIndex, Location, Component,
1290 else if (Var->hasDecoration(SpvDecorationBuiltIn))
1292 switch (Var->getDecoration(SpvDecorationBuiltIn))
1294 case SpvBuiltInInstanceIndex:
1295 PipelineMemory->store(Address, 4, (
const uint8_t *)&InstanceIndex);
1297 case SpvBuiltInVertexIndex:
1298 assert(ElemSize == 4);
1299 PipelineMemory->store(Address, 4, (
const uint8_t *)&VertexIndex);
1302 assert(
false &&
"Unhandled vertex input builtin");
1307 assert(
false &&
"Unhandled input variable type");
1315 InitialObjects[Var->getId()] =
Object(Ty, Address);
1316 OutputAddresses[Var] = Address;
1322 new Invocation(Dev, *CurrentStage, InitialObjects, PipelineMemory,
1323 nullptr,
Dim3(VertexIndex, 0, 0));
1327 while (CurrentInvocation->
getState() == Invocation::READY)
1329 CurrentInvocation->
step();
1333 delete CurrentInvocation;
1334 CurrentInvocation =
nullptr;
1337 for (
auto Var : CurrentStage->getEntryPoint()->getVariables())
1339 if (Var->getType()->getStorageClass() != SpvStorageClassOutput)
1342 uint64_t BaseAddress = OutputAddresses[Var];
1345 if (Var->hasDecoration(SpvDecorationBuiltIn))
1347 SpvBuiltIn BuiltIn =
1348 (SpvBuiltIn)Var->getDecoration(SpvDecorationBuiltIn);
1350 Object::load(Ty, *PipelineMemory, BaseAddress);
1352 else if (Var->hasDecoration(SpvDecorationLocation))
1354 uint32_t Location = Var->getDecoration(SpvDecorationLocation);
1355 uint32_t Component = 0;
1356 if (Var->hasDecoration(SpvDecorationComponent))
1357 Component = Var->getDecoration(SpvDecorationComponent);
1358 State->
VertexOutputs[WorkIndex].Locations[{Location, Component}] =
1359 Object::load(Ty, *PipelineMemory, BaseAddress);
1361 else if (Ty->
getTypeId() == Type::STRUCT &&
1369 SpvDecorationBuiltIn);
1376 assert(
false &&
"Unhandled output variable type");
1385 for (
auto V : CurrentStage->getModule()->getVariables())
1388 if (!V->isBufferVariable())
1390 if (V->getType()->getElementType()->getTypeId() != Type::ARRAY)
1393 assert(V->getType()->getElementType()->getTypeId() == Type::ARRAY);
1397 uint32_t Set = V->getDecoration(SpvDecorationDescriptorSet);
1398 uint32_t Binding = V->getDecoration(SpvDecorationBinding);
1399 assert(DSM.count(Set));
1401 uint64_t Address = Objects[V->getId()].get<uint64_t>();
1403 Objects[V->getId()].getDescriptorElements();
1404 assert(DescriptorElements);
1407 for (uint32_t i = 0; i < ArrayTy->getElementCount(); i++)
1409 if (!DSM.at(Set).count({Binding, i}))
1412 Memory::copy(DSM.at(Set).at({Binding, i}).Address, Dev.getGlobalMemory(),
1413 DescriptorElements[i].Address, Dev.getGlobalMemory(),
1414 DescriptorElements[i].NumBytes);
1418 Dev.getGlobalMemory().release(Address);
1419 delete[] DescriptorElements;
1424 uint64_t PushConstantAddress)
1426 for (
auto V : CurrentStage->getModule()->getVariables())
1429 if (V->getType()->getStorageClass() == SpvStorageClassPushConstant)
1431 Objects[V->getId()] =
Object(V->getType(), PushConstantAddress);
1435 if (!V->isBufferVariable())
1439 uint32_t Set = V->getDecoration(SpvDecorationDescriptorSet);
1440 uint32_t Binding = V->getDecoration(SpvDecorationBinding);
1441 if (!DSM.count(Set))
1444 if (V->getType()->getElementType()->getTypeId() == Type::ARRAY)
1453 uint64_t NumBytes = 0;
1456 if (!DSM.at(Set).count({Binding, i}))
1458 DescriptorElements[i] = {0, 0};
1462 size_t ElemSize = DSM.at(Set).at({Binding, i}).NumBytes;
1463 DescriptorElements[i] = {NumBytes, ElemSize};
1464 NumBytes += (uint64_t)ElemSize;
1468 uint64_t Address = Dev.getGlobalMemory().allocate(NumBytes);
1469 Objects[V->getId()] =
Object(V->getType(), Address);
1475 if (!DSM.at(Set).count({Binding, i}))
1479 DescriptorElements[i].
Address = Address + DescriptorElements[i].
Address;
1482 Memory::copy(DescriptorElements[i].Address, Dev.getGlobalMemory(),
1483 DSM.at(Set).at({Binding, i}).Address,
1484 Dev.getGlobalMemory(), DescriptorElements[i].
NumBytes);
1489 if (!DSM.at(Set).count({Binding, 0}))
1492 Objects[V->getId()] =
1493 Object(V->getType(), DSM.at(Set).at({Binding, 0}).Address);
1499 const VkViewport &Viewport,
1505 Vec4 Position = getPosition(Vertex);
1508 float PointSize = 0.1f;
1509 if (Vertex.
BuiltIns.count(SpvBuiltInPointSize))
1510 PointSize = Vertex.
BuiltIns.at(SpvBuiltInPointSize).get<
float>();
1513 float X =
XDevToFB(Position.
X, Viewport);
1514 float Y =
YDevToFB(Position.
Y, Viewport);
1517 int XMinFB = (int)std::floor(X - (PointSize / 2));
1518 int XMaxFB = (int)std::ceil(X + (PointSize / 2));
1519 int YMinFB = (int)std::floor(Y - (PointSize / 2));
1520 int YMaxFB = (int)std::ceil(Y + (PointSize / 2));
1522 buildPendingFragments(Cmd, XMinFB, XMaxFB, YMinFB, YMaxFB);
1527 doWork([&]() { runPointFragmentWorker(Primitive, RPI); });
1529 PendingFragments.clear();
1533 const VkViewport &Viewport,
1541 Vec4 A = getPosition(VA);
1542 Vec4 B = getPosition(VB);
1543 Vec4 C = getPosition(VC);
1557 float XMinDev = std::fmin(A.
X, std::fmin(B.
X, C.
X));
1558 float YMinDev = std::fmin(A.
Y, std::fmin(B.
Y, C.
Y));
1559 float XMaxDev = std::fmax(A.
X, std::fmax(B.
X, C.
X));
1560 float YMaxDev = std::fmax(A.
Y, std::fmax(B.
Y, C.
Y));
1561 int XMinFB = (int)std::floor(
XDevToFB(XMinDev, Viewport));
1562 int XMaxFB = (int)std::ceil(
XDevToFB(XMaxDev, Viewport));
1563 int YMinFB = (int)std::floor(
YDevToFB(YMinDev, Viewport));
1564 int YMaxFB = (int)std::ceil(
YDevToFB(YMaxDev, Viewport));
1566 buildPendingFragments(Cmd, XMinFB, XMaxFB, YMinFB, YMaxFB);
1576 PendingFragments.clear();
1579 void PipelineExecutor::signalError()
1581 if (!IsWorkerThread)
1592 assert(Out.
BuiltIns.count(SpvBuiltInPosition));
1594 assert(PosObj.getType()->isVector() &&
1595 PosObj.getType()->getElementType()->isFloat() &&
1596 PosObj.getType()->getElementType()->getBitWidth() == 32 &&
1597 "Position built-in type must be float4");
1598 memcpy(&Pos, PosObj.getData(),
sizeof(
Vec4));
1603 template <
typename T>
1610 for (uint32_t i = 0; i < (
getElementSize(Format) /
sizeof(T)); i++)
1611 Obj.
set<
float>(Data[i] / (
float)std::numeric_limits<T>::max(), i);
1615 Memory *PipelineMemory, uint64_t Address,
1616 uint32_t VertexIndex,
1617 uint32_t InstanceIndex,
1618 uint32_t Location, uint32_t Component,
1619 const Type *ElemTy)
const
1622 assert(Pipeline !=
nullptr);
1627 std::find_if(Attributes.begin(), Attributes.end(),
1628 [Location](
auto Elem) {
return Elem.location == Location; });
1629 assert(Attr != Attributes.end() &&
"invalid attribute location");
1634 std::find_if(Bindings.begin(), Bindings.end(),
1635 [Attr](
auto Elem) {
return Elem.binding == Attr->binding; });
1636 assert(Binding != Bindings.end() &&
"invalid binding number");
1640 switch (Binding->inputRate)
1642 case VK_VERTEX_INPUT_RATE_VERTEX:
1643 ElemAddr += VertexIndex * Binding->stride;
1645 case VK_VERTEX_INPUT_RATE_INSTANCE:
1646 ElemAddr += InstanceIndex * Binding->stride;
1649 assert(
false &&
"Unhandled vertex input rate");
1651 ElemAddr += Attr->offset;
1671 Result.
set<
float>(1.f, 3);
1673 Result.
set<
double>(1.0, 3);
1675 Result.
set<uint16_t>(1, 3);
1677 Result.
set<uint32_t>(1, 3);
1679 Result.
set<uint64_t>(1, 3);
1681 assert(
false &&
"Unhandled vertex input variable type");
1684 switch (Attr->format)
1686 case VK_FORMAT_R32_SINT:
1687 case VK_FORMAT_R32G32_SINT:
1688 case VK_FORMAT_R32G32B32_SINT:
1689 case VK_FORMAT_R32G32B32A32_SINT:
1690 case VK_FORMAT_R32_UINT:
1691 case VK_FORMAT_R32G32_UINT:
1692 case VK_FORMAT_R32G32B32_UINT:
1693 case VK_FORMAT_R32G32B32A32_UINT:
1694 case VK_FORMAT_R32_SFLOAT:
1695 case VK_FORMAT_R32G32_SFLOAT:
1696 case VK_FORMAT_R32G32B32_SFLOAT:
1697 case VK_FORMAT_R32G32B32A32_SFLOAT:
1699 Dev.getGlobalMemory().load(
1703 case VK_FORMAT_R8_SNORM:
1704 case VK_FORMAT_R8G8_SNORM:
1705 case VK_FORMAT_R8G8B8_SNORM:
1706 case VK_FORMAT_R8G8B8A8_SNORM:
1707 loadNormalizedVertexInput<int8_t>(Result, Attr->format,
1708 Dev.getGlobalMemory(), ElemAddr);
1710 case VK_FORMAT_R16_SNORM:
1711 case VK_FORMAT_R16G16_SNORM:
1712 case VK_FORMAT_R16G16B16_SNORM:
1713 case VK_FORMAT_R16G16B16A16_SNORM:
1714 loadNormalizedVertexInput<int16_t>(Result, Attr->format,
1715 Dev.getGlobalMemory(), ElemAddr);
1717 case VK_FORMAT_R8_UNORM:
1718 case VK_FORMAT_R8G8_UNORM:
1719 case VK_FORMAT_R8G8B8_UNORM:
1720 case VK_FORMAT_R8G8B8A8_UNORM:
1721 loadNormalizedVertexInput<uint8_t>(Result, Attr->format,
1722 Dev.getGlobalMemory(), ElemAddr);
1724 case VK_FORMAT_R16_UNORM:
1725 case VK_FORMAT_R16G16_UNORM:
1726 case VK_FORMAT_R16G16B16_UNORM:
1727 case VK_FORMAT_R16G16B16A16_UNORM:
1728 loadNormalizedVertexInput<uint16_t>(Result, Attr->format,
1729 Dev.getGlobalMemory(), ElemAddr);
1732 std::cerr <<
"Unhandled vertex input format" << std::endl;
1737 Result.
store(*PipelineMemory, Address);
1742 void PipelineExecutor::interact()
1750 CurrentInvocation->
getState() != Invocation::BARRIER)
1753 auto BP = std::find_if(
1754 Breakpoints.begin(), Breakpoints.end(),
1755 [ResultId](
const auto &BP) {
return BP.second == ResultId; });
1756 if (BP != Breakpoints.end())
1758 std::cout <<
"Breakpoint " << BP->first <<
" hit by invocation "
1771 bool IsTTY = isatty(STDIN_FILENO) == 1;
1780 char *CLine = readline(
"(talvos) ");
1793 std::cout <<
"(talvos) " << std::flush;
1794 getline(std::cin, Line);
1795 eof = std::cin.eof();
1802 std::cout <<
"(quit)" << std::endl;
1808 std::istringstream ISS(Line);
1809 std::vector<std::string> Tokens{std::istream_iterator<std::string>{ISS},
1810 std::istream_iterator<std::string>{}};
1814 if (!LastLine.size())
1823 add_history(Line.c_str());
1828 #define CMD(LONG, SHORT, FUNC) \
1829 if (Tokens[0] == LONG || Tokens[0] == SHORT) \
1836 CMD(
"break",
"b", brk);
1837 CMD(
"breakpoint",
"bp", breakpoint);
1838 CMD(
"continue",
"c", cont);
1839 CMD(
"help",
"h", help);
1841 CMD(
"quit",
"q", quit);
1842 CMD(
"step",
"s", step);
1843 CMD(
"switch",
"sw", swtch);
1845 std::cerr <<
"Unrecognized command '" << Tokens[0] <<
"'" << std::endl;
1849 void PipelineExecutor::printContext()
const
1851 assert(CurrentInvocation);
1852 if (CurrentInvocation->
getState() == Invocation::FINISHED)
1853 std::cout <<
" <finished>" << std::endl;
1868 for (; i < CONTEXT_SIZE + 1; i++)
1873 if (CurrentInvocation->
getState() == Invocation::BARRIER)
1874 std::cout <<
" <barrier>" << std::endl <<
" ";
1879 I->
print(std::cout);
1880 std::cout << std::endl;
1889 bool PipelineExecutor::brk(
const std::vector<std::string> &Args)
1891 if (Args.size() != 2)
1893 std::cerr <<
"Usage: break %id" << std::endl;
1899 uint32_t Id = (uint32_t)strtoul(Args[1].c_str() + 1, &Next, 10);
1900 if (Args[1][0] !=
'%' || strlen(Next))
1902 std::cerr <<
"Invalid result ID '" << Args[1] <<
"'" << std::endl;
1907 Breakpoints[NextBreakpoint] = Id;
1908 std::cout <<
"Breakpoint " << NextBreakpoint <<
" set for result ID %" << Id
1915 bool PipelineExecutor::breakpoint(
const std::vector<std::string> &Args)
1917 if (Args.size() < 2)
1919 std::cerr <<
"Usage: breakpoint [clear|delete|list]" << std::endl;
1923 if (Args[1] ==
"clear")
1925 Breakpoints.clear();
1926 std::cout <<
"All breakpoints cleared." << std::endl;
1928 else if (Args[1] ==
"delete")
1930 if (Args.size() != 3)
1932 std::cerr <<
"Usage: breakpoint delete ID" << std::endl;
1938 uint32_t Id = (uint32_t)strtoul(Args[2].c_str(), &Next, 10);
1939 if (strlen(Next) || !Breakpoints.count(Id))
1941 std::cerr <<
"Invalid breakpoint ID '" << Args[2] <<
"'" << std::endl;
1945 Breakpoints.erase(Id);
1946 std::cout <<
"Breakpoint " << Id <<
" deleted." << std::endl;
1948 else if (Args[1] ==
"list")
1950 if (Breakpoints.empty())
1951 std::cout <<
"No breakpoints." << std::endl;
1954 for (
auto &BP : Breakpoints)
1955 std::cout <<
"Breakpoint " << BP.first <<
": %" << BP.second
1960 std::cerr <<
"Usage: breakpoint [clear|delete|list]" << std::endl;
1965 bool PipelineExecutor::cont(
const std::vector<std::string> &Args)
1971 bool PipelineExecutor::help(
const std::vector<std::string> &Args)
1973 std::cout <<
"Command list:" << std::endl;
1974 std::cout <<
" break (b)" << std::endl;
1975 std::cout <<
" breakpoint (bp)" << std::endl;
1976 std::cout <<
" continue (c)" << std::endl;
1977 std::cout <<
" help (h)" << std::endl;
1978 std::cout <<
" print (p)" << std::endl;
1979 std::cout <<
" quit (q)" << std::endl;
1980 std::cout <<
" step (s)" << std::endl;
1981 std::cout <<
" switch (sw)" << std::endl;
1990 if (Args.size() != 2)
1992 std::cerr <<
"Usage: print %<id>" << std::endl;
1998 uint32_t Id = (uint32_t)strtoul(Args[1].c_str() + 1, &Next, 10);
1999 if (Args[1][0] !=
'%' || strlen(Next))
2001 std::cerr <<
"Invalid result ID" << std::endl;
2005 std::cout <<
" %" << std::dec << Id <<
" = ";
2008 if (
const Type *Ty = CurrentStage->getModule()->getType(Id))
2010 std::cout << Ty << std::endl;
2015 std::cout << CurrentInvocation->
getObject(Id) << std::endl;
2020 bool PipelineExecutor::quit(
const std::vector<std::string> &Args) { exit(0); }
2022 bool PipelineExecutor::step(
const std::vector<std::string> &Args)
2024 if (CurrentInvocation->
getState() == Invocation::FINISHED)
2026 std::cout <<
"Invocation has finished." << std::endl;
2029 else if (CurrentInvocation->
getState() == Invocation::BARRIER)
2031 std::cout <<
"Invocation is at a barrier." << std::endl;
2038 bool PipelineExecutor::swtch(
const std::vector<std::string> &Args)
2043 std::cerr <<
"switch not implemented for this command." << std::endl;
2048 if (Args.size() < 2 || Args.size() > 4)
2050 std::cerr <<
"Usage: switch X [Y [Z]]" << std::endl;
2056 for (
unsigned i = 1; i < Args.size(); i++)
2059 Id[i - 1] = (uint32_t)strtoul(Args[i].c_str(), &Next, 10);
2062 std::cerr <<
"Invalid global ID '" << Args[i] <<
"'" << std::endl;
2068 Dim3 GroupSize = CurrentStage->getGroupSize();
2070 if (Id.
X >= GroupSize.
X * NumGroups.
X || Id.
Y >= GroupSize.
Y * NumGroups.
Y ||
2071 Id.
Z >= GroupSize.
Z * NumGroups.
Z)
2073 std::cerr <<
"Global ID is out of the bounds of the current dispatch."
2081 std::cerr <<
"Already executing this invocation!" << std::endl;
2086 Dim3 GroupId(Id.
X / GroupSize.
X, Id.
Y / GroupSize.
Y, Id.
Z / GroupSize.
Z);
2091 Group = CurrentGroup;
2096 auto RG = std::find_if(
2097 RunningGroups.begin(), RunningGroups.end(),
2098 [&GroupId](
const Workgroup *G) {
return G->getGroupId() == GroupId; });
2099 if (RG != RunningGroups.end())
2103 RunningGroups.erase(RG);
2109 auto PG = std::find(PendingGroups.begin() + NextWorkIndex,
2110 PendingGroups.end(), GroupId);
2111 if (PG != PendingGroups.end())
2114 Group = createWorkgroup(*PG);
2115 Dev.reportWorkgroupBegin(Group);
2116 PendingGroups.erase(PG);
2122 std::cerr <<
"Workgroup containing invocation has already finished."
2128 if (Group != CurrentGroup)
2130 RunningGroups.push_back(CurrentGroup);
2131 CurrentGroup = Group;
2135 Dim3 LocalId(Id.
X % GroupSize.
X, Id.
Y % GroupSize.
Y, Id.
Z % GroupSize.
Z);
2136 uint32_t LocalIndex =
2137 LocalId.
X + (LocalId.
Y + LocalId.
Z * GroupSize.
Y) * GroupSize.
X;
2138 CurrentInvocation = CurrentGroup->
getWorkItems()[LocalIndex].get();
2140 std::cout <<
"Switched to invocation with global ID " << Id << std::endl;
This class represents a module-scope variable declaration.
uint32_t getSubpassIndex() const
Returns the index of the current subpass.
std::vector< Workgroup * > RunningGroups
Pool of groups that have begun execution and been suspended.
uint32_t Y
Framebuffer y-coordinate.
This file declares the Workgroup class.
const Subpass & getSubpass(uint32_t Index) const
Returns the subpass at index Index.
This file declares the ComputePipeline class.
bool isScalar() const
Returns true if this is a scalar type.
const GraphicsPipeline * getGraphicsPipeline() const
Returns the graphics pipeline.
const PipelineStage * CurrentStage
The pipeline stage currently being executed.
unsigned long getEnvUInt(const char *Name, unsigned Default)
Returns the integer value for the environment variable Name, or Default if it is not set...
This file declares the Device class.
bool isFloat() const
Returns true if this is a floating point type.
void setDescriptorElements(const DescriptorElement *DAE)
Set the descriptor array elements for this object.
Dim3 getGroupId() const
Returns the group ID of this workgroup.
#define DISPATCH(Op, Func)
size_t getSize() const
Returns the size of this type in bytes.
const PipelineStage * getStage() const
Returns the pipeline stage.
Only allow Device objects to create PipelineExecutor instances.
void run(const DispatchCommand &Cmd)
Run a compute dispatch command to completion.
State getState() const
Returns the state of this invocation.
bool isWorkerThread() const
Returns true if the calling thread is a PipelineExecutor worker thread.
std::map< SpvBuiltIn, Object > BuiltIns
BuiltIn variables.
void step()
Step this invocation by executing the next instruction.
void release(uint64_t Address)
Release the allocation with base address Address.
uint32_t X
Framebuffer x-coordinate.
const Command * CurrentCommand
The command currently being executed.
const VkPipelineRasterizationStateCreateInfo & getRasterizationState() const
Returns the rasterization state used by this pipeline.
This class encapsulates information about an indexed draw command.
float PointSize
The point size.
bool ShutDownWorkers
Signal to shut down worker threads.
bool hasAlphaChannel(VkFormat Format)
Returns true if Format includes an alpha channel.
~PipelineExecutor()
Destroy a pipeline executor.
Type getType() const
Returns the type of this command.
This file declares the Module class.
size_t getElementOffset(uint64_t Index) const
Returns the byte offset of the element at Index.
const Type * getElementType(uint64_t Index=0) const
Returns the type of the element at Index.
const Type * getScalarType() const
Returns the element type for vector types, or this for scalar types.
const DescriptorSetMap & getGraphicsDescriptors() const
Returns the descriptor bindings for draw commands.
bool isInt() const
Returns true if this is an integer type.
const VertexOutput & OutC
The vertex shader outputs for vertex C.
uint32_t getHeight() const
Returns the height of this framebuffer in pixels.
void initializeVariables(const DescriptorSetMap &DSM, uint64_t PushConstantAddress)
Initialize variables.
static std::map< uint32_t, uint32_t > Breakpoints
Map from breakpoint ID to instruction result ID.
float YFBToDev(float Yfb, VkViewport Viewport)
T get(unsigned C) const
Get a component value from the texel.
This class represents a view into a range of image subresources.
bool checkEnv(const char *Name, bool Default)
Returns true if the environment variable Name is set to 1, false for 0, or Default if it is not set...
This file declares the EntryPoint class.
float XFBToDev(float Xfb, VkViewport Viewport)
void set(unsigned C, T Value)
Set a component value in the texel.
uint32_t getElementSize(VkFormat Format)
Returns the size in bytes for each element of an image with type Format.
const Invocation * getCurrentInvocation() const
Returns the current invocation being executed.
uint32_t getIndexOffset() const
Returns the offset of the first index.
This class encapsulates information about a compute kernel launch.
void store(Memory &Mem, uint64_t Address) const
Store the value of this object to memory at Address.
#define CMD(LONG, SHORT, FUNC)
const Framebuffer & getFramebuffer() const
Returns the framebuffer associated with this render pass instance.
const EntryPoint * getEntryPoint() const
Return the entry point this pipeline stage will invoke.
bool isMatrix() const
Returns true if this is a matrix type.
uint32_t getOperand(unsigned i) const
Returns the operand at index i;.
void addWorkItem(std::unique_ptr< Invocation > WorkItem)
Add a work-item invocation to this group, transferring ownership.
Vec4 PosA
The position of vertex A.
uint64_t getIndexBaseAddress() const
Returns the address in memory of the indices.
const RenderPassInstance & getRenderPassInstance() const
Returns the render pass instance used by this command.
const VertexOutput & OutA
The vertex shader outputs for vertex A.
const Workgroup * getCurrentWorkgroup() const
Returns the current workgroup being executed.
void set(T Value, uint32_t Element=0)
Set the value of this object to a scalar of type T.
std::condition_variable WorkerSignal
Condition variable used to wake worker threads.
const std::map< uint32_t, uint32_t > & getStructMemberDecorations(uint32_t Index) const
Returns the decoration map for the structure member at Index.
This class represents an instance of a render pass being used for drawing.
This class encapsulates pipeline state and bound resources.
const BlendAttachmentStateList & getBlendAttachmentStates() const
Returns the list of blend attachment states.
#define CONTEXT_SIZE
The number of lines before and after the current instruction to print.
const ComputePipeline * getComputePipeline() const
Returns the compute pipeline.
Dim3 getNumGroups() const
Returns the number of workgroups this command launches.
const PipelineContext & getPipelineContext() const
Returns the pipeline context.
This class represents a single execution of a SPIR-V entry point.
This class represents a single texel with four 32-bit component values.
uint32_t getElementCount() const
Returns the number of elements in this array, struct, or vector type.
const VertexOutput & OutB
The vertex shader outputs for vertex B.
std::vector< Object > Objects
The initial object values for each invocation.
This file declares miscellaneous utilities used internally by libtalvos.
This file declares the Instruction class.
Triangle primitive data, used for rasterization.
Workgroup * createWorkgroup(Dim3 GroupId) const
Create a compute shader workgroup and its work-item invocations.
This file declares the Type class.
float YDevToFB(float Yd, VkViewport Viewport)
Vec4 PosB
The position of vertex B.
Class representing a 3-dimensional size or ID.
std::map< uint32_t, talvos::DescriptorSet > DescriptorSetMap
Mapping from set numbers to descriptor sets.
std::map< std::pair< uint32_t, uint32_t >, Object > Locations
Location variables (key is {Location, Component}).
This is an abstract base class for draw commands.
const std::vector< VkRect2D > & getScissors() const
Returns the scissor rectangles.
VkIndexType getIndexType() const
Returns the type of the indices.
const VertexOutput & Out
The vertex shader output.
void interpolate(Object &Output, const Type *Ty, size_t Offset, const Object &FA, const Object &FB, const Object &FC, float AW, float BW, float CW, float InvW, float a, float b, float c, bool Flat, bool Perspective)
Recursively populate a fragment shader input variable by interpolating between the vertex shader outp...
uint32_t getInstanceOffset() const
Returns the offset of the first instance.
This class represents a framebuffer that can be used for rendering.
VkPrimitiveTopology getTopology() const
Returns the primitive topology used by this pipeline.
std::mutex WorkerMutex
Mutex used to synchronize with worker threads.
This file declares the PipelineExecutor class.
uint32_t getWidth() const
Returns the width of this framebuffer in pixels.
const PipelineStage * getFragmentStage() const
Returns the fragment pipeline stage.
std::vector< VkPipelineColorBlendAttachmentState > BlendAttachmentStateList
A list of pipeline color blend attachment states.
This class represents an address space in the virtual device.
void print(std::ostream &O, bool Align=true) const
Print a human-readable form of this instruction to O.
const PipelineContext & getPipelineContext() const
Returns the pipeline context.
Structure used to hold information about an element of a descriptor array.
const VertexAttributeDescriptionList & getVertexAttributeDescriptions() const
Returns the list of vertex attribute descriptions.
This file declares the PipelineStage class.
Device & Dev
The device this shader is executing on.
const std::array< float, 4 > & getBlendConstants() const
Returns the blend constants.
This file declares data structures and functions for handling images.
This class encapsulates a graphics pipeline.
This class represents a Vulkan render pass.
bool wasDiscarded() const
Returns true if this invocation has been discarded with OpKill.
uint32_t getBitWidth() const
Returns the bit-width of this type.
uint32_t getStorageClass() const
Returns the storage class of this type.
void zero()
Set all of the value bits in this object to zero.
A Device instance encapsulates properties and state for the virtual device.
const std::vector< ImageView * > & getAttachments() const
Returns the list of attachments backing this framebuffer.
Outputs from a vertex shading stage.
This file declares the RenderPass class and related data structures.
This class represents a workgroup executing a compute command.
float X
The framebuffer x-coordinate.
const VariableList & getVariables() const
Returns the input/output variables used by this entry point.
This file declares the GraphicsPipeline class.
uint8_t * getData()
Returns a mutable pointer to the raw data backing this object.
const Instruction * previous() const
Get the previous instruction in the containing block.
Point primitive data, used for rasterization.
const std::vector< Object > & getObjects() const
Returns a list of all result objects in this pipeline stage.
const Type * getResultType() const
Returns the result type of this instruction, or nullptr if it does not produce a result.
float Y
The framebuffer y-coordinate.
const RenderPass & getRenderPass() const
Returns the render pass.
This file declares the Memory class.
std::vector< std::thread > WorkerThreads
List of worker threads.
void loadNormalizedVertexInput(Object &Obj, VkFormat Format, const Memory &Mem, uint64_t Address)
Memory & getGlobalMemory()
Get the global memory instance associated with this device.
void blendTexel(Image::Texel &NewTexel, const Image::Texel &OldTexel, const VkPipelineColorBlendAttachmentState &Blend, const std::array< float, 4 > &BlendConstants)
const DescriptorSetMap & getComputeDescriptors() const
Returns the descriptor bindings for compute commands.
TypeId getTypeId() const
Returns the type ID of this type.
uint64_t NumBytes
Size of descriptor element.
uint32_t getNumInstances() const
Returns the number of instances.
void load(uint8_t *Result, uint64_t Address, uint64_t NumBytes) const
Load NumBytes of data from Address into Result.
const Instruction * getCurrentInstruction() const
Returns the instruction that this invocation is executing.
PipelineExecutor(PipelineExecutorKey Key, Device &Dev)
Create a pipeline executor on Dev.
Dim3 getGroupSize() const
Return the workgroup size.
This file declares the Command base class and its subclasses.
Vec4 PosC
The position of vertex C.
bool isThreadSafe() const
Returns true if all of the loaded plugins are thread-safe.
This class represents a SPIR-V type.
float InvW
Inverse of the interpolated clip w coordinate.
This file declares the Invocation class.
Dim3 getGlobalId() const
Returns the global invocation ID.
const VertexBindingDescriptionList & getVertexBindingDescriptions() const
Returns the list of vertex binding descriptions.
uint64_t allocate(uint64_t NumBytes)
Allocate a new buffer of size NumBytes.
Object getObject(uint32_t Id) const
Returns the object with the specified ID.
uint32_t getNumAttachments() const
Returns the number of attachments in this render pass.
This class represents an instruction result.
void store(uint64_t Address, uint64_t NumBytes, const uint8_t *Data)
Store NumBytes of data from Data to Address.
const std::vector< VkViewport > & getViewports() const
Returns the viewports.
static const uint32_t PUSH_CONSTANT_MEM_SIZE
The number of bytes used for push constant data.
const Instruction * next() const
Get the next instruction in the containing block.
std::vector< std::unique_ptr< Invocation > > WorkItemList
List of work items in the workgroup.
const PipelineStage * getVertexStage() const
Returns the vertex pipeline stage.
This class represents a SPIR-V instruction.
const uint8_t * getPushConstantData() const
Returns a pointer to the push constant data.
static uint32_t NextBreakpoint
Index of the next breakpoint to create.
uint32_t getNumVertices() const
Returns the number of vertices.
This file declares the Variable class.
float XDevToFB(float Xd, VkViewport Viewport)
bool Continue
True when the user has used continue command.
std::vector< Dim3 > PendingGroups
Pool of group IDs pending creation and execution.
bool isVector() const
Returns true if this is a vector type.
This class encapsulates a compute pipeline.
unsigned NumThreads
The number of worker threads currently executing.
State to be carried through the execution of a render pipeline.
uint64_t Address
Address of descriptor element.
float Depth
Fragment depth.
Dim3 getBaseGroup() const
Returns the base workgroup offset used by this command.
bool Interactive
True when interactive mode is enabled.
const WorkItemList & getWorkItems() const
Return the list of work items in this workgroup.
void print(std::ostream &Stream, uint8_t *Data, const Type *Ty)
Recursively print typed data to a stream.
std::vector< VertexOutput > VertexOutputs
The outputs from the vertex shading stage.
const VertexBindingMap & getVertexBindings() const
Returns the vertex bindings.
Internal structure to hold fragment data.
uint32_t getVertexOffset() const
Returns the offset of the first vertex.