Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Exceeding some character count results in a memory related crash #22

Closed
meshantz opened this issue Oct 3, 2022 · 6 comments
Closed

Comments

@meshantz
Copy link

meshantz commented Oct 3, 2022

This seems to be both font and character specific.

Experimenting with the NotoSansMono-Thin and updating the example (bare/index.js) text value to 241 * characters results in the following traceback:

bf.0.1.0.babylon.font.wasm:0x237 Uncaught (in promise) RuntimeError: memory access out of bounds
    at bf.0.1.0.babylon.font.wasm:0x237
    at bf.0.1.0.babylon.font.wasm:0x268
    at bf.0.1.0.babylon.font.wasm:0xed
    at bf.0.1.0.babylon.font.wasm:0x6f5
    at bf.0.1.0.babylon.font.wasm:0xb37
    at bf.0.1.0.babylon.font.wasm:0x250d
    at bf.0.1.0.babylon.font.wasm:0x207c
    at curr.<computed> [as compile] (loader.js:379:18)
    at Compiler.compileEncoded (babylon.font.js:104:45)
    at Compiler.compile (babylon.font.js:146:21)

Using 241 l characters instead, does not result in this crash. Other fonts can result in much lower limits before this happens.

Is this some kind of natural limitation (if so, is there a calculation that can prevent it) or a bug in memory management somewhere?

@ycw
Copy link
Owner

ycw commented Oct 4, 2022

increase the budget in asconfig.json:options.memoryBase ( say, 655360 = 640kB )

"memoryBase": 65536

then rebuild (npm run asbuild)

🥂

@meshantz
Copy link
Author

meshantz commented Oct 4, 2022

Okay, that makes sense. Thanks for the quick reply!

Is there a way to calculate what values will be a problem for a given font, or is the only way to wrap every call to builder.create with error handling to catch this error?

@meshantz
Copy link
Author

meshantz commented Oct 4, 2022

Hmm. I can't seem to recover from this error at all. I've even tried reloading the entire complier mechanism (which would be pretty heavy to do every time this error occurs) to no avail.

All subsequent calls to builder.create fail with the same error.

Here is (roughly) the reloading code I attempted:

  let compiler = await Compiler.Build(`${constants.BABYLON_FONT_WASM}`)

  let fonts: { [key in FontName]: Font } = {
    calibri: await Font.Install(fontPaths.calibri, compiler, opentype),
    consola: await Font.Install(fontPaths.consola, compiler, opentype),
    'consola-bold': await Font.Install(
      fontPaths['consola-bold'],
      compiler,
      opentype,
    ),
  }

  let builder = new TextMeshBuilder(BABYLON, earcut)

      try {
        mesh = builder.create(
          // eslint-disable-next-line @typescript-eslint/ban-ts-comment
          // @ts-ignore
          {
            font: fonts.calibri,
            text: failingText,
            size: 12,
          },
          scene,
        )
      } catch (error) {
        Compiler.Build(`${constants.BABYLON_FONT_WASM}`).then(
          async (newCompiler) => {
            compiler = newCompiler
            fonts = {
              calibri: await Font.Install(
                fontPaths.calibri,
                compiler,
                opentype,
              ),
              consola: await Font.Install(
                fontPaths.consola,
                compiler,
                opentype,
              ),
              'consola-bold': await Font.Install(
                fontPaths['consola-bold'],
                compiler,
                opentype,
              ),
            }
            builder = new TextMeshBuilder(BABYLON, earcut)
            builder.create(
              // eslint-disable-next-line @typescript-eslint/ban-ts-comment
              // @ts-ignore
              {
                font: fonts.calibri,
                text: 'small',
                size: 12,
              },
              makeOpts.scene,
            )
          },
        )
      }

@ycw
Copy link
Owner

ycw commented Oct 4, 2022

a workaround off the top of my head

bytes required for (font, text) can be computed by:

function bytes_required(font, text) {
  let b = 0
  const cmds = font.raw.getPath(text, 0, 0, 100).commands
  for (const cmd of cmds) {
    b += 1
    switch (cmd.type) {
      case 'M': 
      case 'L': b += 16; break
      case 'Q': b += 48; break
      case 'C': b += 64; break 
    }
  }
  return b
}

then, validate before each builder.create:

if ( bytes_required(font, 'hello') <= 65536 ) {
  // builder.create( .. )
} 

where 65536 := asconfig.json:options.memoryBase

🥂

@meshantz
Copy link
Author

meshantz commented Oct 4, 2022

Awesome. Thanks again! I'll give this a shot.

meshantz added a commit to meshantz/Babylon.Font that referenced this issue Oct 4, 2022
@ycw
Copy link
Owner

ycw commented Oct 6, 2022

solved in v4.

@ycw ycw closed this as completed Oct 6, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants