Skip to content

Commit 507621a

Browse files
committed
Texture array updates WIP
1 parent 87c5eda commit 507621a

File tree

5 files changed

+96
-81
lines changed

5 files changed

+96
-81
lines changed

src/framework/handlers/texture.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,18 @@ const _completePartialMipmapChain = function (texture) {
9999
for (let level = texture._levels.length; level < requiredMipLevels; ++level) {
100100
const width = Math.max(1, texture._width >> (level - 1));
101101
const height = Math.max(1, texture._height >> (level - 1));
102-
if (texture.cubemap) {
102+
if (texture.cubemap || texture.array) {
103103
const mips = [];
104-
for (let face = 0; face < 6; ++face) {
105-
mips.push(downsample(width, height, texture._levels[level - 1][face]));
104+
for (let slice = 0; slice < texture.slices; ++slice) {
105+
mips.push(downsample(width, height, texture._levels[level - 1][slice]));
106106
}
107107
texture._levels.push(mips);
108108
} else {
109109
texture._levels.push(downsample(width, height, texture._levels[level - 1]));
110110
}
111111
}
112112

113-
texture._levelsUpdated = texture.cubemap ? [[true, true, true, true, true, true]] : [true];
113+
texture._levelsUpdated = (texture.cubemap || texture.array) ? [Array(texture.slices).fill(true)] : [true];
114114
};
115115

116116
/**

src/platform/graphics/null/null-texture.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ class NullTexture {
1010

1111
loseContext() {
1212
}
13+
14+
uploadImmediate(device, texture, immediate) {
15+
}
1316
}
1417

1518
export { NullTexture };

src/platform/graphics/texture-utils.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
import { Debug } from '../../core/debug.js';
22
import {
33
pixelFormatInfo,
4-
PIXELFORMAT_PVRTC_2BPP_RGB_1, PIXELFORMAT_PVRTC_2BPP_RGBA_1,
5-
TEXTUREDIMENSION_3D
4+
PIXELFORMAT_PVRTC_2BPP_RGB_1, PIXELFORMAT_PVRTC_2BPP_RGBA_1
65
} from './constants.js';
76

87
/**
@@ -69,11 +68,11 @@ class TextureUtils {
6968
/**
7069
* Calculate the GPU memory required for a texture.
7170
*
72-
* @param {string} dimension - Texture's dimension
7371
* @param {number} width - Texture's width.
7472
* @param {number} height - Texture's height.
7573
* @param {number} slices - Texture's slices.
7674
* @param {number} format - Texture's pixel format PIXELFORMAT_***.
75+
* @param {boolean} isVolume - True if the texture is a volume texture, false otherwise.
7776
* @param {boolean} mipmaps - True if the texture includes mipmaps, false otherwise.
7877
* @returns {number} The number of bytes of GPU memory required for the texture.
7978
*/

src/platform/graphics/texture.js

Lines changed: 47 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -71,9 +71,6 @@ class Texture {
7171
/** @protected */
7272
_invalid = false;
7373

74-
/** @protected */
75-
_lockedLevel = -1;
76-
7774
/** @protected */
7875
_lockedMode = TEXTURELOCK_NONE;
7976

@@ -287,7 +284,7 @@ class Texture {
287284
if (this._levels) {
288285
this.upload(options.immediate ?? false);
289286
} else {
290-
this._levels = this.cubemap ? [[null, null, null, null, null, null]] : [null];
287+
this._levels = (this.cubemap || this.array) ? [Array(this._slices).fill(null)] : [null];
291288
}
292289

293290
// track the texture
@@ -826,7 +823,7 @@ class Texture {
826823

827824
// Force a full resubmission of the texture to the GPU (used on a context restore event)
828825
dirtyAll() {
829-
this._levelsUpdated = this.cubemap ? [[true, true, true, true, true, true]] : [true];
826+
this._levelsUpdated = (this.cubemap || this.array) ? [Array(this._slices).fill(true)] : [true];
830827

831828
this._needsUpload = true;
832829
this._needsMipmapsUpload = this._mipmaps;
@@ -843,6 +840,8 @@ class Texture {
843840
* to 0.
844841
* @param {number} [options.face] - If the texture is a cubemap, this is the index of the face
845842
* to lock.
843+
* @param {number} [options.slice] - If the texture is a texture array, this is the index of the
844+
* slice to lock.
846845
* @param {number} [options.mode] - The lock mode. Can be:
847846
* - {@link TEXTURELOCK_READ}
848847
* - {@link TEXTURELOCK_WRITE}
@@ -854,6 +853,7 @@ class Texture {
854853
// Initialize options to some sensible defaults
855854
options.level ??= 0;
856855
options.face ??= 0;
856+
options.slice ??= 0;
857857
options.mode ??= TEXTURELOCK_WRITE;
858858

859859
Debug.assert(
@@ -868,19 +868,38 @@ class Texture {
868868
this
869869
);
870870

871+
Debug.assert(
872+
options.level >= 0 && options.level < this._levels.length,
873+
'Invalid mip level',
874+
this
875+
);
876+
877+
Debug.assert(
878+
((this.cubemap || this.array) && options.mode === TEXTURELOCK_WRITE) ? options.level === 0 : true,
879+
'Only mip level 0 can be locked for writing for cubemaps and texture arrays',
880+
this
881+
);
882+
871883
this._lockedMode = options.mode;
872-
this._lockedLevel = options.level;
873884

874-
const levels = this.cubemap ? this._levels[options.face] : this._levels;
885+
const levels = this.cubemap ? this._levels[options.face] : this.array ? this._levels[options.slice] : this._levels;
875886
if (levels[options.level] === null) {
876887
// allocate storage for this mip level
877888
const width = Math.max(1, this._width >> options.level);
878889
const height = Math.max(1, this._height >> options.level);
879-
const depth = Math.max(1, (this._dimension === TEXTUREDIMENSION_3D ? this._slices : 1) >> options.level);
890+
const depth = Math.max(1, this.depth >> options.level);
880891
const data = new ArrayBuffer(TextureUtils.calcLevelGpuSize(width, height, depth, this._format));
881892
levels[options.level] = new (getPixelFormatArrayType(this._format))(data);
882893
}
883894

895+
if (this._lockedMode === TEXTURELOCK_WRITE) {
896+
if (this.cubemap || this.array) {
897+
this._levelsUpdated[0][options.face ?? options.slice] = true;
898+
} else {
899+
this._levelsUpdated[0] = true;
900+
}
901+
}
902+
884903
return levels[options.level];
885904
}
886905

@@ -890,22 +909,21 @@ class Texture {
890909
*
891910
* @param {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement|HTMLCanvasElement[]|HTMLImageElement[]|HTMLVideoElement[]} source - A
892911
* canvas, image or video element, or an array of 6 canvas, image or video elements.
893-
* @param {number} [mipLevel] - A non-negative integer specifying the image level of detail.
894912
* Defaults to 0, which represents the base image source. A level value of N, that is greater
895913
* than 0, represents the image source for the Nth mipmap reduction level.
896914
* @param {boolean} [immediate] - When set to true it forces an immediate upload upon assignment. Defaults to false.
897915
*/
898-
setSource(source, mipLevel = 0, immediate = false) {
916+
setSource(source, immediate = false) {
899917
let invalid = false;
900918
let width, height;
901919

902-
if (this.cubemap) {
920+
if (this.cubemap || this.array) {
903921
if (source[0]) {
904922
// rely on first face sizes
905923
width = source[0].width || 0;
906924
height = source[0].height || 0;
907925

908-
for (let i = 0; i < 6; i++) {
926+
for (let i = 0; i < this._slices; i++) {
909927
const face = source[i];
910928
// cubemap becomes invalid if any condition is not satisfied
911929
if (!face || // face is missing
@@ -923,10 +941,9 @@ class Texture {
923941

924942
if (!invalid) {
925943
// mark levels as updated
926-
for (let i = 0; i < 6; i++) {
927-
if (this._levels[mipLevel][i] !== source[i]) {
928-
this._levelsUpdated[mipLevel][i] = true;
929-
}
944+
for (let i = 0; i < this._slices; i++) {
945+
if (this._levels[0][i] !== source[i])
946+
this._levelsUpdated[0][i] = true;
930947
}
931948
}
932949
} else {
@@ -937,9 +954,8 @@ class Texture {
937954

938955
if (!invalid) {
939956
// mark level as updated
940-
if (source !== this._levels[mipLevel]) {
941-
this._levelsUpdated[mipLevel] = true;
942-
}
957+
if (source !== this._levels[0])
958+
this._levelsUpdated[0] = true;
943959

944960
width = source.width;
945961
height = source.height;
@@ -954,23 +970,22 @@ class Texture {
954970
this._height = 4;
955971

956972
// remove levels
957-
if (this.cubemap) {
958-
for (let i = 0; i < 6; i++) {
959-
this._levels[mipLevel][i] = null;
960-
this._levelsUpdated[mipLevel][i] = true;
973+
if (this.cubemap || this.array) {
974+
for (let i = 0; i < this._slices; i++) {
975+
this._levels[0][i] = null;
976+
this._levelsUpdated[0][i] = true;
961977
}
962978
} else {
963-
this._levels[mipLevel] = null;
964-
this._levelsUpdated[mipLevel] = true;
979+
this._levels[0] = null;
980+
this._levelsUpdated[0] = true;
965981
}
966982
} else {
967983
// valid texture
968-
if (mipLevel === 0) {
969-
this._width = width;
970-
this._height = height;
971-
}
972984

973-
this._levels[mipLevel] = source;
985+
this._width = width;
986+
this._height = height;
987+
988+
this._levels[0] = source;
974989
}
975990

976991
// valid or changed state of validity
@@ -986,14 +1001,11 @@ class Texture {
9861001
* Get the pixel data of the texture. If this is a cubemap then an array of 6 images will be
9871002
* returned otherwise a single image.
9881003
*
989-
* @param {number} [mipLevel] - A non-negative integer specifying the image level of detail.
990-
* Defaults to 0, which represents the base image source. A level value of N, that is greater
991-
* than 0, represents the image source for the Nth mipmap reduction level.
9921004
* @returns {HTMLImageElement} The source image of this texture. Can be null if source not
9931005
* assigned for specific image level.
9941006
*/
995-
getSource(mipLevel = 0) {
996-
return this._levels[mipLevel];
1007+
getSource() {
1008+
return this._levels[0];
9971009
}
9981010

9991011
/**
@@ -1009,7 +1021,6 @@ class Texture {
10091021
if (this._lockedMode === TEXTURELOCK_WRITE) {
10101022
this.upload(immediate);
10111023
}
1012-
this._lockedLevel = -1;
10131024
this._lockedMode = TEXTURELOCK_NONE;
10141025
}
10151026

src/platform/graphics/webgl/webgl-texture.js

Lines changed: 40 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -479,7 +479,7 @@ class WebglTexture {
479479

480480
const requiredMipLevels = texture.requiredMipLevels;
481481

482-
if (texture.array) {
482+
if (texture.array && !this._glCreated) {
483483
// for texture arrays we reserve the space in advance
484484
gl.texStorage3D(gl.TEXTURE_2D_ARRAY,
485485
requiredMipLevels,
@@ -517,11 +517,11 @@ class WebglTexture {
517517
if (device._isBrowserInterface(mipObject[0])) {
518518
// Upload the image, canvas or video
519519
for (face = 0; face < texture.slices; face++) {
520-
if (!texture._levelsUpdated[0][face])
520+
let src = mipObject[face];
521+
if (!texture._levelsUpdated[0][face] || !src)
521522
continue;
522523
}
523524

524-
let src = mipObject[face];
525525
// Downsize images that are too large to be used as cube maps
526526
if (device._isImageBrowserInterface(src)) {
527527
if (src.width > device.maxCubeMapSize || src.height > device.maxCubeMapSize) {
@@ -560,11 +560,11 @@ class WebglTexture {
560560
// Upload the byte array
561561
resMult = 1 / Math.pow(2, mipLevel);
562562
for (face = 0; face < texture.slices; face++) {
563-
if (!texture._levelsUpdated[0][face])
563+
const texData = mipObject[face];
564+
if (!texture._levelsUpdated[0][face] || !texData)
564565
continue;
565566
}
566567

567-
const texData = mipObject[face];
568568
if (texture._compressed) {
569569
if (this._glCreated && texData) {
570570
gl.compressedTexSubImage2D(
@@ -644,38 +644,40 @@ class WebglTexture {
644644
mipObject);
645645
}
646646
} else if (texture.array && typeof mipObject === "object") {
647-
if (texture._slices === mipObject.length) {
648-
if (texture._compressed) {
649-
for (let index = 0; index < texture._slices; index++) {
650-
gl.compressedTexSubImage3D(
651-
gl.TEXTURE_2D_ARRAY,
652-
mipLevel,
653-
0,
654-
0,
655-
index,
656-
Math.max(Math.floor(texture._width * resMult), 1),
657-
Math.max(Math.floor(texture._height * resMult), 1),
658-
1,
659-
this._glFormat,
660-
mipObject[index]
661-
);
662-
}
663-
} else {
664-
for (let index = 0; index < texture.slices; index++) {
665-
gl.texSubImage3D(
666-
gl.TEXTURE_2D_ARRAY,
667-
mipLevel,
668-
0,
669-
0,
670-
index,
671-
Math.max(Math.floor(texture._width * resMult), 1),
672-
Math.max(Math.floor(texture._height * resMult), 1),
673-
1,
674-
this._glFormat,
675-
this._glPixelType,
676-
mipObject[index]
677-
);
678-
}
647+
if (texture._compressed) {
648+
for (let index = 0; index < texture._slices; index++) {
649+
if (!texture._levelsUpdated[0][index] || !mipObject[index])
650+
continue;
651+
gl.compressedTexSubImage3D(
652+
gl.TEXTURE_2D_ARRAY,
653+
mipLevel,
654+
0,
655+
0,
656+
index,
657+
Math.max(Math.floor(texture._width * resMult), 1),
658+
Math.max(Math.floor(texture._height * resMult), 1),
659+
1,
660+
this._glFormat,
661+
mipObject[index]
662+
);
663+
}
664+
} else {
665+
for (let index = 0; index < texture.slices; index++) {
666+
if (!texture._levelsUpdated[0][index] || !mipObject[index])
667+
continue;
668+
gl.texSubImage3D(
669+
gl.TEXTURE_2D_ARRAY,
670+
mipLevel,
671+
0,
672+
0,
673+
index,
674+
Math.max(Math.floor(texture._width * resMult), 1),
675+
Math.max(Math.floor(texture._height * resMult), 1),
676+
1,
677+
this._glFormat,
678+
this._glPixelType,
679+
mipObject[index]
680+
);
679681
}
680682
}
681683
} else {
@@ -790,7 +792,7 @@ class WebglTexture {
790792
}
791793

792794
if (texture._needsUpload) {
793-
if (texture.cubemap) {
795+
if (texture.cubemap || texture.array) {
794796
for (let i = 0; i < texture.slices; i++)
795797
texture._levelsUpdated[0][i] = false;
796798
}

0 commit comments

Comments
 (0)