dev/studio-packer-rgba8888-asset-pipeline #11

Merged
bquarkz merged 10 commits from dev/studio-packer-rgba8888-asset-pipeline into master 2026-05-24 21:46:24 +00:00
13 changed files with 244 additions and 1 deletions
Showing only changes of commit 5dc876c923 - Show all commits

View File

@ -1,6 +1,25 @@
final_id_hex,final_id_dec,canonical_name,canonical_version,owner,name,arg_slots,ret_slots,arg_layout,ret_layout,deterministic,may_allocate
0x1000,4096,vec2.dot,1,vec2,dot,4,1,float|float|float|float,float,true,false
0x1001,4097,vec2.length,1,vec2,length,2,1,float|float,float,true,false
0x1100,4352,color.from_raw,1,color,from_raw,1,1,int,builtin:color,true,false
0x1101,4353,color.rgb,1,color,rgb,3,1,int|int|int,builtin:color,true,false
0x1102,4354,color.rgba,1,color,rgba,4,1,int|int|int|int,builtin:color,true,false
0x1103,4355,color.html_rgba,1,color,html_rgba,1,1,str,builtin:color,true,false
0x1104,4356,color.gray_scale,1,color,gray_scale,1,1,int,builtin:color,true,false
0x1105,4357,color.hex,1,color,hex,1,1,builtin:color,int,true,false
0x1106,4358,color.alpha,1,color,alpha,1,1,builtin:color,int,true,false
0x1120,4384,color.black,1,color,black,0,1,,builtin:color,true,false
0x1121,4385,color.white,1,color,white,0,1,,builtin:color,true,false
0x1122,4386,color.red,1,color,red,0,1,,builtin:color,true,false
0x1123,4387,color.green,1,color,green,0,1,,builtin:color,true,false
0x1124,4388,color.blue,1,color,blue,0,1,,builtin:color,true,false
0x1125,4389,color.yellow,1,color,yellow,0,1,,builtin:color,true,false
0x1126,4390,color.orange,1,color,orange,0,1,,builtin:color,true,false
0x1127,4391,color.indigo,1,color,indigo,0,1,,builtin:color,true,false
0x1128,4392,color.gray,1,color,gray,0,1,,builtin:color,true,false
0x1129,4393,color.cyan,1,color,cyan,0,1,,builtin:color,true,false
0x112A,4394,color.magenta,1,color,magenta,0,1,,builtin:color,true,false
0x112B,4395,color.transparent,1,color,transparent,0,1,,builtin:color,true,false
0x2000,8192,input.pad,1,input,pad,0,1,,builtin:input.pad,true,false
0x2001,8193,input.touch,1,input,touch,0,1,,builtin:input.touch,true,false
0x2010,8208,input.pad.up,1,input.pad,up,1,1,builtin:input.pad,builtin:input.button,true,false

1 final_id_hex final_id_dec canonical_name canonical_version owner name arg_slots ret_slots arg_layout ret_layout deterministic may_allocate
2 0x1000 4096 vec2.dot 1 vec2 dot 4 1 float|float|float|float float true false
3 0x1001 4097 vec2.length 1 vec2 length 2 1 float|float float true false
4 0x1100 4352 color.from_raw 1 color from_raw 1 1 int builtin:color true false
5 0x1101 4353 color.rgb 1 color rgb 3 1 int|int|int builtin:color true false
6 0x1102 4354 color.rgba 1 color rgba 4 1 int|int|int|int builtin:color true false
7 0x1103 4355 color.html_rgba 1 color html_rgba 1 1 str builtin:color true false
8 0x1104 4356 color.gray_scale 1 color gray_scale 1 1 int builtin:color true false
9 0x1105 4357 color.hex 1 color hex 1 1 builtin:color int true false
10 0x1106 4358 color.alpha 1 color alpha 1 1 builtin:color int true false
11 0x1120 4384 color.black 1 color black 0 1 builtin:color true false
12 0x1121 4385 color.white 1 color white 0 1 builtin:color true false
13 0x1122 4386 color.red 1 color red 0 1 builtin:color true false
14 0x1123 4387 color.green 1 color green 0 1 builtin:color true false
15 0x1124 4388 color.blue 1 color blue 0 1 builtin:color true false
16 0x1125 4389 color.yellow 1 color yellow 0 1 builtin:color true false
17 0x1126 4390 color.orange 1 color orange 0 1 builtin:color true false
18 0x1127 4391 color.indigo 1 color indigo 0 1 builtin:color true false
19 0x1128 4392 color.gray 1 color gray 0 1 builtin:color true false
20 0x1129 4393 color.cyan 1 color cyan 0 1 builtin:color true false
21 0x112A 4394 color.magenta 1 color magenta 0 1 builtin:color true false
22 0x112B 4395 color.transparent 1 color transparent 0 1 builtin:color true false
23 0x2000 8192 input.pad 1 input pad 0 1 builtin:input.pad true false
24 0x2001 8193 input.touch 1 input touch 0 1 builtin:input.touch true false
25 0x2010 8208 input.pad.up 1 input.pad up 1 1 builtin:input.pad builtin:input.button true false

View File

@ -574,7 +574,30 @@ final class PbsExecutableBodyLowerer {
final var constDecl = context.resolveConstDecl(identifierExpr.name());
if (constDecl != null && constDecl.initializer() != null) {
lowerConstExpression(constDecl.initializer(), context);
return;
}
final var builtinConst = context.builtinConstByNameId().get(context.nameTable().register(identifierExpr.name()));
if (builtinConst != null) {
emitBuiltinConstFetch(builtinConst, identifierExpr.span(), context);
}
}
private void emitBuiltinConstFetch(
final p.studio.compiler.models.IRReservedMetadata.BuiltinConstSurface builtinConst,
final p.studio.compiler.source.Span span,
final PbsExecutableLoweringContext context) {
final var canonicalName = builtinConst.canonicalTarget() + "." + builtinConst.canonicalName();
context.instructions().add(new IRBackendExecutableFunction.Instruction(
IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC,
"",
null,
new IRBackendExecutableFunction.IntrinsicCallMetadata(
canonicalName,
builtinConst.canonicalVersion(),
context.intrinsicIdTable().register(canonicalName, builtinConst.canonicalVersion())),
0,
1,
span));
}
private String flattenAssetReference(final PbsAst.Expression expression) {

View File

@ -326,6 +326,10 @@ final class PbsExecutableCallsiteEmitter {
if (!localOwner.isBlank()) {
return localOwner;
}
final var builtinOwner = context.builtinCanonicalBySourceType().getOrDefault(identifier, "");
if (!builtinOwner.isBlank()) {
return builtinOwner;
}
return context.builtinConstOwnerByNameId().getOrDefault(context.nameTable().register(identifier), "");
}

View File

@ -60,6 +60,10 @@ final class PbsExecutableLoweringContext {
return metadataIndex.builtinConstOwnerByNameId();
}
Map<NameId, p.studio.compiler.models.IRReservedMetadata.BuiltinConstSurface> builtinConstByNameId() {
return metadataIndex.builtinConstByNameId();
}
Map<NameId, Integer> globalSlotByNameId() {
return metadataIndex.globalSlotByNameId();
}

View File

@ -45,6 +45,7 @@ public class PbsExecutableLoweringModels {
Map<NameId, List<IRReservedMetadata.HostMethodBinding>> hostByMethodName,
Map<String, String> builtinCanonicalBySourceType,
Map<NameId, String> builtinConstOwnerByNameId,
Map<NameId, IRReservedMetadata.BuiltinConstSurface> builtinConstByNameId,
Map<NameId, Integer> globalSlotByNameId,
Map<NameId, PbsAst.ConstDecl> constDeclByNameId,
Map<String, Addressable> addressableByAddress,

View File

@ -30,6 +30,7 @@ final class PbsExecutableMetadataIndexFactory {
final var hostByMethodName = indexHostBindingsByMethodName(reservedMetadata, nameTable);
final var builtinCanonicalBySourceType = indexBuiltinCanonicalBySourceType(reservedMetadata);
final var builtinConstOwnerByNameId = indexBuiltinConstOwners(reservedMetadata, nameTable);
final var builtinConstByNameId = indexBuiltinConstSurfaces(reservedMetadata, nameTable);
final var globalSlotByNameId = indexGlobalSlots(ast, nameTable);
final var constDeclByNameId = indexConstDecls(ast, nameTable);
final var addressableByAddress = indexAddressables(feSurfaceContext);
@ -50,6 +51,7 @@ final class PbsExecutableMetadataIndexFactory {
hostByMethodName,
builtinCanonicalBySourceType,
builtinConstOwnerByNameId,
builtinConstByNameId,
globalSlotByNameId,
constDeclByNameId,
addressableByAddress,
@ -90,6 +92,19 @@ final class PbsExecutableMetadataIndexFactory {
return builtinConstOwnerByNameId;
}
private Map<NameId, IRReservedMetadata.BuiltinConstSurface> indexBuiltinConstSurfaces(
final IRReservedMetadata reservedMetadata,
final NameTable nameTable) {
final var builtinConstByNameId = new HashMap<NameId, IRReservedMetadata.BuiltinConstSurface>();
for (final var builtinConst : reservedMetadata.builtinConstSurfaces()) {
if (builtinConst.sourceConstName().isBlank() || builtinConst.canonicalTarget().isBlank()) {
continue;
}
builtinConstByNameId.put(nameTable.register(builtinConst.sourceConstName()), builtinConst);
}
return builtinConstByNameId;
}
private Map<NameId, Integer> indexGlobalSlots(
final PbsAst.File ast,
final NameTable nameTable) {

View File

@ -86,6 +86,22 @@ final class PbsFlowCallableResolutionAnalyzer {
if (enumCases != null && enumCases.contains(memberExpr.memberName())) {
return ExprResult.type(TypeView.enumType(receiver.name()));
}
if (model.knownBuiltinTypeNames.contains(receiver.name())) {
final var builtin = model.structs.get(receiver.name());
if (builtin != null) {
final var methods = builtin.methods().get(memberExpr.memberName());
if (methods != null && !methods.isEmpty()) {
if (use == ExprUse.VALUE) {
Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_BARE_METHOD_EXTRACTION.name(),
"Bare method extraction is not allowed in PBS core",
memberExpr.span());
return ExprResult.type(TypeView.unknown());
}
return ExprResult.callables(methods, true);
}
}
}
Diagnostics.error(diagnostics,
PbsSemanticsErrors.E_SEM_INVALID_MEMBER_ACCESS.name(),
"Invalid type member access",

View File

@ -191,6 +191,7 @@ final class PbsFlowSemanticSupport {
final Map<String, TypeView> constTypes = new HashMap<>();
final Map<String, TypeView> globalTypes = new HashMap<>();
final Map<String, TypeView> serviceSingletons = new HashMap<>();
final Set<String> knownBuiltinTypeNames = new HashSet<>();
final Set<String> knownStructNames = new HashSet<>();
final Set<String> knownServiceNames = new HashSet<>();
final Set<String> knownContractNames = new HashSet<>();
@ -232,6 +233,7 @@ final class PbsFlowSemanticSupport {
return;
}
if (topDecl instanceof PbsAst.BuiltinTypeDecl builtinTypeDecl) {
knownBuiltinTypeNames.add(builtinTypeDecl.name());
knownStructNames.add(builtinTypeDecl.name());
return;
}

View File

@ -108,6 +108,10 @@ final class PbsFlowStructuralExpressionAnalyzer {
return ExprResult.type(TypeView.typeRef(identifierExpr.name()));
}
if (model.knownBuiltinTypeNames.contains(identifierExpr.name())) {
return ExprResult.type(TypeView.typeRef(identifierExpr.name()));
}
return ExprResult.type(TypeView.unknown());
}
if (expression instanceof PbsAst.GroupExpr groupExpr) {

View File

@ -1,5 +1,61 @@
[BuiltinType(name = "Color", version = 1)]
[BuiltinType(name = "color", version = 1)]
declare builtin type Color(
pub raw: int
) {
[IntrinsicCall(name = "from_raw", version = 1)]
fn from_raw(raw: int) -> Color;
[IntrinsicCall(name = "rgb", version = 1)]
fn rgb(r: int, g: int, b: int) -> Color;
[IntrinsicCall(name = "rgba", version = 1)]
fn rgba(r: int, g: int, b: int, a: int) -> Color;
[IntrinsicCall(name = "html_rgba", version = 1)]
fn html_rgba(value: str) -> Color;
[IntrinsicCall(name = "gray_scale", version = 1)]
fn gray_scale(value: int) -> Color;
[IntrinsicCall(name = "hex", version = 1)]
fn hex() -> int;
[IntrinsicCall(name = "alpha", version = 1)]
fn alpha() -> int;
}
[BuiltinConst(target = "color", name = "black", version = 1)]
declare const BLACK: Color;
[BuiltinConst(target = "color", name = "white", version = 1)]
declare const WHITE: Color;
[BuiltinConst(target = "color", name = "red", version = 1)]
declare const RED: Color;
[BuiltinConst(target = "color", name = "green", version = 1)]
declare const GREEN: Color;
[BuiltinConst(target = "color", name = "blue", version = 1)]
declare const BLUE: Color;
[BuiltinConst(target = "color", name = "yellow", version = 1)]
declare const YELLOW: Color;
[BuiltinConst(target = "color", name = "orange", version = 1)]
declare const ORANGE: Color;
[BuiltinConst(target = "color", name = "indigo", version = 1)]
declare const INDIGO: Color;
[BuiltinConst(target = "color", name = "gray", version = 1)]
declare const GRAY: Color;
[BuiltinConst(target = "color", name = "cyan", version = 1)]
declare const CYAN: Color;
[BuiltinConst(target = "color", name = "magenta", version = 1)]
declare const MAGENTA: Color;
[BuiltinConst(target = "color", name = "transparent", version = 1)]
declare const TRANSPARENT: Color;

View File

@ -1 +1,13 @@
pub struct Color;
pub const BLACK;
pub const WHITE;
pub const RED;
pub const GREEN;
pub const BLUE;
pub const YELLOW;
pub const ORANGE;
pub const INDIGO;
pub const GRAY;
pub const CYAN;
pub const MAGENTA;
pub const TRANSPARENT;

View File

@ -1019,6 +1019,74 @@ class PBSFrontendPhaseServiceTest {
assertTrue(irBackend.getExecutableFunctions().stream().anyMatch(function -> "frame".equals(function.callableName())));
}
@Test
void shouldLowerCoreColorConstructorsAndConstantsFromBootstrapStdlib() throws IOException {
final var projectRoot = tempDir.resolve("project-bootstrap-core-color-rgba");
final var sourceRoot = projectRoot.resolve("src");
final var modulePath = sourceRoot.resolve("app");
Files.createDirectories(modulePath);
final var sourceFile = modulePath.resolve("source.pbs");
final var modBarrel = modulePath.resolve("mod.barrel");
Files.writeString(sourceFile, """
import { Color, RED, TRANSPARENT } from @core:color;
import { Gfx } from @sdk:gfx;
[Frame]
fn frame() -> void
{
let tint: Color = Color.rgba(1, 2, 3, 128);
let web: Color = Color.html_rgba("#11223344");
Gfx.clear(RED);
Gfx.fill_rect(0, 0, 1, 1, tint);
Gfx.fill_rect(1, 0, 1, 1, web);
Gfx.fill_rect(2, 0, 1, 1, TRANSPARENT);
}
""");
Files.writeString(modBarrel, "pub fn frame() -> void;");
final var projectTable = new ProjectTable();
final var fileTable = new FileTable(1);
final var projectId = projectTable.register(ProjectDescriptor.builder()
.rootPath(projectRoot)
.name("app")
.version("1.0.0")
.sourceRoots(ReadOnlyList.wrap(List.of(sourceRoot)))
.build());
registerFile(projectId, projectRoot, sourceFile, fileTable);
registerFile(projectId, projectRoot, modBarrel, fileTable);
final var ctx = new FrontendPhaseContext(
projectTable,
fileTable,
new BuildStack(ReadOnlyList.wrap(List.of(projectId))),
1,
AppMode.Game);
final var diagnostics = DiagnosticSink.empty();
final var irBackend = new PBSFrontendPhaseService().compile(
ctx,
diagnostics,
LogAggregator.empty(),
BuildingIssueSink.empty());
assertFalse(diagnostics.hasErrors(),
"diagnostics=" + diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList());
assertTrue(diagnostics.stream().noneMatch(d ->
d.getCode().equals(PbsSemanticsErrors.E_SEM_EXEC_LOWERING_UNRESOLVED_CALLEE.name())),
"diagnostics=" + diagnostics.stream().map(d -> d.getCode() + ":" + d.getMessage()).toList());
final var intrinsicNames = irBackend.getExecutableFunctions().stream()
.flatMap(function -> function.instructions().stream())
.filter(instruction -> instruction.kind() == IRBackendExecutableFunction.InstructionKind.CALL_INTRINSIC)
.map(instruction -> instruction.intrinsicCall().canonicalName())
.toList();
assertTrue(intrinsicNames.contains("color.rgba"), "intrinsics=" + intrinsicNames);
assertTrue(intrinsicNames.contains("color.html_rgba"), "intrinsics=" + intrinsicNames);
assertTrue(intrinsicNames.contains("color.red"), "intrinsics=" + intrinsicNames);
assertTrue(intrinsicNames.contains("color.transparent"), "intrinsics=" + intrinsicNames);
}
@Test
void shouldLowerSdkComposerEmitSpriteFacadeUsingCanonicalComposerContract() throws IOException {
final var projectRoot = tempDir.resolve("project-bootstrap-sdk-composer-emit-sprite");

View File

@ -5,6 +5,25 @@ import java.util.Objects;
enum IRVMIntrinsicDefinition {
VEC2_DOT("vec2.dot", 1, 0x1000, "vec2", "dot", 4, 1, "float|float|float|float", "float", true, false),
VEC2_LENGTH("vec2.length", 1, 0x1001, "vec2", "length", 2, 1, "float|float", "float", true, false),
COLOR_FROM_RAW("color.from_raw", 1, 0x1100, "color", "from_raw", 1, 1, "int", "builtin:color", true, false),
COLOR_RGB("color.rgb", 1, 0x1101, "color", "rgb", 3, 1, "int|int|int", "builtin:color", true, false),
COLOR_RGBA("color.rgba", 1, 0x1102, "color", "rgba", 4, 1, "int|int|int|int", "builtin:color", true, false),
COLOR_HTML_RGBA("color.html_rgba", 1, 0x1103, "color", "html_rgba", 1, 1, "str", "builtin:color", true, false),
COLOR_GRAY_SCALE("color.gray_scale", 1, 0x1104, "color", "gray_scale", 1, 1, "int", "builtin:color", true, false),
COLOR_HEX("color.hex", 1, 0x1105, "color", "hex", 1, 1, "builtin:color", "int", true, false),
COLOR_ALPHA("color.alpha", 1, 0x1106, "color", "alpha", 1, 1, "builtin:color", "int", true, false),
COLOR_BLACK("color.black", 1, 0x1120, "color", "black", 0, 1, "", "builtin:color", true, false),
COLOR_WHITE("color.white", 1, 0x1121, "color", "white", 0, 1, "", "builtin:color", true, false),
COLOR_RED("color.red", 1, 0x1122, "color", "red", 0, 1, "", "builtin:color", true, false),
COLOR_GREEN("color.green", 1, 0x1123, "color", "green", 0, 1, "", "builtin:color", true, false),
COLOR_BLUE("color.blue", 1, 0x1124, "color", "blue", 0, 1, "", "builtin:color", true, false),
COLOR_YELLOW("color.yellow", 1, 0x1125, "color", "yellow", 0, 1, "", "builtin:color", true, false),
COLOR_ORANGE("color.orange", 1, 0x1126, "color", "orange", 0, 1, "", "builtin:color", true, false),
COLOR_INDIGO("color.indigo", 1, 0x1127, "color", "indigo", 0, 1, "", "builtin:color", true, false),
COLOR_GRAY("color.gray", 1, 0x1128, "color", "gray", 0, 1, "", "builtin:color", true, false),
COLOR_CYAN("color.cyan", 1, 0x1129, "color", "cyan", 0, 1, "", "builtin:color", true, false),
COLOR_MAGENTA("color.magenta", 1, 0x112A, "color", "magenta", 0, 1, "", "builtin:color", true, false),
COLOR_TRANSPARENT("color.transparent", 1, 0x112B, "color", "transparent", 0, 1, "", "builtin:color", true, false),
INPUT_PAD("input.pad", 1, 0x2000, "input", "pad", 0, 1, "", "builtin:input.pad", true, false),
INPUT_TOUCH("input.touch", 1, 0x2001, "input", "touch", 0, 1, "", "builtin:input.touch", true, false),
INPUT_PAD_UP("input.pad.up", 1, 0x2010, "input.pad", "up", 1, 1, "builtin:input.pad", "builtin:input.button", true, false),