Skip to content

Commit ccf2af7

Browse files
committed
Texture array updates WIP
1 parent cae51cb commit ccf2af7

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
@@ -70,9 +70,6 @@ class Texture {
7070
/** @protected */
7171
_invalid = false;
7272

73-
/** @protected */
74-
_lockedLevel = -1;
75-
7673
/** @protected */
7774
_lockedMode = TEXTURELOCK_NONE;
7875

@@ -286,7 +283,7 @@ class Texture {
286283
if (this._levels) {
287284
this.upload(options.immediate ?? false);
288285
} else {
289-
this._levels = this.cubemap ? [[null, null, null, null, null, null]] : [null];
286+
this._levels = (this.cubemap || this.array) ? [Array(this._slices).fill(null)] : [null];
290287
}
291288

292289
// track the texture
@@ -825,7 +822,7 @@ class Texture {
825822

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

830827
this._needsUpload = true;
831828
this._needsMipmapsUpload = this._mipmaps;
@@ -842,6 +839,8 @@ class Texture {
842839
* to 0.
843840
* @param {number} [options.face] - If the texture is a cubemap, this is the index of the face
844841
* to lock.
842+
* @param {number} [options.slice] - If the texture is a texture array, this is the index of the
843+
* slice to lock.
845844
* @param {number} [options.mode] - The lock mode. Can be:
846845
* - {@link TEXTURELOCK_READ}
847846
* - {@link TEXTURELOCK_WRITE}
@@ -853,6 +852,7 @@ class Texture {
853852
// Initialize options to some sensible defaults
854853
options.level ??= 0;
855854
options.face ??= 0;
855+
options.slice ??= 0;
856856
options.mode ??= TEXTURELOCK_WRITE;
857857

858858
Debug.assert(
@@ -867,19 +867,38 @@ class Texture {
867867
this
868868
);
869869

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

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

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

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

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

907-
for (let i = 0; i < 6; i++) {
925+
for (let i = 0; i < this._slices; i++) {
908926
const face = source[i];
909927
// cubemap becomes invalid if any condition is not satisfied
910928
if (!face || // face is missing
@@ -922,10 +940,9 @@ class Texture {
922940

923941
if (!invalid) {
924942
// mark levels as updated
925-
for (let i = 0; i < 6; i++) {
926-
if (this._levels[mipLevel][i] !== source[i]) {
927-
this._levelsUpdated[mipLevel][i] = true;
928-
}
943+
for (let i = 0; i < this._slices; i++) {
944+
if (this._levels[0][i] !== source[i])
945+
this._levelsUpdated[0][i] = true;
929946
}
930947
}
931948
} else {
@@ -936,9 +953,8 @@ class Texture {
936953

937954
if (!invalid) {
938955
// mark level as updated
939-
if (source !== this._levels[mipLevel]) {
940-
this._levelsUpdated[mipLevel] = true;
941-
}
956+
if (source !== this._levels[0])
957+
this._levelsUpdated[0] = true;
942958

943959
width = source.width;
944960
height = source.height;
@@ -953,23 +969,22 @@ class Texture {
953969
this._height = 4;
954970

955971
// remove levels
956-
if (this.cubemap) {
957-
for (let i = 0; i < 6; i++) {
958-
this._levels[mipLevel][i] = null;
959-
this._levelsUpdated[mipLevel][i] = true;
972+
if (this.cubemap || this.array) {
973+
for (let i = 0; i < this._slices; i++) {
974+
this._levels[0][i] = null;
975+
this._levelsUpdated[0][i] = true;
960976
}
961977
} else {
962-
this._levels[mipLevel] = null;
963-
this._levelsUpdated[mipLevel] = true;
978+
this._levels[0] = null;
979+
this._levelsUpdated[0] = true;
964980
}
965981
} else {
966982
// valid texture
967-
if (mipLevel === 0) {
968-
this._width = width;
969-
this._height = height;
970-
}
971983

972-
this._levels[mipLevel] = source;
984+
this._width = width;
985+
this._height = height;
986+
987+
this._levels[0] = source;
973988
}
974989

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

9981010
/**
@@ -1008,7 +1020,6 @@ class Texture {
10081020
if (this._lockedMode === TEXTURELOCK_WRITE) {
10091021
this.upload(immediate);
10101022
}
1011-
this._lockedLevel = -1;
10121023
this._lockedMode = TEXTURELOCK_NONE;
10131024
}
10141025

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

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

463463
const requiredMipLevels = texture.requiredMipLevels;
464464

465-
if (texture.array) {
465+
if (texture.array && !this._glCreated) {
466466
// for texture arrays we reserve the space in advance
467467
gl.texStorage3D(gl.TEXTURE_2D_ARRAY,
468468
requiredMipLevels,
@@ -500,11 +500,11 @@ class WebglTexture {
500500
if (device._isBrowserInterface(mipObject[0])) {
501501
// Upload the image, canvas or video
502502
for (face = 0; face < texture.slices; face++) {
503-
if (!texture._levelsUpdated[0][face])
503+
let src = mipObject[face];
504+
if (!texture._levelsUpdated[0][face] || !src)
504505
continue;
505506
}
506507

507-
let src = mipObject[face];
508508
// Downsize images that are too large to be used as cube maps
509509
if (device._isImageBrowserInterface(src)) {
510510
if (src.width > device.maxCubeMapSize || src.height > device.maxCubeMapSize) {
@@ -543,11 +543,11 @@ class WebglTexture {
543543
// Upload the byte array
544544
resMult = 1 / Math.pow(2, mipLevel);
545545
for (face = 0; face < texture.slices; face++) {
546-
if (!texture._levelsUpdated[0][face])
546+
const texData = mipObject[face];
547+
if (!texture._levelsUpdated[0][face] || !texData)
547548
continue;
548549
}
549550

550-
const texData = mipObject[face];
551551
if (texture._compressed) {
552552
if (this._glCreated && texData) {
553553
gl.compressedTexSubImage2D(
@@ -627,38 +627,40 @@ class WebglTexture {
627627
mipObject);
628628
}
629629
} else if (texture.array && typeof mipObject === "object") {
630-
if (texture._slices === mipObject.length) {
631-
if (texture._compressed) {
632-
for (let index = 0; index < texture._slices; index++) {
633-
gl.compressedTexSubImage3D(
634-
gl.TEXTURE_2D_ARRAY,
635-
mipLevel,
636-
0,
637-
0,
638-
index,
639-
Math.max(Math.floor(texture._width * resMult), 1),
640-
Math.max(Math.floor(texture._height * resMult), 1),
641-
1,
642-
this._glFormat,
643-
mipObject[index]
644-
);
645-
}
646-
} else {
647-
for (let index = 0; index < texture.slices; index++) {
648-
gl.texSubImage3D(
649-
gl.TEXTURE_2D_ARRAY,
650-
mipLevel,
651-
0,
652-
0,
653-
index,
654-
Math.max(Math.floor(texture._width * resMult), 1),
655-
Math.max(Math.floor(texture._height * resMult), 1),
656-
1,
657-
this._glFormat,
658-
this._glPixelType,
659-
mipObject[index]
660-
);
661-
}
630+
if (texture._compressed) {
631+
for (let index = 0; index < texture._slices; index++) {
632+
if (!texture._levelsUpdated[0][index] || !mipObject[index])
633+
continue;
634+
gl.compressedTexSubImage3D(
635+
gl.TEXTURE_2D_ARRAY,
636+
mipLevel,
637+
0,
638+
0,
639+
index,
640+
Math.max(Math.floor(texture._width * resMult), 1),
641+
Math.max(Math.floor(texture._height * resMult), 1),
642+
1,
643+
this._glFormat,
644+
mipObject[index]
645+
);
646+
}
647+
} else {
648+
for (let index = 0; index < texture.slices; index++) {
649+
if (!texture._levelsUpdated[0][index] || !mipObject[index])
650+
continue;
651+
gl.texSubImage3D(
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+
this._glPixelType,
662+
mipObject[index]
663+
);
662664
}
663665
}
664666
} else {
@@ -773,7 +775,7 @@ class WebglTexture {
773775
}
774776

775777
if (texture._needsUpload) {
776-
if (texture.cubemap) {
778+
if (texture.cubemap || texture.array) {
777779
for (let i = 0; i < texture.slices; i++)
778780
texture._levelsUpdated[0][i] = false;
779781
}

0 commit comments

Comments
 (0)