playcanvas / playcanvas/engine

texture.lock({ level: 0 }): only upload a single mip level if locked explicitly

Open
#6,004 5 comments 0 reactions 2 assignees View on GitHub

@mvaligursky is already working on this.

Since Feb 26, 2024.

area: graphics enhancement
Dominant language
JavaScript
Stars
16.8k
Forks
2k
Avg merge
4h 32m
Merged PRs (30d)
222

Description

I also have some questions about future directions texture.lock() API, which I would be happy to help implement.

I'm asking these in the context of #6003 - I kept that PR deliberately small, but can open a followup PR depending on your thoughts.

Apologies in advance for length!

Questions for PlayCanvas team

Question 1

As mentioned in #5754, it would be good to be able to:

  1. Lock an individual slice of a 2D Texture Array
  2. Lock a specific mip level, and:
  3. Only upload the explicitly locked mip level instead of all of them

I'm excited to contribute an implementation for 1), but first I would like to clarify some issues around 2) and 3).

On 3): it looks to me like we always re-upload all mip levels regardless of whether we locked a specific one.

Q1: Is this correct, or have I missed something important in webgl/webgpu-texture.js?


Question 2

We could check texture._lockedLevel and use it to only upload the specified level when a level option was passed to texture.lock().

For example in webgl-texture.js:

        // Upload all existing mip levels. Initialize 0 mip anyway.
        while (texture._levels[mipLevel] || mipLevel === 0) {

+             // If we have locked a single mip level, only upload that mip
+            if (texture.lockedLevel !== -1 && mipLevel !== texture.lockedLevel) {
+                mipLevel++;
+                continue;
+            }

Q2: Does this seem like a good approach? Or should we be checking / updating texture._levelsUpdated instead?


Question 3
  • Currently, texture.lockedLevel defaults to 0 when no level option is passed.
  • This is because _lockedLevel !== -1 is overloaded to indicate whether a texture is locked.
  • With #6003, we can use _lockedMode for this instead, and leave _lockedLevel at -1 if no explicit level was specified.

The default API would have the same behavior as now:

const data = texture.lock(); // Returns mip level 0 data

/** Internally, _lockedLevel remains -1, because user didn't set it explicitly */

texture.unlock(); // Uploads all mipmaps

But when the user specifies mip level 0 explicitly:

const data = texture.lock({ level: 0 }); // Returns mip level 0 data

/** Internally, _lockedLevel is now 0, because user set it explicitly */

texture.unlock(); // Uploads only mip level 0

So for most cases of lock(), the behavior is the same, but it could break expectations in code that is passing { level: 0 } and expecting all mips to update.

Additionally, anyone relying on the private texture._lockedLevel would not longer see it set to 0 when a texture is locked in the default way. But they could switch to the public texture.lockMode instead to check the locked state.

Q3: Is this level of API/behavior change acceptable?

Thank you, and let me know if there is a better venue for implementation questions like this!

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.