@forgeax/engine-assets-runtime 0.1.19 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=texture-pack-loader.unit.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"texture-pack-loader.unit.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/texture-pack-loader.unit.test.ts"],"names":[],"mappings":""}
@@ -25,8 +25,8 @@ import type { ImageError, Result, TextureAsset } from '@forgeax/engine-types';
25
25
  * @param opts - Optional decode overrides:
26
26
  * - `colorSpace`: `'srgb'` (default) or `'linear'`. Derives POD `format`:
27
27
  * `srgb -> 'rgba8unorm-srgb'`, `linear -> 'rgba8unorm'`.
28
- * - `mipmap`: `true` (default) or `false`. When true, `mipLevelCount` is
29
- * computed via `numMipLevels({ width, height })`; when false, forced 1.
28
+ * - `mipmap`: `true` (default) or `false`. When true, the producer requests
29
+ * generated mips; when false, it keeps one authored level.
30
30
  * @returns `ok(TextureAsset)` on success; `err(ImageError)` on failure.
31
31
  *
32
32
  * @example
@@ -1 +1 @@
1
- {"version":3,"file":"decode-image-bytes.d.ts","sourceRoot":"","sources":["../src/decode-image-bytes.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAa9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,GAAG,WAAW,EAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9D,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CAkC3C"}
1
+ {"version":3,"file":"decode-image-bytes.d.ts","sourceRoot":"","sources":["../src/decode-image-bytes.ts"],"names":[],"mappings":"AAuBA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAY9E;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkDG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,UAAU,GAAG,WAAW,EAC/B,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,UAAU,CAAC,EAAE,MAAM,GAAG,QAAQ,CAAC;IAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAC9D,OAAO,CAAC,MAAM,CAAC,YAAY,EAAE,UAAU,CAAC,CAAC,CA8B3C"}
@@ -1,5 +1,25 @@
1
1
  import type { MeshBinHeaderV4 } from '@forgeax/engine-pack';
2
2
  import { AssetError, type AssetMeshBinContractFacts, type AssetMeshBinContractViolationReason } from '@forgeax/engine-types';
3
+ export type TexturePackVerificationCause = 'byte-length' | 'digest-mismatch' | 'packing-order-mismatch' | 'shape-mismatch';
4
+ export interface TexturePackVerificationDetail {
5
+ readonly guid: string;
6
+ readonly sourceKey: string;
7
+ readonly generation: number;
8
+ readonly stage: 'producer' | 'loader';
9
+ readonly cause: TexturePackVerificationCause;
10
+ readonly expectedBytes?: number;
11
+ readonly actualBytes?: number;
12
+ readonly expectedDigest?: string;
13
+ readonly actualDigest?: string;
14
+ }
15
+ /** Structured failure for the producer/loader texture contract. */
16
+ export declare class TexturePackVerificationError extends Error {
17
+ readonly code: "texture-pack-verification-failed";
18
+ readonly expected: string;
19
+ readonly hint = "repair the producer output and retry the same texture GUID generation";
20
+ readonly detail: TexturePackVerificationDetail;
21
+ constructor(detail: TexturePackVerificationDetail, expected: string);
22
+ }
3
23
  export declare class MeshBinAssetError extends AssetError {
4
24
  readonly subject: "mesh-bin";
5
25
  readonly sourceKey: string;
@@ -1 +1 @@
1
- {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../src/errors/asset.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"asset.d.ts","sourceRoot":"","sources":["../../src/errors/asset.ts"],"names":[],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -695,217 +695,6 @@ function unpackMeshBinV4(bytes, sourceKey) {
695
695
  };
696
696
  return ok(mesh);
697
697
  }
698
- var deviceCache = /* @__PURE__ */ new WeakMap();
699
- var MIPMAP_WGSL = `
700
- struct VsOut {
701
- @builtin(position) clip : vec4<f32>,
702
- @location(0) uv : vec2<f32>,
703
- };
704
-
705
- @vertex
706
- fn vs_main(@builtin(vertex_index) vid : u32) -> VsOut {
707
- // 3 vertices forming an oversized triangle: (-1,-1), (-1,3), (3,-1)
708
- var positions = array<vec2<f32>, 3>(
709
- vec2<f32>(-1.0, -1.0),
710
- vec2<f32>(-1.0, 3.0),
711
- vec2<f32>( 3.0, -1.0),
712
- );
713
- let pos = positions[vid];
714
- var out : VsOut;
715
- out.clip = vec4<f32>(pos, 0.0, 1.0);
716
- // NDC -> UV with Y-flip fused into a single MAD.
717
- out.uv = pos * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
718
- return out;
719
- }
720
-
721
- @group(0) @binding(0) var src_sampler : sampler;
722
- @group(0) @binding(1) var src_texture : texture_2d<f32>;
723
-
724
- @fragment
725
- fn fs_main(in : VsOut) -> @location(0) vec4<f32> {
726
- return textureSample(src_texture, src_sampler, in.uv);
727
- }
728
- `;
729
- function numMipLevels(size) {
730
- const max = Math.max(size.width, size.height);
731
- if (max <= 1) return 1;
732
- return Math.floor(Math.log2(max)) + 1;
733
- }
734
- function mipmapCacheSize(device) {
735
- const cache = deviceCache.get(device);
736
- return cache?.pipelines.size ?? 0;
737
- }
738
- async function getOrCreateMipmapPipeline(device, format, asyncCreateShaderModule) {
739
- const cache = await ensureDeviceCache(device, asyncCreateShaderModule);
740
- if (!cache.ok) return cache;
741
- const existing = cache.value.pipelines.get(format);
742
- if (existing !== void 0) {
743
- return ok$1(existing);
744
- }
745
- const layoutRes = device.createPipelineLayout({
746
- label: "mipmap-pl",
747
- bindGroupLayouts: [cache.value.layout]
748
- });
749
- if (!layoutRes.ok) return layoutRes;
750
- const pipelineRes = device.createRenderPipeline({
751
- label: `mipmap-pipeline-${format}`,
752
- layout: layoutRes.value,
753
- vertex: { module: cache.value.module, entryPoint: "vs_main" },
754
- fragment: {
755
- module: cache.value.module,
756
- entryPoint: "fs_main",
757
- targets: [{ format }]
758
- },
759
- primitive: { topology: "triangle-list" }
760
- });
761
- if (!pipelineRes.ok) return pipelineRes;
762
- cache.value.pipelines.set(format, pipelineRes.value);
763
- return pipelineRes;
764
- }
765
- async function ensureDeviceCache(device, asyncCreateShaderModule) {
766
- const existing = deviceCache.get(device);
767
- if (existing !== void 0) return ok$1(existing);
768
- const moduleRes = await asyncCreateShaderModule(device, {
769
- code: MIPMAP_WGSL,
770
- label: "mipmap-wgsl"
771
- });
772
- if (!moduleRes.ok) return moduleRes;
773
- const samplerRes = device.createSampler({
774
- magFilter: "linear",
775
- minFilter: "linear",
776
- mipmapFilter: "linear"
777
- });
778
- if (!samplerRes.ok) return samplerRes;
779
- const FRAGMENT_STAGE = 2;
780
- const layoutRes = device.createBindGroupLayout({
781
- label: "mipmap-bgl",
782
- entries: [
783
- { binding: 0, visibility: FRAGMENT_STAGE, sampler: { type: "filtering" } },
784
- {
785
- binding: 1,
786
- visibility: FRAGMENT_STAGE,
787
- texture: { sampleType: "float", viewDimension: "2d" }
788
- }
789
- ]
790
- });
791
- if (!layoutRes.ok) return layoutRes;
792
- const cache = {
793
- sampler: samplerRes.value,
794
- module: moduleRes.value,
795
- layout: layoutRes.value,
796
- pipelines: /* @__PURE__ */ new Map()
797
- };
798
- deviceCache.set(device, cache);
799
- return ok$1(cache);
800
- }
801
- function recordMipmapBlit(device, texture, levels, pipeline, cache) {
802
- const encoderRes = device.createCommandEncoder({ label: "mipmap-encoder" });
803
- if (!encoderRes.ok) return encoderRes;
804
- const encoder = encoderRes.value;
805
- for (let i = 1; i < levels; i++) {
806
- const srcViewRes = device.createTextureView(texture, {
807
- baseMipLevel: i - 1,
808
- mipLevelCount: 1,
809
- dimension: "2d"
810
- });
811
- if (!srcViewRes.ok) return srcViewRes;
812
- const dstViewRes = device.createTextureView(texture, {
813
- baseMipLevel: i,
814
- mipLevelCount: 1,
815
- dimension: "2d"
816
- });
817
- if (!dstViewRes.ok) return dstViewRes;
818
- const bindGroupRes = device.createBindGroup({
819
- label: `mipmap-bg-${i}`,
820
- layout: cache.layout,
821
- entries: [
822
- { binding: 0, resource: { kind: "sampler", value: cache.sampler } },
823
- { binding: 1, resource: { kind: "textureView", value: srcViewRes.value } }
824
- ]
825
- });
826
- if (!bindGroupRes.ok) return bindGroupRes;
827
- const pass = encoder.beginRenderPass({
828
- label: `mipmap-pass-${i}`,
829
- colorAttachments: [
830
- {
831
- view: dstViewRes.value,
832
- clearValue: { r: 0, g: 0, b: 0, a: 1 },
833
- loadOp: "clear",
834
- storeOp: "store"
835
- }
836
- ]
837
- });
838
- pass.setPipeline(pipeline);
839
- pass.setBindGroup(0, bindGroupRes.value);
840
- pass.draw(3, 1, 0, 0);
841
- pass.end();
842
- }
843
- const finishRes = encoder.finish();
844
- if (!finishRes.ok) return finishRes;
845
- return device.queue.submit([finishRes.value]);
846
- }
847
- function blitMipmapsSync(device, texture, descriptor) {
848
- const levels = descriptor.levels ?? numMipLevels(descriptor);
849
- if (levels <= 1) return ok$1(void 0);
850
- const cache = deviceCache.get(device);
851
- if (cache === void 0) {
852
- return err(
853
- new RhiError({
854
- code: "rhi-not-available",
855
- expected: "mipmap pipeline cache prewarmed for this device before blitMipmapsSync",
856
- hint: "call prewarmMipmapPipeline(device, formats) at renderer.ready before the synchronous record-stage mipmap blit"
857
- })
858
- );
859
- }
860
- const pipeline = cache.pipelines.get(descriptor.format);
861
- if (pipeline === void 0) {
862
- return err(
863
- new RhiError({
864
- code: "rhi-not-available",
865
- expected: `mipmap pipeline for format ${descriptor.format} prewarmed`,
866
- hint: `format ${descriptor.format} was not prewarmed; add it to the prewarmMipmapPipeline format list at renderer.ready`
867
- })
868
- );
869
- }
870
- return recordMipmapBlit(device, texture, levels, pipeline, cache);
871
- }
872
- function encodeMipmapLevel(device, pass, sourceView, format) {
873
- const cache = deviceCache.get(device);
874
- if (cache === void 0) {
875
- return err(
876
- new RhiError({
877
- code: "rhi-not-available",
878
- expected: "mipmap pipeline cache prewarmed for the graph device before encoding",
879
- hint: "call prewarmMipmapPipeline(device, formats) at renderer.ready"
880
- })
881
- );
882
- }
883
- const pipeline = cache.pipelines.get(format);
884
- if (pipeline === void 0) {
885
- return err(
886
- new RhiError({
887
- code: "rhi-not-available",
888
- expected: `mipmap pipeline for format ${format} prewarmed`,
889
- hint: `format ${format} was not prewarmed; add it to the renderer prewarm list`
890
- })
891
- );
892
- }
893
- const bindGroup = device.createBindGroup({
894
- label: "mipmap-graph-bind-group",
895
- layout: cache.layout,
896
- entries: [
897
- { binding: 0, resource: { kind: "sampler", value: cache.sampler } },
898
- { binding: 1, resource: { kind: "textureView", value: sourceView } }
899
- ]
900
- });
901
- if (!bindGroup.ok) return bindGroup;
902
- pass.setPipeline(pipeline);
903
- pass.setBindGroup(0, bindGroup.value);
904
- pass.draw(3, 1, 0, 0);
905
- return ok$1(void 0);
906
- }
907
-
908
- // src/loaders/pack-artifact.ts
909
698
  function firstArtifact(input) {
910
699
  return input.artifacts.body ?? Object.values(input.artifacts)[0];
911
700
  }
@@ -916,6 +705,34 @@ function payloadNumber(payload, key2, fallback) {
916
705
  function payloadColorSpace(payload) {
917
706
  return payload.colorSpace === "linear" ? "linear" : "srgb";
918
707
  }
708
+ function payloadTextureShape(payload) {
709
+ const shape = payload.shape;
710
+ if (!record(shape) || typeof shape.viewDimension !== "string" || !record(shape.extent)) {
711
+ return void 0;
712
+ }
713
+ const { width, height, layers, depth } = shape.extent;
714
+ if (!positiveInteger(width) || !positiveInteger(height)) return void 0;
715
+ if (shape.viewDimension === "2d" && layers === void 0 && depth === void 0) {
716
+ return { viewDimension: "2d", extent: { width, height } };
717
+ }
718
+ if (shape.viewDimension === "2d-array" && positiveInteger(layers) && depth === void 0) {
719
+ return { viewDimension: "2d-array", extent: { width, height, layers } };
720
+ }
721
+ if (shape.viewDimension === "3d" && positiveInteger(depth) && layers === void 0) {
722
+ return { viewDimension: "3d", extent: { width, height, depth } };
723
+ }
724
+ return void 0;
725
+ }
726
+ function payloadTextureMips(payload) {
727
+ const mips = payload.mips;
728
+ if (!record(mips) || typeof mips.kind !== "string") return void 0;
729
+ if (mips.kind === "none") return { kind: "none" };
730
+ if (mips.kind === "generate") return { kind: "generate" };
731
+ if (mips.kind === "packed" && positiveInteger(mips.levelCount)) {
732
+ return { kind: "packed", levelCount: mips.levelCount };
733
+ }
734
+ return void 0;
735
+ }
919
736
  function invalidPackAsset(input, expected) {
920
737
  return {
921
738
  ok: false,
@@ -1070,8 +887,6 @@ async function loadTexturePack(input, ctx) {
1070
887
  if (artifact === void 0)
1071
888
  return invalidPackAsset(input, "texture asset-local image artifact");
1072
889
  const payload = input.payload;
1073
- const width = payloadNumber(payload, "width", 0);
1074
- const height = payloadNumber(payload, "height", 0);
1075
890
  const colorSpace = payloadColorSpace(payload);
1076
891
  const codec = artifact.descriptor.assetCodec;
1077
892
  const profile = codecProfile(codec);
@@ -1119,13 +934,14 @@ async function loadTexturePack(input, ctx) {
1119
934
  ok: true,
1120
935
  value: {
1121
936
  kind: "texture",
1122
- width: transcoded.value.width,
1123
- height: transcoded.value.height,
937
+ shape: {
938
+ viewDimension: "2d",
939
+ extent: { width: transcoded.value.width, height: transcoded.value.height }
940
+ },
1124
941
  format: target,
1125
942
  data,
1126
943
  colorSpace,
1127
- mipmap: transcoded.value.mips.length > 1,
1128
- mipLevelCount: Math.max(1, transcoded.value.mips.length)
944
+ mips: { kind: "packed", levelCount: Math.max(1, transcoded.value.mips.length) }
1129
945
  }
1130
946
  };
1131
947
  } catch (error) {
@@ -1203,13 +1019,14 @@ async function loadTexturePack(input, ctx) {
1203
1019
  ok: true,
1204
1020
  value: {
1205
1021
  kind: "texture",
1206
- width: transcoded.value.width,
1207
- height: transcoded.value.height,
1022
+ shape: {
1023
+ viewDimension: "2d",
1024
+ extent: { width: transcoded.value.width, height: transcoded.value.height }
1025
+ },
1208
1026
  format: target,
1209
1027
  data,
1210
1028
  colorSpace,
1211
- mipmap: transcoded.value.mips.length > 1,
1212
- mipLevelCount: Math.max(1, transcoded.value.mips.length)
1029
+ mips: { kind: "packed", levelCount: Math.max(1, transcoded.value.mips.length) }
1213
1030
  }
1214
1031
  };
1215
1032
  } catch (error) {
@@ -1234,18 +1051,23 @@ async function loadTexturePack(input, ctx) {
1234
1051
  };
1235
1052
  }
1236
1053
  }
1237
- const mipmap = payload.mipmap === true;
1054
+ const shape = payloadTextureShape(payload);
1055
+ const mips = payloadTextureMips(payload);
1056
+ if (shape === void 0 || mips === void 0) {
1057
+ return invalidPackAsset(
1058
+ input,
1059
+ "texture payload with a valid shape and mip policy"
1060
+ );
1061
+ }
1238
1062
  return {
1239
1063
  ok: true,
1240
1064
  value: {
1241
1065
  kind: "texture",
1242
- width,
1243
- height,
1066
+ shape,
1244
1067
  format: payload.format ?? (colorSpace === "srgb" ? "rgba8unorm-srgb" : "rgba8unorm"),
1245
1068
  data: artifact.bytes,
1246
1069
  colorSpace,
1247
- mipmap,
1248
- mipLevelCount: mipmap ? numMipLevels({ width, height }) : 1
1070
+ mips
1249
1071
  }
1250
1072
  };
1251
1073
  }
@@ -6899,16 +6721,13 @@ async function decodeImageBytes(bytes, mime, opts = {}) {
6899
6721
  }
6900
6722
  const dec = decoded.value;
6901
6723
  const format = colorSpace === "srgb" ? "rgba8unorm-srgb" : "rgba8unorm";
6902
- const mipLevelCount = mipmap ? numMipLevels({ width: dec.width, height: dec.height }) : 1;
6903
6724
  const pod = {
6904
6725
  kind: "texture",
6905
- width: dec.width,
6906
- height: dec.height,
6726
+ shape: { viewDimension: "2d", extent: { width: dec.width, height: dec.height } },
6907
6727
  format,
6908
6728
  data: dec.bytes,
6909
6729
  colorSpace,
6910
- mipmap,
6911
- mipLevelCount
6730
+ mips: mipmap ? { kind: "generate" } : { kind: "none" }
6912
6731
  };
6913
6732
  return ok(pod);
6914
6733
  }
@@ -8318,6 +8137,215 @@ function inspectMaterialRuntime(ready) {
8318
8137
  status: "Ready"
8319
8138
  };
8320
8139
  }
8140
+ var deviceCache = /* @__PURE__ */ new WeakMap();
8141
+ var MIPMAP_WGSL = `
8142
+ struct VsOut {
8143
+ @builtin(position) clip : vec4<f32>,
8144
+ @location(0) uv : vec2<f32>,
8145
+ };
8146
+
8147
+ @vertex
8148
+ fn vs_main(@builtin(vertex_index) vid : u32) -> VsOut {
8149
+ // 3 vertices forming an oversized triangle: (-1,-1), (-1,3), (3,-1)
8150
+ var positions = array<vec2<f32>, 3>(
8151
+ vec2<f32>(-1.0, -1.0),
8152
+ vec2<f32>(-1.0, 3.0),
8153
+ vec2<f32>( 3.0, -1.0),
8154
+ );
8155
+ let pos = positions[vid];
8156
+ var out : VsOut;
8157
+ out.clip = vec4<f32>(pos, 0.0, 1.0);
8158
+ // NDC -> UV with Y-flip fused into a single MAD.
8159
+ out.uv = pos * vec2<f32>(0.5, -0.5) + vec2<f32>(0.5);
8160
+ return out;
8161
+ }
8162
+
8163
+ @group(0) @binding(0) var src_sampler : sampler;
8164
+ @group(0) @binding(1) var src_texture : texture_2d<f32>;
8165
+
8166
+ @fragment
8167
+ fn fs_main(in : VsOut) -> @location(0) vec4<f32> {
8168
+ return textureSample(src_texture, src_sampler, in.uv);
8169
+ }
8170
+ `;
8171
+ function numMipLevels(size) {
8172
+ const max = Math.max(size.width, size.height);
8173
+ if (max <= 1) return 1;
8174
+ return Math.floor(Math.log2(max)) + 1;
8175
+ }
8176
+ function mipmapCacheSize(device) {
8177
+ const cache = deviceCache.get(device);
8178
+ return cache?.pipelines.size ?? 0;
8179
+ }
8180
+ async function getOrCreateMipmapPipeline(device, format, asyncCreateShaderModule) {
8181
+ const cache = await ensureDeviceCache(device, asyncCreateShaderModule);
8182
+ if (!cache.ok) return cache;
8183
+ const existing = cache.value.pipelines.get(format);
8184
+ if (existing !== void 0) {
8185
+ return ok$1(existing);
8186
+ }
8187
+ const layoutRes = device.createPipelineLayout({
8188
+ label: "mipmap-pl",
8189
+ bindGroupLayouts: [cache.value.layout]
8190
+ });
8191
+ if (!layoutRes.ok) return layoutRes;
8192
+ const pipelineRes = device.createRenderPipeline({
8193
+ label: `mipmap-pipeline-${format}`,
8194
+ layout: layoutRes.value,
8195
+ vertex: { module: cache.value.module, entryPoint: "vs_main" },
8196
+ fragment: {
8197
+ module: cache.value.module,
8198
+ entryPoint: "fs_main",
8199
+ targets: [{ format }]
8200
+ },
8201
+ primitive: { topology: "triangle-list" }
8202
+ });
8203
+ if (!pipelineRes.ok) return pipelineRes;
8204
+ cache.value.pipelines.set(format, pipelineRes.value);
8205
+ return pipelineRes;
8206
+ }
8207
+ async function ensureDeviceCache(device, asyncCreateShaderModule) {
8208
+ const existing = deviceCache.get(device);
8209
+ if (existing !== void 0) return ok$1(existing);
8210
+ const moduleRes = await asyncCreateShaderModule(device, {
8211
+ code: MIPMAP_WGSL,
8212
+ label: "mipmap-wgsl"
8213
+ });
8214
+ if (!moduleRes.ok) return moduleRes;
8215
+ const samplerRes = device.createSampler({
8216
+ magFilter: "linear",
8217
+ minFilter: "linear",
8218
+ mipmapFilter: "linear"
8219
+ });
8220
+ if (!samplerRes.ok) return samplerRes;
8221
+ const FRAGMENT_STAGE = 2;
8222
+ const layoutRes = device.createBindGroupLayout({
8223
+ label: "mipmap-bgl",
8224
+ entries: [
8225
+ { binding: 0, visibility: FRAGMENT_STAGE, sampler: { type: "filtering" } },
8226
+ {
8227
+ binding: 1,
8228
+ visibility: FRAGMENT_STAGE,
8229
+ texture: { sampleType: "float", viewDimension: "2d" }
8230
+ }
8231
+ ]
8232
+ });
8233
+ if (!layoutRes.ok) return layoutRes;
8234
+ const cache = {
8235
+ sampler: samplerRes.value,
8236
+ module: moduleRes.value,
8237
+ layout: layoutRes.value,
8238
+ pipelines: /* @__PURE__ */ new Map()
8239
+ };
8240
+ deviceCache.set(device, cache);
8241
+ return ok$1(cache);
8242
+ }
8243
+ function recordMipmapBlit(device, texture, levels, pipeline, cache) {
8244
+ const encoderRes = device.createCommandEncoder({ label: "mipmap-encoder" });
8245
+ if (!encoderRes.ok) return encoderRes;
8246
+ const encoder = encoderRes.value;
8247
+ for (let i = 1; i < levels; i++) {
8248
+ const srcViewRes = device.createTextureView(texture, {
8249
+ baseMipLevel: i - 1,
8250
+ mipLevelCount: 1,
8251
+ dimension: "2d"
8252
+ });
8253
+ if (!srcViewRes.ok) return srcViewRes;
8254
+ const dstViewRes = device.createTextureView(texture, {
8255
+ baseMipLevel: i,
8256
+ mipLevelCount: 1,
8257
+ dimension: "2d"
8258
+ });
8259
+ if (!dstViewRes.ok) return dstViewRes;
8260
+ const bindGroupRes = device.createBindGroup({
8261
+ label: `mipmap-bg-${i}`,
8262
+ layout: cache.layout,
8263
+ entries: [
8264
+ { binding: 0, resource: { kind: "sampler", value: cache.sampler } },
8265
+ { binding: 1, resource: { kind: "textureView", value: srcViewRes.value } }
8266
+ ]
8267
+ });
8268
+ if (!bindGroupRes.ok) return bindGroupRes;
8269
+ const pass = encoder.beginRenderPass({
8270
+ label: `mipmap-pass-${i}`,
8271
+ colorAttachments: [
8272
+ {
8273
+ view: dstViewRes.value,
8274
+ clearValue: { r: 0, g: 0, b: 0, a: 1 },
8275
+ loadOp: "clear",
8276
+ storeOp: "store"
8277
+ }
8278
+ ]
8279
+ });
8280
+ pass.setPipeline(pipeline);
8281
+ pass.setBindGroup(0, bindGroupRes.value);
8282
+ pass.draw(3, 1, 0, 0);
8283
+ pass.end();
8284
+ }
8285
+ const finishRes = encoder.finish();
8286
+ if (!finishRes.ok) return finishRes;
8287
+ return device.queue.submit([finishRes.value]);
8288
+ }
8289
+ function blitMipmapsSync(device, texture, descriptor) {
8290
+ const levels = descriptor.levels ?? numMipLevels(descriptor);
8291
+ if (levels <= 1) return ok$1(void 0);
8292
+ const cache = deviceCache.get(device);
8293
+ if (cache === void 0) {
8294
+ return err(
8295
+ new RhiError({
8296
+ code: "rhi-not-available",
8297
+ expected: "mipmap pipeline cache prewarmed for this device before blitMipmapsSync",
8298
+ hint: "call prewarmMipmapPipeline(device, formats) at renderer.ready before the synchronous record-stage mipmap blit"
8299
+ })
8300
+ );
8301
+ }
8302
+ const pipeline = cache.pipelines.get(descriptor.format);
8303
+ if (pipeline === void 0) {
8304
+ return err(
8305
+ new RhiError({
8306
+ code: "rhi-not-available",
8307
+ expected: `mipmap pipeline for format ${descriptor.format} prewarmed`,
8308
+ hint: `format ${descriptor.format} was not prewarmed; add it to the prewarmMipmapPipeline format list at renderer.ready`
8309
+ })
8310
+ );
8311
+ }
8312
+ return recordMipmapBlit(device, texture, levels, pipeline, cache);
8313
+ }
8314
+ function encodeMipmapLevel(device, pass, sourceView, format) {
8315
+ const cache = deviceCache.get(device);
8316
+ if (cache === void 0) {
8317
+ return err(
8318
+ new RhiError({
8319
+ code: "rhi-not-available",
8320
+ expected: "mipmap pipeline cache prewarmed for the graph device before encoding",
8321
+ hint: "call prewarmMipmapPipeline(device, formats) at renderer.ready"
8322
+ })
8323
+ );
8324
+ }
8325
+ const pipeline = cache.pipelines.get(format);
8326
+ if (pipeline === void 0) {
8327
+ return err(
8328
+ new RhiError({
8329
+ code: "rhi-not-available",
8330
+ expected: `mipmap pipeline for format ${format} prewarmed`,
8331
+ hint: `format ${format} was not prewarmed; add it to the renderer prewarm list`
8332
+ })
8333
+ );
8334
+ }
8335
+ const bindGroup = device.createBindGroup({
8336
+ label: "mipmap-graph-bind-group",
8337
+ layout: cache.layout,
8338
+ entries: [
8339
+ { binding: 0, resource: { kind: "sampler", value: cache.sampler } },
8340
+ { binding: 1, resource: { kind: "textureView", value: sourceView } }
8341
+ ]
8342
+ });
8343
+ if (!bindGroup.ok) return bindGroup;
8344
+ pass.setPipeline(pipeline);
8345
+ pass.setBindGroup(0, bindGroup.value);
8346
+ pass.draw(3, 1, 0, 0);
8347
+ return ok$1(void 0);
8348
+ }
8321
8349
 
8322
8350
  // src/plugin.ts
8323
8351
  function assetsPlugin(assets) {